Ana içeriğe geç
Kesit Python
Orta · Veri analizine giriş

Makine öğrenmesine giriş

Denetimli/denetimsiz öğrenme, özellik ve hedef, eğitim/test ayrımı, scikit-learn estimator API'si (fit/predict/score), ilk modeller, aşırı/eksik öğrenme, veri sızıntısı, temel metrikler ve CRISP-DM akışı.

Uygulamada aç, 18 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ç.

Kural yazmak yerine kuralı öğrenmek

Ilgaz Bank'ın kredi biriminde yıllardır şöyle kurallar yazılır: "Geliri 30 bin TL'nin altındaysa ve son bir yılda iki gecikmesi varsa reddet." Kurallar çoğaldıkça birbirine çarpar, yeni bir müşteri profili geldiğinde kimse hangi kuralı güncelleyeceğini bilemez. Makine öğrenmesi (machine learning, ML) bu işi tersine çevirir: kuralı sen yazmazsın, geçmiş örneklerden (geçmiş başvurular ve sonuçları) bir algoritma kuralı kendisi öğrenir. Sen veriyi hazırlar, doğru soruyu sorar ve öğrenilen modelin gerçekten işe yarayıp yaramadığını ölçersin.

Bu derste ML'in temel sözlüğünü, scikit-learn kütüphanesinin ortak arayüzünü, ilk üç modelini ve en önemlisi bir modeli dürüstçe değerlendirmeyi öğreneceksin. numpy dizilerini (numpy dersi) ve pandas DataFrame'lerini (pandas-giris) bildiğini varsayıyoruz; ortalama, varyans gibi kavramlar istatistik dersinden tanıdık gelecek.

Öğrenme türleri

TürVeride ne var?SoruÖrnek
Denetimli (supervised) — regresyonÖzellikler + sayısal hedef"Ne kadar?"Sepet tutarı, teslim süresi, ev fiyatı
Denetimli — sınıflandırmaÖzellikler + kategorik hedef"Hangisi?"Kredi temerrüde düşer mi, e-posta spam mı
Denetimsiz (unsupervised)Yalnızca özellikler, hedef yok"Nasıl gruplanıyor?"Müşteri segmentleri, anormal işlemler
Pekiştirmeli (reinforcement)Ortam + ödül sinyali"Hangi hamle?"Depo robotu rotası, oyun oynayan ajan

Bu dersten itibaren üç ders boyunca denetimli öğrenmeye odaklanacağız; kümeleme gibi denetimsiz yöntemleri ml-kumeleme dersinde göreceksin.

Özellik, hedef ve X/y

Bir tablo düşün: her satır bir örnek (sample; bir müşteri, bir sipariş), her sütun bir özellik (feature; yaş, gelir, sepet adedi). Tahmin etmek istediğin sütun ise hedef (target, label). scikit-learn geleneği: özellik matrisine büyük X, hedef vektörüne küçük y denir. X her zaman iki boyutludur: şekli (örnek_sayısı, özellik_sayısı). Tek özelliğin olsa bile (n, 1) olmalı.

import numpy as np
from sklearn.datasets import load_iris, make_classification

iris = load_iris()                    # internet gerektirmez, kütüphaneyle gelir
X, y = iris.data, iris.target
print(X.shape, y.shape)               # 150 çiçek, 4 özellik
print(iris.feature_names)
print(list(iris.target_names), np.bincount(y))

# Sentetik veri: kontrollü deneyler için
Xs, ys = make_classification(n_samples=200, n_features=5, n_informative=3, random_state=42)
print(Xs.shape, np.bincount(ys))

metrekare = np.array([65, 90, 120, 150])
print(metrekare.shape, metrekare.reshape(-1, 1).shape)   # tek özellik: (n, 1)
Neden yerleşik veri setleri?load_iris, load_diabetes, load_wine, load_breast_cancer scikit-learn ile birlikte diske gelir; ağ istemez. make_classification ve make_regression ise istediğin boyutta sentetik veri üretir. random_state verdiğinde her çalıştırmada aynı veri çıkar; deneylerin tekrarlanabilir olur.

Eğitim ve test: modelin sınav kâğıdı

Bir öğrenciyi, çalıştığı soruların aynısıyla sınava sokarsan ezberlediği için tam not alır ama konuyu anlayıp anlamadığını öğrenemezsin. Modeller de böyledir. Bu yüzden veriyi en baştan ikiye ayırırız: eğitim seti (training set) ile model öğrenir, test seti (test set) ile hiç görmediği veride nasıl davrandığını ölçeriz. Test setine değerlendirme anına kadar dokunulmaz.

import numpy as np
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42, stratify=y
)
print(X_train.shape, X_test.shape)
print("eğitim sınıf dağılımı:", np.bincount(y_train))
print("test sınıf dağılımı:  ", np.bincount(y_test))
Zaman verisi karıştırılmazSatış tahmini gibi zamana bağlı problemlerde rastgele bölme, modele "gelecekten" bilgi sızdırır. Orada eğitim eski tarihler, test yeni tarihler olur (ör. Ocak-Eylül ile eğit, Ekim-Aralık ile test et). pandas-zaman-serisi dersindeki tarih süzmesi tam bunun için.

scikit-learn'ün ortak dili: estimator API

scikit-learn'ün en güzel yanı tutarlılığıdır: yüzlerce farklı algoritma aynı metotlarla kullanılır. Bir modeli öğrendiğinde hepsini öğrenmiş olursun.

MetotNe yaparKimde var
fit(X, y)Veriden öğrenir, nesnenin kendisini döndürürHepsi (denetimsizde yalnız fit(X))
predict(X)Yeni örnekler için tahmin üretirModeller (regresör, sınıflandırıcı)
score(X, y)Varsayılan metrik: regresyonda R², sınıflandırmada doğrulukModeller
predict_proba(X)Sınıf olasılıklarıÇoğu sınıflandırıcı
transform(X) / fit_transformVeriyi dönüştürür (ölçekleme, kodlama)Dönüştürücüler (transformer)

Öğrenilen her şey alt çizgiyle biten özniteliklerde saklanır: coef_, intercept_, classes_, feature_importances_. Alt çizgi "bu değer fit sırasında hesaplandı" demektir; fit etmeden erişirsen AttributeError ya da NotFittedError alırsın. Hiperparametreler (kullanıcının seçtiği ayarlar: n_neighbors, max_depth) ise kurucuda verilir.

İlk üç model

Doğrusal regresyon (LinearRegression)

Hedefi özelliklerin ağırlıklı toplamı olarak modeller: ŷ = b + w1·x1 + w2·x2 + .... Hızlı, yorumlanabilir, her regresyon projesinde ilk denenecek temel çizgidir (baseline).

import numpy as np
from sklearn.datasets import load_diabetes
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_squared_error, r2_score

X, y = load_diabetes(return_X_y=True)   # 442 hasta, 10 özellik, hedef: 1 yıl sonraki hastalık ilerlemesi
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

model = LinearRegression()
model.fit(X_train, y_train)
tahmin = model.predict(X_test)

print("MAE :", round(mean_absolute_error(y_test, tahmin), 1))
print("RMSE:", round(float(np.sqrt(mean_squared_error(y_test, tahmin))), 1))
print("R²  :", round(r2_score(y_test, tahmin), 3))
print("score() ile aynı mı:", round(model.score(X_test, y_test), 3))

taban = np.full_like(y_test, y_train.mean(), dtype=float)   # hep ortalamayı söyleyen model
print("Taban çizgi MAE:", round(mean_absolute_error(y_test, taban), 1))

k-en yakın komşu (KNeighborsClassifier) ve karar ağacı (DecisionTreeClassifier)

KNN yeni örneğe en yakın k eğitim örneğine bakar ve çoğunluğun sınıfını söyler; "öğrenme" aslında veriyi ezberlemektir. Karar ağacı ise veriyi "petal uzunluğu 2.45'ten küçük mü?" gibi evet/hayır sorularıyla dallara böler; kuralları insanın okuyabileceği biçimdedir.

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.neighbors import KNeighborsClassifier
from sklearn.tree import DecisionTreeClassifier, export_text

X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42, stratify=y)

knn = KNeighborsClassifier(n_neighbors=5).fit(X_train, y_train)
agac = DecisionTreeClassifier(max_depth=2, random_state=0).fit(X_train, y_train)
print("KNN doğruluk  :", round(knn.score(X_test, y_test), 3))
print("Ağaç doğruluk :", round(agac.score(X_test, y_test), 3))
print("İlk 5 tahmin  :", agac.predict(X_test[:5]), "gerçek:", y_test[:5])
print(export_text(agac, feature_names=["sepal_l", "sepal_w", "petal_l", "petal_w"]))

Metrikler: neyi ölçüyoruz?

MetrikProblemYorumNe zaman
MAE (ortalama mutlak hata)RegresyonOrtalama kaç birim yanılıyorum; hedefle aynı birim (TL, gün)İş birimine anlatmak kolay
RMSE (kök ortalama kare hata)RegresyonBüyük hataları daha çok cezalandırırBüyük sapmalar pahalıysa
R² (belirleme katsayısı)Regresyon1 mükemmel, 0 "hep ortalamayı söylemek" kadar, negatif daha kötüModeller arası karşılaştırma
Accuracy (doğruluk)SınıflandırmaDoğru tahmin oranıSınıflar dengeliyse

Bir metrik tek başına anlamsızdır; her zaman bir taban çizgiyle (baseline) karşılaştır. Regresyonda "hep eğitim ortalamasını söyle", sınıflandırmada "hep en sık sınıfı söyle" modelleri (DummyRegressor, DummyClassifier) en ucuz rakiptir. Temerrüt oranı %5 olan bir portföyde "kimse temerrüde düşmez" diyen model %95 doğruluk alır ve tamamen işe yaramaz. Dengesiz sınıflar için precision, recall ve ROC-AUC'yi bir sonraki derste göreceksin.

Aşırı ve eksik öğrenme

Eksik öğrenme (underfitting): model veriyi yakalayamayacak kadar basittir; eğitimde de testte de kötüdür. Aşırı öğrenme (overfitting): model eğitim verisindeki gürültüyü bile ezberler; eğitimde parlak, testte sönüktür. Teşhis aracın, eğitim ve test skorlarını yan yana görmektir.

from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier

# flip_y=0.15: etiketlerin %15'i rastgele bozuk (gerçek hayattaki gürültü)
X, y = make_classification(n_samples=600, n_features=8, n_informative=4, flip_y=0.15, random_state=1)
X_tr, X_te, y_tr, y_te = train_test_split(X, y, test_size=0.3, random_state=0, stratify=y)

print("derinlik  eğitim  test")
for derinlik in [1, 3, 5, 10, None]:
    m = DecisionTreeClassifier(max_depth=derinlik, random_state=0).fit(X_tr, y_tr)
    print(f"{str(derinlik):>8}  {m.score(X_tr, y_tr):.3f}  {m.score(X_te, y_te):.3f}")

Derinlik 1'de iki skor da düşük: eksik öğrenme. Derinlik sınırsızken eğitim 1.000'e çıkar ama test düşer: model gürültüyü ezberledi. Tatlı nokta ikisinin arasındadır. Bu ayarı test setine bakarak seçersen test seti artık "görülmemiş" değildir; doğru yöntem (doğrulama seti ve çapraz doğrulama (cross-validation)) ml-pipeline-degerlendirme dersinde.

Veri sızıntısı: en pahalı hata

Veri sızıntısı (data leakage), modelin eğitim sırasında tahmin anında elinde olmayacak bir bilgiyi görmesidir. Sonuç: testte muhteşem, canlıda felaket. Tipik biçimleri:

Sızıntı testiBir model "fazla iyi" görünüyorsa (sınıflandırmada %99, R² 0.99) önce sevinme, şüphelen. En önemli özelliklere bak ve her biri için "tahmin anında bu bilgi elimde olur mu?" diye sor.

ML proje akışı: CRISP-DM

Endüstride en yaygın süreç modeli CRISP-DM'dir (Cross-Industry Standard Process for Data Mining). Doğrusal değil, döngüseldir; değerlendirmede çıkan sonuç seni sık sık başa döndürür.

  1. İş anlayışı: Hangi karar iyileşecek? Başarı nasıl ölçülecek (ör. "temerrüt kayıplarını %10 azalt")?
  2. Veri anlayışı: Hangi veri var, kalitesi ne, hedef nasıl tanımlanıyor (90 gün gecikme = temerrüt)?
  3. Veri hazırlama: Temizleme, birleştirme, özellik üretme; zamanın çoğu buraya gider.
  4. Modelleme: Taban çizgi, sonra birkaç aday model.
  5. Değerlendirme: Test metrikleri ve iş metriği; sızıntı kontrolü, adalet ve açıklanabilirlik.
  6. Yayına alma (deployment): Modeli servis et, izle, performans düşerse yeniden eğit.
Gerçek işteBir bankanın kredi modelinde ilk sorulan soru "doğruluğun kaç?" değil, "neyle karşılaştırdın ve hangi tarih aralığında test ettin?" olur. Model risk ekipleri tekrarlanabilirlik ister: aynı kod, aynı random_state, aynı veri sürümüyle aynı sayılar çıkmalıdır. Bu yüzden ilk günden bölme tohumlarını sabitlemek, taban çizgiyi raporlamak ve test setini en sona saklamak profesyonel alışkanlıktır.
Uzmanlaş

Yanlılık-varyans dengesi

Bir modelin hatası kabaca üç parçaya ayrılır: yanlılık (bias; modelin varsayımları gerçeği yakalayamıyor, eksik öğrenme), varyans (variance; model eğitim verisindeki küçük değişikliklere aşırı duyarlı, aşırı öğrenme) ve indirgenemez gürültü. Model karmaşıklığını artırmak yanlılığı düşürür ama varyansı artırır. KNN'de küçük k, ağaçta büyük max_depth varyansı artırır. Daha fazla veri toplamak varyansı azaltmanın en güvenilir yoludur.

fit sonrası nesne ve zincirleme

fit nesnenin kendisini döndürdüğü için KNeighborsClassifier(3).fit(X, y).predict(X_yeni) yazılabilir. Aynı nesneyi farklı veriyle yeniden fit etmek önceki öğrenmeyi tamamen siler; iki ayrı model istiyorsan iki nesne oluştur ya da sklearn.base.clone kullan.

import numpy as np
from sklearn.base import clone
from sklearn.neighbors import KNeighborsClassifier

X = np.array([[1], [2], [3], [10], [11], [12]])
y = np.array([0, 0, 0, 1, 1, 1])
sablon = KNeighborsClassifier(n_neighbors=3)
m1 = clone(sablon).fit(X, y)
m2 = clone(sablon).fit(X[:4], y[:4])
print(m1.predict([[9]]), m2.predict([[9]]))
print(sablon.get_params()["n_neighbors"], hasattr(sablon, "classes_"))

Tekrarlanabilirlik kontrol listesi

Bölmede, sentetik veride ve rastgelelik içeren her modelde (DecisionTreeClassifier, RandomForestClassifier) random_state ver; kütüphane sürümlerini requirements.txt ile sabitle; veri kesim tarihini kaydet. Aynı sayıyı yarın yeniden üretemiyorsan modeli savunamazsın.

Alıştırmalara geç (18)