Makine öğrenmesi dünyasında herkesin algoritmalara takıntılı olduğu bir dönemdeyiz — ama açıkçası, çoğu zaman modelin başarısını belirleyen şey algoritma değil, veriye nasıl şekil verdiğiniz. İşte tam burada özellik mühendisliği (feature engineering) sahneye çıkıyor. Ham veriyi, modelin gerçekten anlayabileceği ve öğrenebileceği sinyallere dönüştürme sanatı. Ve evet, biraz da bilimi.
Doğru özellikler oluşturabilirseniz, basit bir lojistik regresyon bile karmaşık bir sinir ağını geçebilir. Bunu ilk kez gördüğümde inanmamıştım, ama defalarca doğrulandı.
Bu rehberde Pandas 3.0 ve scikit-learn 1.8 kullanarak özellik mühendisliğinin temellerinden ileri düzey tekniklere kadar her şeyi ele alacağız. Bol bol çalıştırılabilir kod var — hadi başlayalım.
Özellik Mühendisliği Nedir ve Neden Bu Kadar Önemli?
Özellik mühendisliği, ham veriyi makine öğrenmesi modelleri için en uygun formata dönüştürme sürecidir. Yeni özellikler türetmek, mevcut özellikleri dönüştürmek, gereksiz olanları elemek ve kategorik verileri sayısal formlara kodlamak — hepsi bu şemsiyenin altında.
Peki neden bu kadar kritik?
- Model performansı: Araştırmalar, özellik mühendisliğinin model doğruluğunu %10-50 oranında artırabildiğini gösteriyor. Algoritmayı değiştirmek genellikle bunun yanında solda sıfır kalır.
- Yorumlanabilirlik: İyi tasarlanmış özellikler, modelin kararlarını anlamayı kolaylaştırır.
- Eğitim süresi: Doğru özelliklerle model daha hızlı yakınsar, daha az kaynak tüketir.
- Aşırı öğrenmeyi azaltma: Gürültülü özellikleri eleyerek modelin genelleme kapasitesini artırırsınız.
Çalışma Ortamının Hazırlanması
2026 itibarıyla güncel kütüphane sürümleriyle çalışacağız. Pandas 3.0 özellikle özellik mühendisliği iş akışlarını ciddi şekilde iyileştirdi (bunu ilerleyen bölümlerde somut olarak göreceksiniz).
# Kütüphaneleri yükleyin
pip install pandas==3.0.1 scikit-learn==1.8.0 numpy category_encoders feature-engine
# Gerekli import'lar
import pandas as pd
import numpy as np
from sklearn.preprocessing import (
StandardScaler, MinMaxScaler, LabelEncoder,
OneHotEncoder, OrdinalEncoder, TargetEncoder,
PolynomialFeatures, KBinsDiscretizer
)
from sklearn.compose import ColumnTransformer, make_column_selector
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.feature_selection import SelectKBest, mutual_info_classif
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
import warnings
warnings.filterwarnings("ignore")
Örnek Veri Seti: Çalışan Yıpranma Tahmini
Tüm teknikleri somut bir örnek üzerinde göstermek için sentetik bir çalışan veri seti oluşturacağız. Bu veri setini rehber boyunca kullanacağız — böylece her tekniği aynı bağlamda karşılaştırabilirsiniz.
np.random.seed(42)
n = 1000
df = pd.DataFrame({
"yas": np.random.randint(22, 60, n),
"maas": np.random.normal(12000, 5000, n).clip(4000),
"deneyim_yil": np.random.randint(0, 35, n),
"departman": np.random.choice(
["Mühendislik", "Pazarlama", "Satış", "İK", "Finans"], n
),
"egitim_durumu": np.random.choice(
["Lise", "Ön Lisans", "Lisans", "Yüksek Lisans", "Doktora"], n
),
"ise_giris_tarihi": pd.date_range(
"2010-01-01", periods=n, freq="D"
).to_series().sample(n, replace=True).values,
"sehir": np.random.choice(
["İstanbul", "Ankara", "İzmir", "Bursa", "Antalya",
"Adana", "Konya", "Trabzon", "Kayseri", "Eskişehir"], n
),
"performans_puani": np.random.uniform(1, 5, n).round(1),
"uzaktan_calisma": np.random.choice([True, False], n, p=[0.4, 0.6]),
"ayrildi": np.random.choice([0, 1], n, p=[0.75, 0.25])
})
# Bilinçli olarak bazı eksik değerler ekleyelim
mask = np.random.random(n) < 0.08
df.loc[mask, "maas"] = np.nan
df.loc[np.random.random(n) < 0.05, "egitim_durumu"] = np.nan
print(df.info())
print(df.head())
1. Sayısal Özellik Mühendisliği
Sayısal veriler üzerinde yapacağınız dönüşümler, modelin ham sayıları yorumlama biçimini temelden değiştirebilir. Bu bölüm biraz uzun ama sabırlı olun — temeli sağlam atmak önemli.
1.1 Ölçeklendirme ve Normalleştirme
Farklı ölçeklerdeki sayısal özellikler — mesela maaş (binler) ve yaş (onlar) — mesafe tabanlı algoritmalarda ciddi sorun yaratır. İki temel yaklaşım var:
# StandardScaler: ortalaması 0, standart sapması 1
from sklearn.preprocessing import StandardScaler, MinMaxScaler
scaler_std = StandardScaler()
df["maas_scaled"] = scaler_std.fit_transform(df[["maas"]])
# MinMaxScaler: 0-1 aralığına sıkıştırma
scaler_mm = MinMaxScaler()
df["performans_normalized"] = scaler_mm.fit_transform(
df[["performans_puani"]]
)
print(f"Maaş — Orijinal aralık: {df['maas'].min():.0f}-{df['maas'].max():.0f}")
print(f"Maaş — Scaled aralık: {df['maas_scaled'].min():.2f}-{df['maas_scaled'].max():.2f}")
Hangisini ne zaman kullanmalı? StandardScaler, normal dağılıma yakın verilerde tercih edilir (SVM, lojistik regresyon gibi). MinMaxScaler ise sinir ağları ve belirli bir aralıkta tutmak istediğiniz durumlar için daha uygun. Ağaç tabanlı modeller (XGBoost, Random Forest) ölçeklendirmeye ihtiyaç duymaz — bu güzel bir haber.
1.2 Logaritmik ve Kuvvet Dönüşümleri
Çarpık dağılımlı veriler modelleri yanıltabilir. Logaritmik dönüşüm, sağa çarpık verileri normalleştirmek için en yaygın kullanılan tekniktir.
# Log dönüşümü (sıfır ve negatif değerler için log1p kullanın)
df["maas_log"] = np.log1p(df["maas"])
# Kare kök dönüşümü
df["deneyim_sqrt"] = np.sqrt(df["deneyim_yil"])
# Box-Cox dönüşümü (scikit-learn ile)
from sklearn.preprocessing import PowerTransformer
pt = PowerTransformer(method="yeo-johnson") # Negatif değerleri de destekler
df["maas_boxcox"] = pt.fit_transform(df[["maas"]])
print(f"Orijinal maaş çarpıklığı: {df['maas'].skew():.3f}")
print(f"Log dönüşüm sonrası: {df['maas_log'].skew():.3f}")
print(f"Box-Cox sonrası: {df['maas_boxcox'].skew():.3f}")
1.3 Binning (Ayrıklaştırma)
Sürekli değişkenleri kategorilere ayırmak, özellikle doğrusal olmayan ilişkileri yakalamak için oldukça etkili olabilir. Kişisel deneyimimden söyleyeyim: yaş gibi değişkenlerde binning bazen sürpriz derecede iyi sonuç veriyor.
# Pandas cut ile manuel binning
df["yas_grubu"] = pd.cut(
df["yas"],
bins=[20, 30, 40, 50, 60],
labels=["20-30", "30-40", "40-50", "50-60"]
)
# Scikit-learn KBinsDiscretizer ile otomatik binning
kbd = KBinsDiscretizer(n_bins=5, encode="ordinal", strategy="quantile")
df["maas_bin"] = kbd.fit_transform(df[["maas"]]).astype(int)
print(df["yas_grubu"].value_counts())
print(df["maas_bin"].value_counts())
1.4 Etkileşim Özellikleri (Interaction Features)
İki veya daha fazla özelliği birleştirerek yeni özellikler türetmek, modele ek bilgi sağlayabilir. Mesela maaş tek başına bir şey söyler, deneyim tek başına bir şey söyler — ama maaş/deneyim oranı bambaşka bir hikaye anlatır.
# Manuel etkileşim özellikleri
df["maas_deneyim_orani"] = df["maas"] / (df["deneyim_yil"] + 1)
df["performans_x_deneyim"] = df["performans_puani"] * df["deneyim_yil"]
# Pandas 3.0 pd.col() ile daha temiz sözdizimi
df = df.assign(
verimlilik_skoru=pd.col("performans_puani") / (pd.col("yas") - 20)
)
# PolynomialFeatures ile otomatik etkileşim
poly = PolynomialFeatures(
degree=2,
interaction_only=True, # Yalnızca etkileşimler, kareler yok
include_bias=False
)
sayisal_cols = ["yas", "maas", "deneyim_yil"]
poly_features = poly.fit_transform(df[sayisal_cols].fillna(0))
poly_names = poly.get_feature_names_out(sayisal_cols)
print(f"Orijinal özellik sayısı: {len(sayisal_cols)}")
print(f"Etkileşim sonrası: {poly_features.shape[1]}")
print(f"Yeni özellikler: {poly_names}")
2. Kategorik Özellik Mühendisliği
Kategorik verileri doğru şekilde kodlamak, özellik mühendisliğinin en kritik — ve açıkçası en sık hata yapılan — alanlarından biri. Yanlış kodlama, modele gerçekte var olmayan ilişkiler öğretebilir. Bu bölümü dikkatli okuyun.
2.1 Label Encoding (Etiket Kodlama)
Her kategoriye sıralı bir tam sayı atar. Ama dikkat: bu yöntem kategoriler arasında bir sıralama ilişkisi olduğunu ima eder. Yani sadece gerçekten sıralı kategorilerde veya ağaç tabanlı modellerde kullanın.
from sklearn.preprocessing import LabelEncoder
le = LabelEncoder()
df["departman_label"] = le.fit_transform(df["departman"])
print(dict(zip(le.classes_, le.transform(le.classes_))))
# {'Finans': 0, 'İK': 2, 'Mühendislik': 3, 'Pazarlama': 4, 'Satış': 5}
2.2 One-Hot Encoding (Tek-Sıcak Kodlama)
Her kategori için ayrı bir ikili (0/1) sütun oluşturur. Sıralama ilişkisi olmayan ve kardinalitesi düşük kategoriler için idealdir.
# Pandas ile (hızlı prototipleme için)
df_onehot = pd.get_dummies(df["departman"], prefix="dept", dtype=int)
print(df_onehot.head())
# Scikit-learn ile (pipeline uyumlu)
ohe = OneHotEncoder(sparse_output=False, handle_unknown="ignore")
encoded = ohe.fit_transform(df[["departman"]])
print(f"Sütun sayısı: {encoded.shape[1]}")
print(f"Sütun isimleri: {ohe.get_feature_names_out()}")
Önemli ipucu: Yüksek kardinaliteli özelliklerde (50+ benzersiz değer) one-hot encoding boyutsallık patlamasına yol açar. Bu durumda target encoding veya frequency encoding gibi alternatiflere yönelin.
2.3 Ordinal Encoding (Sıralı Kodlama)
Kategoriler arasında doğal bir sıralama olduğunda tercih edilir. Eğitim durumu buna güzel bir örnek — Lise'den Doktora'ya doğru açık bir hiyerarşi var.
from sklearn.preprocessing import OrdinalEncoder
egitim_sirasi = [["Lise", "Ön Lisans", "Lisans", "Yüksek Lisans", "Doktora"]]
oe = OrdinalEncoder(
categories=egitim_sirasi,
handle_unknown="use_encoded_value",
unknown_value=-1
)
df["egitim_ordinal"] = oe.fit_transform(df[["egitim_durumu"]])
print(df[["egitim_durumu", "egitim_ordinal"]].drop_duplicates().sort_values("egitim_ordinal"))
2.4 Target Encoding (Hedef Kodlama) — Scikit-learn 1.8
Target encoding, her kategoriyi hedef değişkenin koşullu ortalamasıyla kodlar. Yüksek kardinaliteli özellikler için harika çalışır. Scikit-learn 1.3'ten itibaren yerleşik olarak destekleniyor ve 1.8 sürümünde çoklu sınıf desteğiyle birlikte iyice olgunlaştı.
from sklearn.preprocessing import TargetEncoder
te = TargetEncoder(
smooth="auto", # Otomatik düzleştirme (overfitting önleme)
cv=5, # 5 katlı çapraz doğrulama (veri sızıntısı önleme)
target_type="binary"
)
# ÖNEMLİ: fit_transform kullanın, fit + transform değil!
# fit_transform, çapraz doğrulama şeması ile veri sızıntısını önler
df["sehir_target_enc"] = te.fit_transform(
df[["sehir"]],
df["ayrildi"]
)
print(df.groupby("sehir")["sehir_target_enc"].mean().sort_values())
Neden fit_transform? Bu çok önemli bir incelik. Target encoding'de fit(X, y).transform(X) ile fit_transform(X, y) aynı sonucu vermez. fit_transform dahili olarak çapraz doğrulama kullanarak veri sızıntısını (data leakage) engeller. Bunu atlamayın — ciddi bir hata kaynağı.
2.5 Frequency Encoding (Frekans Kodlama)
Her kategoriyi veri setindeki görülme sıklığıyla kodlar. Hedef değişkene ihtiyaç duymaz, bu yüzden veri sızıntısı riski sıfırdır. Yüksek kardinaliteli özellikler için güvenli bir alternatif.
# Pandas ile frequency encoding
freq_map = df["sehir"].value_counts(normalize=True)
df["sehir_freq"] = df["sehir"].map(freq_map)
print(df[["sehir", "sehir_freq"]].drop_duplicates().sort_values("sehir_freq", ascending=False))
3. Tarih ve Zaman Özellik Mühendisliği
Tarih sütunları ham formlarında modeller için neredeyse hiç işe yaramaz. Ama doğru şekilde ayrıştırıldığında? Zengin sinyaller sunarlar. Tarih verisiyle ne kadar uğraşırsanız, o kadar çok bilgi çıkarabilirsiniz.
# Temel tarih bileşenlerini çıkarma
df["giris_yil"] = df["ise_giris_tarihi"].dt.year
df["giris_ay"] = df["ise_giris_tarihi"].dt.month
df["giris_haftanin_gunu"] = df["ise_giris_tarihi"].dt.dayofweek
df["giris_ceyrek"] = df["ise_giris_tarihi"].dt.quarter
# Şirketteki toplam gün sayısı (bugünden farkı)
bugun = pd.Timestamp("2026-02-26")
df["calisma_gunu"] = (bugun - df["ise_giris_tarihi"]).dt.days
df["kidem_yil"] = df["calisma_gunu"] / 365.25
# Mevsimsel döngüsel kodlama (sinüs/kosinüs)
# Ay gibi döngüsel verileri düz sayı olarak kodlamak yanıltıcıdır
# (12 ve 1 birbirine yakındır ama 12 vs 1 farkı 11 olarak görünür)
df["ay_sin"] = np.sin(2 * np.pi * df["giris_ay"] / 12)
df["ay_cos"] = np.cos(2 * np.pi * df["giris_ay"] / 12)
df["gun_sin"] = np.sin(2 * np.pi * df["giris_haftanin_gunu"] / 7)
df["gun_cos"] = np.cos(2 * np.pi * df["giris_haftanin_gunu"] / 7)
print(df[["ise_giris_tarihi", "giris_ay", "ay_sin", "ay_cos"]].head(10))
Döngüsel kodlama neden önemli? Bir düşünün: aylarda 12 (Aralık) ve 1 (Ocak) aslında birbirine en yakın iki ay. Ama ordinal kodlamada aralarındaki fark 11 oluyor. Sinüs ve kosinüs dönüşümleri bu döngüsel ilişkiyi matematiksel olarak korur. Küçük bir detay gibi görünüyor ama fark yaratır.
4. Metin Tabanlı Özellik Çıkarımı
Metin içeren sütunlardan özellik çıkarmak sadece NLP projelerine özgü değil — sıradan veri setlerinde bile işe yarar. Pandas 3.0'ın PyArrow destekli yeni string dtype'ı bu işlemleri belirgin şekilde hızlandırıyor.
# Basit metin özellikleri — örneğin iş tanımı sütunu varsa
# Burada sehir sütununu örnekleyelim
df["sehir_uzunluk"] = df["sehir"].str.len()
df["sehir_kelime_sayisi"] = df["sehir"].str.split().str.len()
# Daha gerçekçi bir senaryo: açıklama sütunu olsaydı
# Bag-of-Words veya TF-IDF ile özellik çıkarımı
from sklearn.feature_extraction.text import TfidfVectorizer
# Örnek metin verisi oluşturalım
yorumlar = [
"Çalışma ortamı çok iyi, maaş yeterli",
"Yönetim kötü ama ekip güzel",
"Maaş düşük, fazla mesai çok",
"Kariyer fırsatları mükemmel",
"İş-yaşam dengesi berbat"
]
tfidf = TfidfVectorizer(max_features=20)
tfidf_matrix = tfidf.fit_transform(yorumlar)
print(f"TF-IDF özellik sayısı: {tfidf_matrix.shape[1]}")
print(f"Kelimeler: {tfidf.get_feature_names_out()}")
5. Özellik Seçimi: Gereksiz Olanları Elemek
Çok fazla özellik üretmek bazen fayda yerine zarar verir. Özellik seçimi, modeli gereksiz gürültüden arındırır ve aşırı öğrenme riskini azaltır. "Daha fazla özellik = daha iyi model" diye düşünmek cazip ama yanıltıcı.
5.1 İstatistiksel Testlerle Seçim
from sklearn.feature_selection import SelectKBest, mutual_info_classif, f_classif
# Hazırlık: eksik değerleri dolduralım
X_secim = df[["yas", "maas", "deneyim_yil", "performans_puani",
"maas_deneyim_orani", "performans_x_deneyim"]].fillna(0)
y_secim = df["ayrildi"]
# Karşılıklı bilgi ile en iyi 4 özelliği seç
selector = SelectKBest(score_func=mutual_info_classif, k=4)
X_selected = selector.fit_transform(X_secim, y_secim)
# Sonuçları görüntüle
scores = pd.Series(
selector.scores_, index=X_secim.columns
).sort_values(ascending=False)
print("Özellik Önem Skorları:")
print(scores)
5.2 Model Tabanlı Seçim
from sklearn.feature_selection import SelectFromModel
from sklearn.ensemble import RandomForestClassifier
# Random Forest ile özellik önem sıralaması
rf = RandomForestClassifier(n_estimators=100, random_state=42)
rf.fit(X_secim, y_secim)
importances = pd.Series(
rf.feature_importances_, index=X_secim.columns
).sort_values(ascending=False)
print("\nRandom Forest Özellik Önemleri:")
print(importances)
# Otomatik seçim (medyanın üstündekiler)
sfm = SelectFromModel(rf, threshold="median")
X_rf_selected = sfm.fit_transform(X_secim, y_secim)
print(f"\nSeçilen özellik sayısı: {X_rf_selected.shape[1]}")
5.3 Korelasyon Tabanlı Eleme
# Yüksek korelasyonlu özellikleri bul ve ele
corr_matrix = X_secim.corr().abs()
upper_triangle = corr_matrix.where(
np.triu(np.ones(corr_matrix.shape), k=1).astype(bool)
)
# Eşik değeri: 0.85 üzerindeki korelasyonlar
yuksek_korr = [
col for col in upper_triangle.columns
if any(upper_triangle[col] > 0.85)
]
print(f"Yüksek korelasyonlu çıkarılacak sütunlar: {yuksek_korr}")
6. Üretim Kalitesinde Pipeline: ColumnTransformer ile Her Şeyi Birleştirin
Burası işlerin ciddileştiği bölüm. Gerçek projelerde özellik mühendisliği adımlarını tek tek uygulamak hem hata riskini artırır hem de veri sızıntısına davetiye çıkarır. Scikit-learn'ün Pipeline ve ColumnTransformer yapısı tam da bu sorunları çözmek için var.
from sklearn.compose import ColumnTransformer, make_column_selector
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import (
StandardScaler, OneHotEncoder, OrdinalEncoder, TargetEncoder
)
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import cross_val_score
# Sütun gruplarını tanımla
sayisal_sutunlar = ["yas", "maas", "deneyim_yil", "performans_puani"]
kategorik_dusuk_kard = ["departman", "uzaktan_calisma"]
kategorik_sirali = ["egitim_durumu"]
kategorik_yuksek_kard = ["sehir"]
# Her grup için ayrı pipeline
sayisal_pipeline = Pipeline(steps=[
("imputer", SimpleImputer(strategy="median")),
("scaler", StandardScaler())
])
kategorik_pipeline = Pipeline(steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("encoder", OneHotEncoder(handle_unknown="ignore", sparse_output=False))
])
sirali_pipeline = Pipeline(steps=[
("imputer", SimpleImputer(strategy="most_frequent")),
("encoder", OrdinalEncoder(
categories=[["Lise", "Ön Lisans", "Lisans", "Yüksek Lisans", "Doktora"]],
handle_unknown="use_encoded_value",
unknown_value=-1
))
])
# ColumnTransformer ile hepsini birleştir
preprocessor = ColumnTransformer(
transformers=[
("sayisal", sayisal_pipeline, sayisal_sutunlar),
("kategorik", kategorik_pipeline, kategorik_dusuk_kard),
("sirali", sirali_pipeline, kategorik_sirali),
("yuksek_kard", TargetEncoder(smooth="auto"), kategorik_yuksek_kard)
],
remainder="drop", # Belirtilmeyen sütunları çıkar
verbose_feature_names_out=True # Okunabilir özellik isimleri
)
# Tam pipeline: ön işleme + model
full_pipeline = Pipeline(steps=[
("preprocessor", preprocessor),
("classifier", GradientBoostingClassifier(
n_estimators=200, max_depth=4, random_state=42
))
])
# Çapraz doğrulama ile değerlendirme
X = df[sayisal_sutunlar + kategorik_dusuk_kard + kategorik_sirali + kategorik_yuksek_kard]
y = df["ayrildi"]
scores = cross_val_score(full_pipeline, X, y, cv=5, scoring="roc_auc")
print(f"ROC-AUC Skorları: {scores}")
print(f"Ortalama ROC-AUC: {scores.mean():.4f} (+/- {scores.std():.4f})")
Bu yaklaşımın avantajları:
- Veri sızıntısı yok: Her çapraz doğrulama katında dönüşümler yalnızca eğitim verisine uygulanır.
- Tekrarlanabilir: Pipeline nesnesi kaydedilebilir ve yeni verilere birebir aynı adımlar uygulanır.
- Hiperparametre araması: GridSearchCV ile hem dönüşüm hem model parametrelerini aynı anda optimize edebilirsiniz.
GridSearchCV ile Pipeline Optimizasyonu
from sklearn.model_selection import GridSearchCV
param_grid = {
"preprocessor__sayisal__imputer__strategy": ["mean", "median"],
"classifier__n_estimators": [100, 200, 300],
"classifier__max_depth": [3, 4, 5],
"classifier__learning_rate": [0.05, 0.1, 0.2]
}
grid_search = GridSearchCV(
full_pipeline,
param_grid,
cv=3,
scoring="roc_auc",
n_jobs=-1,
verbose=1
)
grid_search.fit(X, y)
print(f"En iyi parametreler: {grid_search.best_params_}")
print(f"En iyi ROC-AUC: {grid_search.best_score_:.4f}")
7. Pandas 3.0 ile Gelen Özellik Mühendisliği İyileştirmeleri
Pandas 3.0, özellik mühendisliği iş akışlarını doğrudan etkileyen birkaç önemli değişiklik getirdi. Bunları bilmek günlük iş akışınızı gerçekten kolaylaştırır.
7.1 Copy-on-Write: Güvenli Dönüşümler
Artık bir DataFrame'den alt küme aldığınızda veya atama yaptığınızda, orijinal veri hiçbir zaman değişmiyor. Bu, özellik mühendisliği sırasında yan etki hatalarını tamamen ortadan kaldırıyor. Eskiden bunun için saçınızı yolardınız.
# Pandas 3.0 — Copy-on-Write varsayılan
df_train = df[df["yas"] > 30]
df_train["yeni_ozellik"] = df_train["maas"] * 2 # Orijinal df ETKİLENMEZ
# Pandas 2.x'te bu satır SettingWithCopyWarning verirdi
# Pandas 3.0'da güvenle çalışır
7.2 pd.col() ile Temiz Özellik Oluşturma
# Eski yöntem (lambda tabanlı — hata riski taşır)
df = df.assign(
maas_yas_orani=lambda x: x["maas"] / x["yas"]
)
# Pandas 3.0 yöntemi (pd.col ile — daha okunabilir, daha güvenli)
df = df.assign(
maas_yas_orani_v2=pd.col("maas") / pd.col("yas"),
deneyim_etkinligi=pd.col("performans_puani") * pd.col("deneyim_yil")
)
7.3 Hızlı String İşlemleri
Pandas 3.0'ın yeni string dtype'ı PyArrow destekli. String özellik mühendisliği işlemleri artık 5-10 kat daha hızlı — özellikle büyük veri setlerinde farkı hissedersiniz.
# String sütunları artık otomatik olarak PyArrow-backed
# Özellik çıkarımı çok daha hızlı
df["dept_buyuk"] = df["departman"].str.upper()
df["dept_uzunluk"] = df["departman"].str.len()
print(df["departman"].dtype) # string[pyarrow] (Pandas 3.0)
8. En Sık Yapılan Hatalar ve Çözümleri
Özellik mühendisliğinde bazı hatalar modeli gerçekten felakete sürükleyebilir. Bunları en az bir kez yaşamadan öğrenmek zor ama işte en yaygın olanları (ve çözümleri):
- Eğitim verisine sızma (data leakage): Hedef değişken bilgisini eğitim özelliklerine sızdırmak. Model eğitimde harika görünür, üretimde çöker. Çözüm: Pipeline kullanın, dönüşümleri her zaman eğitim kümesinde uygulayın.
- Sırasız kategorilere sıralı kodlama uygulamak: Departman sütununa LabelEncoder uygulamak, model için "Satış > Pazarlama" gibi var olmayan bir ilişki yaratır. Çözüm: One-hot veya target encoding kullanın.
- Yüksek kardinaliteye one-hot encoding: 100 farklı şehir demek 100 yeni sütun demek. Boyutsallık patlaması. Çözüm: Target encoding veya frequency encoding tercih edin.
- Eksik veri stratejisini test verisine sızdırmak: Ortalama doldurmayı tüm veri üzerinde hesaplamak. Çözüm: Pipeline içinde SimpleImputer kullanın.
- Aşırı özellik üretimi: "Ne kadar çok o kadar iyi" mantığı burada geçerli değil. Çözüm: Özellik seçimi uygulayın.
Sıkça Sorulan Sorular
Özellik mühendisliği mi yoksa daha iyi algoritma mı daha etkilidir?
Hem araştırmalar hem Kaggle yarışmaları tutarlı biçimde aynı şeyi söylüyor: iyi özellik mühendisliği, algoritma değişikliğinden çok daha büyük etki yaratır. Ortalama bir veri setinde doğru özellikler %10-50 doğruluk artışı sağlarken, algoritma değişimi genellikle %1-5 aralığında kalır. Önce özelliklerinizi optimize edin, sonra algoritmaya bakın.
Target encoding ne zaman kullanılmalı, ne zaman one-hot encoding?
Basit kural: kategorinin benzersiz değer sayısı 10'dan azsa one-hot encoding idealdir. 10-50 arası duruma göre değişir (verinin boyutuna da bağlı). 50'den fazla benzersiz değer varsa — posta kodu, ürün ID gibi — target encoding veya frequency encoding tercih edin. Target encoding kullanırken mutlaka çapraz doğrulama ile birlikte uygulayın, aksi halde veri sızıntısı kaçınılmaz.
Ağaç tabanlı modeller için de ölçeklendirme gerekli mi?
Hayır, gerekmez. Random Forest, XGBoost, LightGBM gibi ağaç tabanlı modeller özellik ölçeğinden bağımsız çalışır çünkü bölme kararları göreli sıralamaya dayanır. Ancak SVM, lojistik regresyon, k-NN ve sinir ağları gibi mesafe veya gradyan tabanlı modellerde ölçeklendirme zorunludur.
Pandas 3.0 özellik mühendisliği iş akışımı nasıl etkiler?
Üç büyük değişiklik var. Birincisi, Copy-on-Write artık varsayılan olduğundan o meşhur SettingWithCopyWarning hatası geçmişte kaldı. İkincisi, yeni pd.col() sözdizimi lambda fonksiyonlara olan ihtiyacı kaldırarak daha okunabilir kod yazmanızı sağlıyor. Üçüncüsü, PyArrow destekli string dtype metin özellik mühendisliğini 5-10 kat hızlandırıyor.
Özellik seçimi ile boyut indirgeme (PCA) arasındaki fark nedir?
Özellik seçimi mevcut özelliklerden en önemlilerini seçer ve yorumlanabilirliği korur. PCA ise tüm özellikleri yeni bileşenlere dönüştürür — yorumlanabilirlik kaybolur. İş kuralları ve açıklanabilirlik önemliyse özellik seçimi, yalnızca tahmin performansı önemliyse PCA tercih edin.