Ana içeriğe geç
Kesit Python
İleri · Makine öğrenmesi

Regresyon ve sınıflandırma modelleri

Çoklu regresyon ve katsayı yorumu, Ridge/Lasso, lojistik regresyon ve predict_proba, karar ağacı, rastgele orman, gradient boosting; karışıklık matrisi, precision/recall/F1, ROC-AUC, dengesiz sınıflar ve maliyete dayalı eşik seçimi.

Uygulamada aç, 28 alıştırmayı çözÜcretsiz, hesap gerekmez, kurulum yok.

Bu sayfa dersin okuma sürümüdür. Metin bir kutuyu çalıştırmanı ya da adıma geçmeni söylüyorsa dersi uygulamada aç.

İki iş sorusu, iki problem türü

ml-giris dersinde ML'in iskeletini kurdun: bölme, fit, predict, metrik. Şimdi iki gerçekçi soruyu derinlemesine çözeceğiz. Anadolu Market "bir müşterinin sepet tutarı ne olacak?" diye soruyor; bu bir regresyon (sayısal hedef). Ilgaz Bank ise "bu kredi başvurusu temerrüde düşer mi?" diye soruyor; bu bir sınıflandırma (kategorik hedef). İkisinde de model kurmak işin yarısıdır; diğer yarısı modelin ne söylediğini yorumlamak ve iş kararına (kampanya bütçesi, kredi onayı) çevirmektir.

Örnek veriler kurgusaldır ve numpy.random.default_rng(seed) ile üretilir; aynı tohumla her çalıştırmada aynı tablo gelir. Gerçek projede bunlar veri ambarından gelir, ama yöntem aynıdır.

import numpy as np


def sepet_verisi(n=500, seed=42):
    """Anadolu Market kurgusal sepet verisi: ürün adedi, üye mi, kampanya, mesafe (km)."""
    rng = np.random.default_rng(seed)
    urun = rng.integers(1, 15, n)
    uye = rng.integers(0, 2, n)
    kampanya = rng.integers(0, 2, n)
    mesafe = rng.uniform(1, 30, n)
    sepet = 40 + 35 * urun + 60 * uye - 25 * kampanya + rng.normal(0, 30, n)
    return np.column_stack([urun, uye, kampanya, mesafe]), sepet

X, y = sepet_verisi()
print(X.shape, round(y.mean(), 1))
print(X[:3].round(1))

Doğrusal ve çoklu regresyon: katsayıyı okumak

Çoklu doğrusal regresyon tahmini ŷ = b0 + b1·urun + b2·uye + b3·kampanya + b4·mesafe biçiminde kurar. Her katsayı (coefficient) şunu söyler: diğer özellikler sabitken bu özellik bir birim artarsa tahmin ne kadar değişir? Bu yorum, modeli iş birimine anlatmanın en güçlü aracıdır.

import numpy as np


def sepet_verisi(n=500, seed=42):
    """Anadolu Market kurgusal sepet verisi: ürün adedi, üye mi, kampanya, mesafe (km)."""
    rng = np.random.default_rng(seed)
    urun = rng.integers(1, 15, n)
    uye = rng.integers(0, 2, n)
    kampanya = rng.integers(0, 2, n)
    mesafe = rng.uniform(1, 30, n)
    sepet = 40 + 35 * urun + 60 * uye - 25 * kampanya + rng.normal(0, 30, n)
    return np.column_stack([urun, uye, kampanya, mesafe]), sepet

from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split

X, y = sepet_verisi()
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.2, random_state=0)
model = LinearRegression().fit(X_tr, y_tr)
for ad, k in zip(["urun", "uye", "kampanya", "mesafe"], model.coef_):
    print(f"{ad:>9}: {k:+.2f} TL")
print(f"    sabit: {model.intercept_:.2f} TL")
print("Test R²:", round(model.score(X_te, y_te), 3))

Okuma: her ek ürün sepete yaklaşık 35 TL ekliyor, üye müşteriler ortalama 60 TL daha fazla harcıyor, kampanyalı sepetler ~25 TL daha düşük (indirim etkisi), mesafenin katsayısı sıfıra yakın: etkisi yok. Veriyi biz ürettiğimiz için gerçek değerleri biliyoruz ve modelin onları bulduğunu görüyoruz.

Katsayı nedensellik değildir"Üyelik 60 TL artırıyor" demek, "herkesi üye yaparsak sepet 60 TL büyür" demek değildir; zaten çok alışveriş yapanlar üye oluyor olabilir. Katsayılar ilişkiyi ölçer. Ayrıca özellikler farklı ölçeklerdeyse (TL ile adet) katsayıların büyüklüğü karşılaştırılamaz; önce ölçeklemek gerekir (ml-pipeline-degerlendirme).

Düzenlileştirme: Ridge ve Lasso

Özellik sayısı arttıkça ya da özellikler birbiriyle güçlü ilişkiliyse (çoklu doğrusallık, multicollinearity) doğrusal regresyon katsayıları şişer ve aşırı öğrenir. Düzenlileştirme (regularization), büyük katsayılara ceza ekler:

ModelCezaEtkisiNe zaman
LinearRegressionYokSaf en küçük karelerAz ve anlamlı özellik
Ridge(alpha)Katsayıların karesi (L2)Hepsini küçültür, sıfırlamazİlişkili çok özellik
Lasso(alpha)Katsayıların mutlak değeri (L1)Gereksizleri tam sıfıra indirirÖzellik seçimi istendiğinde
ElasticNetL1 + L2 karışımıİkisinin dengesiÇok sayıda ilişkili özellik
import numpy as np


def sepet_verisi(n=500, seed=42):
    """Anadolu Market kurgusal sepet verisi: ürün adedi, üye mi, kampanya, mesafe (km)."""
    rng = np.random.default_rng(seed)
    urun = rng.integers(1, 15, n)
    uye = rng.integers(0, 2, n)
    kampanya = rng.integers(0, 2, n)
    mesafe = rng.uniform(1, 30, n)
    sepet = 40 + 35 * urun + 60 * uye - 25 * kampanya + rng.normal(0, 30, n)
    return np.column_stack([urun, uye, kampanya, mesafe]), sepet

from sklearn.linear_model import Ridge, Lasso

X, y = sepet_verisi()
for alpha in [0.1, 10]:
    r = Ridge(alpha=alpha).fit(X, y)
    l = Lasso(alpha=alpha).fit(X, y)
    print(f"alpha={alpha:<4} Ridge: {r.coef_.round(1)}  Lasso: {l.coef_.round(1)}")

alpha cezanın gücüdür: büyüdükçe katsayılar küçülür. Lasso yüksek alpha'da etkisiz mesafe'yi ve hatta zayıf kampanya'yı sıfırlar. Doğru alpha'yı çapraz doğrulamayla (cross-validation) seçersin (RidgeCV, LassoCV ya da GridSearchCV).

Lojistik regresyon ve olasılık

Adı regresyon olsa da lojistik regresyon (logistic regression) bir sınıflandırıcıdır. Doğrusal skoru sigmoid fonksiyonundan geçirip 0-1 arası bir olasılığa çevirir. predict_proba her sınıfın olasılığını verir; sütun sırası model.classes_ ile aynıdır, ikili problemde pozitif sınıf (1 = temerrüt) ikinci sütundur: [:, 1]. predict ise varsayılan olarak 0.5 eşiğini uygular.

import numpy as np


def kredi_verisi(n=2000, seed=0):
    """Ilgaz Bank kurgusal kredi verisi: gelir (bin TL), borç oranı, gecikme sayısı, yaş."""
    rng = np.random.default_rng(seed)
    gelir = rng.normal(35, 12, n).clip(8, None)
    borc_orani = rng.uniform(0, 0.9, n)
    gecikme = rng.poisson(0.6, n)
    yas = rng.integers(21, 66, n)
    logit = -4.3 + 3.0 * borc_orani + 0.9 * gecikme - 0.05 * (gelir - 35)
    y = (rng.random(n) < 1 / (1 + np.exp(-logit))).astype(int)
    return np.column_stack([gelir, borc_orani, gecikme, yas]), y

from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split

X, y = kredi_verisi()
print("temerrüt oranı:", round(y.mean(), 3))
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.25, random_state=0, stratify=y)
model = LogisticRegression(max_iter=1000).fit(X_tr, y_tr)
olasilik = model.predict_proba(X_te[:5])
print(model.classes_)
print(olasilik.round(3))
print("P(temerrüt):", olasilik[:, 1].round(3))
print("predict    :", model.predict(X_te[:5]))

Ağaçlar ve topluluklar

Karar ağacı doğrusal olmayan ilişkileri ve etkileşimleri (yüksek borç oranı ve gecikme) kendiliğinden yakalar ama tek başına kolayca aşırı öğrenir. Topluluk (ensemble) yöntemleri birçok ağacı birleştirir:

import numpy as np


def kredi_verisi(n=2000, seed=0):
    """Ilgaz Bank kurgusal kredi verisi: gelir (bin TL), borç oranı, gecikme sayısı, yaş."""
    rng = np.random.default_rng(seed)
    gelir = rng.normal(35, 12, n).clip(8, None)
    borc_orani = rng.uniform(0, 0.9, n)
    gecikme = rng.poisson(0.6, n)
    yas = rng.integers(21, 66, n)
    logit = -4.3 + 3.0 * borc_orani + 0.9 * gecikme - 0.05 * (gelir - 35)
    y = (rng.random(n) < 1 / (1 + np.exp(-logit))).astype(int)
    return np.column_stack([gelir, borc_orani, gecikme, yas]), y

from sklearn.ensemble import RandomForestClassifier, HistGradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split

X, y = kredi_verisi()
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.25, random_state=0, stratify=y)
modeller = {
    "lojistik": LogisticRegression(max_iter=1000),
    "orman": RandomForestClassifier(n_estimators=200, min_samples_leaf=5, random_state=0),
    "boosting": HistGradientBoostingClassifier(max_depth=3, random_state=0),
}
for ad, m in modeller.items():
    m.fit(X_tr, y_tr)
    print(f"{ad:>9} ROC-AUC: {roc_auc_score(y_te, m.predict_proba(X_te)[:, 1]):.3f}")
orman = modeller["orman"]
for ad, o in zip(["gelir", "borc_orani", "gecikme", "yas"], orman.feature_importances_):
    print(f"{ad:>11}: {o:.3f}")

Bu veri gerçekte doğrusal bir kuralla üretildiği için lojistik regresyon çok iyi iş çıkarır; karmaşık model her zaman kazanmaz. Özellik önemi (feature importance) ise ağaç modellerinde her özelliğin bölmelere katkısını gösterir. Dikkat: yas hedefle ilgisiz olduğu hâlde sıfır olmayan önem alabilir; çok değerli sayısal özellikler ağaçlarda önemi şişirebilir. Daha güvenilir ölçü için sklearn.inspection.permutation_importance kullan.

Sınıflandırma metrikleri

Temerrüt oranı %10 civarındaysa "herkes öder" diyen model %90 doğruluk alır. Bu yüzden karışıklık matrisine (confusion matrix) bakarız:

Tahmin: 0 (öder)Tahmin: 1 (temerrüt)
Gerçek: 0TN (doğru negatif)FP (yanlış alarm: iyi müşteriyi reddettin)
Gerçek: 1FN (kaçırılan: kötü krediyi onayladın)TP (doğru yakalanan)
from sklearn.metrics import confusion_matrix, precision_score, recall_score, f1_score, classification_report

gercek = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1]
tahmin = [0, 0, 0, 0, 1, 1, 1, 1, 1, 0]
print(confusion_matrix(gercek, tahmin).tolist())     # [[TN, FP], [FN, TP]]
print("precision:", round(precision_score(gercek, tahmin), 3))
print("recall   :", round(recall_score(gercek, tahmin), 3))
print("f1       :", round(f1_score(gercek, tahmin), 3))
print(classification_report(gercek, tahmin, target_names=["öder", "temerrüt"]))

Dengesiz sınıflar ve eşik seçimi

Dengesiz veride model azınlık sınıfını görmezden gelmeye meyillidir. İki temel kol var: class_weight="balanced" ile azınlık sınıfının hatalarını daha pahalı yapmak, ve eşiği (threshold) iş maliyetine göre seçmek. Eşiği düşürmek daha çok başvuruyu riskli sayar: recall artar, precision düşer. Doğru eşik bir matematik sorusu değil, iş sorusudur: kaçırılan bir temerrüt bankaya ortalama ne kadara mal oluyor, yanlış reddedilen iyi müşteri ne kadar kâr kaybettiriyor?

import numpy as np


def kredi_verisi(n=2000, seed=0):
    """Ilgaz Bank kurgusal kredi verisi: gelir (bin TL), borç oranı, gecikme sayısı, yaş."""
    rng = np.random.default_rng(seed)
    gelir = rng.normal(35, 12, n).clip(8, None)
    borc_orani = rng.uniform(0, 0.9, n)
    gecikme = rng.poisson(0.6, n)
    yas = rng.integers(21, 66, n)
    logit = -4.3 + 3.0 * borc_orani + 0.9 * gecikme - 0.05 * (gelir - 35)
    y = (rng.random(n) < 1 / (1 + np.exp(-logit))).astype(int)
    return np.column_stack([gelir, borc_orani, gecikme, yas]), y

import numpy as np
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import precision_score, recall_score
from sklearn.model_selection import train_test_split

X, y = kredi_verisi()
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.25, random_state=0, stratify=y)
for cw in [None, "balanced"]:
    m = LogisticRegression(max_iter=1000, class_weight=cw).fit(X_tr, y_tr)
    p = m.predict(X_te)
    print(f"class_weight={str(cw):<8} recall={recall_score(y_te, p):.2f} precision={precision_score(y_te, p, zero_division=0):.2f}")

m = LogisticRegression(max_iter=1000).fit(X_tr, y_tr)
risk = m.predict_proba(X_te)[:, 1]
for esik in [0.5, 0.3, 0.15]:
    p = (risk >= esik).astype(int)
    print(f"eşik={esik:<4} recall={recall_score(y_te, p):.2f} precision={precision_score(y_te, p, zero_division=0):.2f} riskli sayılan={p.mean():.0%}")
Model seçimi ile eşik seçimi ayrı işlerdirModelleri eşikten bağımsız bir metrikle (ROC-AUC, dengesiz veride PR-AUC / average_precision_score) karşılaştır. Kazanan modelin eşiğini sonra iş maliyetiyle belirle. Eşiği de test setinde değil doğrulama verisinde seç.

Model seçimi: bir yol haritası

Yeni bir regresyon ya da sınıflandırma problemine başladığında hangi modeli deneyeceğini rastgele seçme; aşağıdaki sıra hem zaman kazandırır hem de sonuçlarını savunmanı kolaylaştırır.

AdımRegresyonSınıflandırmaNeden
1. Taban çizgiDummyRegressor (ortalama)DummyClassifier (en sık sınıf)Her modelin geçmesi gereken alt sınır
2. Basit ve yorumlanabilirLinearRegression / RidgeLogisticRegressionKatsayılar iş birimine anlatılabilir
3. Doğrusal olmayanRandomForestRegressorRandomForestClassifierEtkileşimleri kendiliğinden yakalar, az ayar ister
4. En güçlü adayHistGradientBoostingRegressorHistGradientBoostingClassifierTablo verisinde genellikle en iyi skor
5. KararSkor farkı, yorumlanabilirlik ihtiyacı, eğitim/tahmin süresi ve bakım maliyeti birlikte tartılır"En yüksek skor" tek ölçüt değildir

Regresyonda hata metriklerini de iş diline çevirmeyi unutma. "RMSE 31.4" yerine "sepet tutarı tahminlerimiz tipik olarak ±30 TL sapıyor; bu, kampanya bütçesi planlamasında yüzde birkaçlık bir hata payı demek" cümlesi karar vericinin işine yarar. Hataların dağılımına da bak: model küçük sepetlerde iyi, büyük kurumsal siparişlerde kötüyse ortalama metrik bunu gizler. Tahmin ile gerçeği karşılaştıran bir saçılım grafiği ya da hataların segment bazında (üye/üye değil, şehir) ortalaması, tek bir sayının saklayacağı sorunları ortaya çıkarır. Sınıflandırmada da aynı ilke geçerli: genel AUC iyiyken belirli bir müşteri grubunda recall çok düşükse, bu hem iş hem de adalet (fairness) sorunudur ve model kartında açıkça yazılmalıdır.

Son olarak, aynı veride çok sayıda model ve ayar deneyip en iyisini seçmek de bir tür aşırı öğrenmedir (overfitting). Karşılaştırmaları sabit bir çapraz doğrulama düzeninde yap, test setini yalnızca en sonda seçilen tek model için kullan. Bunun sistematik yolu (Pipeline, cross_val_score, GridSearchCV) bir sonraki dersin konusu.

Gerçek işteKredi skorlama ekipleri tek bir "onay/red" eşiği yerine çoğu zaman bantlar kullanır: düşük risk otomatik onay, orta risk analist incelemesi, yüksek risk red. Her bandın sınırı geçmiş kayıp verisiyle belirlenir ve düzenleyici kurumlar modelin açıklanabilir olmasını ister. Bu yüzden bankalarda lojistik regresyon, daha güçlü boosting modellerine rağmen hâlâ yaygındır: katsayısı tek tek gerekçelendirilebilir.
Derinleş

Derinleş: gradient boosting uygulamada (HistGradientBoosting, XGBoost, LightGBM)

Tablo verisinde (satış, kredi, lojistik) en sık kazanan model ailesi gradient boosting'dir: sığ ağaçlar sırayla eklenir ve her yeni ağaç öncekilerin hatasını (artıkları, residuals) düzeltmeye çalışır. Tahmin, başlangıç değeri artı her ağacın learning_rate ile küçültülmüş katkılarının toplamıdır. Bu bölümde scikit-learn'ün hızlı uygulaması HistGradientBoosting'i Lezzet Kurye'nin gerçek teslimat verisiyle (lezzet_kurye, 6638 teslim edilmiş sipariş) ayarlayacak, sonra aynı ayarların XGBoost ve LightGBM'deki karşılıklarını göreceksin.

artik_tahmin = [30.0] * 4                 # başlangıç: ortalama süre (dk)
gercek = [25.0, 40.0, 35.0, 20.0]
for tur in range(3):
    artik = [g - t for g, t in zip(gercek, artik_tahmin)]
    duzeltme = [a * 0.5 for a in artik]   # "ağaç" artığı mükemmel bilseydi; lr = 0.5
    artik_tahmin = [t + d for t, d in zip(artik_tahmin, duzeltme)]
    print(tur + 1, [round(t, 1) for t in artik_tahmin])

Her tur hatanın yarısını kapatır; küçük learning_rate daha çok tur ister ama genellikle daha iyi genelleşir. Gerçekte ağaç artığı tam bilemez; derinliği ve yaprak sayısı sınırlı olduğu için genel örüntüyü öğrenir.

Neden "Hist"?

Klasik GradientBoostingClassifier her bölme için tüm benzersiz değerleri dener. HistGradientBoostingRegressor/Classifier ise önce her sütunu en fazla 255 kutuya (bin) ayırır ve bölmeleri kutu sınırlarında arar; on binlerce satırda çok daha hızlıdır. Ayrıca eksik değerleri (NaN) kendisi yönetir ve kategorik sütunları one-hot yapmadan doğrudan kullanabilir.

import veri
import pandas as pd

def kurye_verisi():
    o = veri.oku("lezzet_kurye", "lk_orders")
    r = veri.oku("lezzet_kurye", "lk_restaurants")
    k = veri.oku("lezzet_kurye", "lk_couriers")
    s = veri.oku("lezzet_kurye", "lk_order_lines")
    o = o[o["status"] == "teslim"].copy()
    zaman = pd.to_datetime(o["placed_at"])
    o["saat"] = zaman.dt.hour
    o["hafta_sonu"] = (zaman.dt.dayofweek >= 5).astype(int)
    o["sure_dk"] = (pd.to_datetime(o["delivered_at"]) - zaman).dt.total_seconds() / 60
    adet = s.groupby("order_id")["qty"].sum().rename("adet").reset_index()
    d = (o.merge(r[["restaurant_id", "cuisine", "city"]], on="restaurant_id")
          .merge(k[["courier_id", "vehicle"]], on="courier_id")
          .merge(adet, on="order_id"))
    d["restoran"] = d["restaurant_id"].astype(str)
    X = d[["saat", "hafta_sonu", "adet", "cuisine", "city", "vehicle", "restoran"]].copy()
    for c in ["cuisine", "city", "vehicle", "restoran"]:
        X[c] = X[c].astype("category")
    return X, d["sure_dk"]
from sklearn.model_selection import train_test_split
X, y = kurye_verisi()
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.25, random_state=0)
KATEGORIK = ["cuisine", "city", "vehicle", "restoran"]
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.metrics import mean_absolute_error

print(X.shape, "| ortalama süre:", round(y.mean(), 1), "dk")
taban = mean_absolute_error(y_te, [y_tr.mean()] * len(y_te))
model = HistGradientBoostingRegressor(
    categorical_features=KATEGORIK,   # pandas category sütunları
    learning_rate=0.1, max_iter=500, max_leaf_nodes=15,
    early_stopping=True, validation_fraction=0.15, n_iter_no_change=10,
    random_state=0)
model.fit(X_tr, y_tr)
print("taban MAE:", round(taban, 2), "| HGB MAE:", round(mean_absolute_error(y_te, model.predict(X_te)), 2))
print("durduğu tur:", model.n_iter_)

Model ortalamaya göre hatayı azaltıyor ama mucize beklenmemeli: teslimat süresini trafik, hava ve restoranın o anki yoğunluğu da belirler ve bunlar veride yok. Erken durdurma 500 tur yerine birkaç on turda durdu; n_iter_ bunu gösterir.

Önemli ayarlar

ParametreVarsayılanEtkisi
learning_rate0.1Her ağacın katkısını küçültür. Düşür (0.05) → daha çok tur, genelde daha iyi sonuç.
max_iter100En fazla ağaç sayısı. Erken durdurmayla birlikte üst sınır gibi düşün.
max_leaf_nodes31Ağaç başına yaprak; modelin karmaşıklığı. Asıl ayar budur.
max_depthNoneDerinlik sınırı; genelde max_leaf_nodes yeterli.
min_samples_leaf20Yapraktaki en az satır; büyütmek gürültüyü ezberlemeyi azaltır.
l2_regularization0Yaprak değerlerini küçülten ceza.
early_stopping"auto"10.000 satırdan büyük veride kendiliğinden açılır; validation_fraction ve n_iter_no_change ile birlikte çalışır.
categorical_features"from_dtype" (yeni sürümler)Kategorik sütunlar; ad listesi ya da bool maske ver. Kategori sayısı max_bins'i (255) aşmamalı.
monotonic_cstNone"adet artınca süre azalmasın" gibi iş kuralını modele zorlar.
Ayar sırası1) learning_rate=0.1 ve erken durdurmayla başla. 2) max_leaf_nodes (15–63) ve min_samples_leaf (20–200) ara. 3) l2_regularization ekle. 4) En sonda learning_rate'i düşürüp max_iter'i büyüt. Aramayı çapraz doğrulamayla yap (pipeline dersindeki HalvingGridSearchCV burada çok işe yarar).

XGBoost ve LightGBM karşılıkları

İş ilanlarında XGBoost ve LightGBM adları sık geçer. İkisi de aynı fikrin bağımsız, çok optimize uygulamalarıdır ve scikit-learn uyumlu sınıflar (XGBRegressor, LGBMRegressor) sunar; yani pipeline, çapraz doğrulama ve arama araçları aynen çalışır. Kavramlar birebir eşlenir, adlar değişir:

scikit-learn HGBXGBoostLightGBM
learning_ratelearning_rate (eta)learning_rate
max_itern_estimatorsn_estimators (num_iterations)
max_leaf_nodesmax_leavesnum_leaves
max_depthmax_depth (varsayılan 6)max_depth (varsayılan -1, sınırsız)
min_samples_leafmin_child_weight (ağırlık toplamı, birebir değil)min_child_samples
l2_regularizationreg_lambdareg_lambda (lambda_l2)
max_binsmax_binmax_bin
n_iter_no_changeearly_stopping_roundscallbacks=[early_stopping(n)]
categorical_featuresenable_categorical=True + category dtypecategory dtype ya da categorical_feature
(yok)subsample, colsample_bytreebagging_fraction, feature_fraction
# pip install xgboost lightgbm
from xgboost import XGBRegressor
from lightgbm import LGBMRegressor, early_stopping

xgb = XGBRegressor(n_estimators=500, learning_rate=0.1, max_leaves=15, tree_method="hist",
                   enable_categorical=True, early_stopping_rounds=10, random_state=0)
xgb.fit(X_tr, y_tr, eval_set=[(X_te, y_te)], verbose=False)   # gerçekte ayrı bir doğrulama seti kullan
print(xgb.best_iteration)

lgbm = LGBMRegressor(n_estimators=500, learning_rate=0.1, num_leaves=15, random_state=0, verbose=-1)
lgbm.fit(X_tr, y_tr, eval_set=[(X_te, y_te)], callbacks=[early_stopping(10, verbose=False)])
print(lgbm.best_iteration_)
Erken durdurmada test sızıntısıYukarıdaki kısa örnekte eval_set olarak test seti verildi; gerçek projede bu sızıntıdır, çünkü tur sayısını test setine bakarak seçersin. Eğitim verisinden ayrı bir doğrulama parçası ayır; HGB'nin validation_fraction ayarı bunu senin yerine yapar.
Gerçek işteKaggle tablo yarışmalarının ve bankaların kredi skor kartlarının büyük kısmı boosting modelleridir. Mülakatlarda sık sorulan sorular: "learning_rate ile n_estimators ilişkisi nedir?", "aşırı öğrenmeyi hangi ayarlarla kontrol edersin?", "kategorik sütunu nasıl verirsin?" Bu tabloyu bilmek üç soruyu da cevaplar. Kütüphane seçiminde ekip standardı belirleyicidir; scikit-learn HGB ek bağımlılık istemediği için iyi bir varsayılandır.
Uzmanlaş

Olasılık kalibrasyonu

Bir modelin 0.20 dediği başvuruların gerçekten yaklaşık %20'si temerrüde düşüyorsa model kalibredir. Lojistik regresyon genellikle iyi kalibredir; rastgele orman ve class_weight="balanced" kullanılan modeller olasılıkları çarpıtır (balanced, olasılıkları yukarı iter). Beklenen kayıp gibi olasılığın kendisinin kullanıldığı hesaplarda CalibratedClassifierCV ile kalibre et, sklearn.calibration.calibration_curve ile kontrol et.

Çok sınıflı metrikler

Üç ve daha fazla sınıfta precision/recall her sınıf için ayrı hesaplanır ve birleştirilir: average="macro" (her sınıfa eşit ağırlık; azınlık sınıflarını önemser), average="weighted" (sınıf büyüklüğüyle ağırlıklı), average="micro" (tüm kararları havuzlar; doğruluğa eşittir). classification_report üçünü birden gösterir.

Beklenen kayıp

Bankacılıkta beklenen kayıp = PD (temerrüt olasılığı) × LGD (temerrüt hâlinde kayıp oranı) × EAD (temerrüt anındaki risk tutarı). Senin sınıflandırıcın PD'yi üretir; bu yüzden olasılıkların kalibre olması doğrudan para demektir.

import numpy as np

pd_ = np.array([0.02, 0.10, 0.35])          # model çıktısı
lgd = 0.45                                   # teminata göre kayıp oranı
ead = np.array([50_000, 120_000, 30_000])    # kredi tutarları (TL)
beklenen = pd_ * lgd * ead
print(beklenen.round(0), "toplam:", round(beklenen.sum()))
Alıştırmalara geç (28)