Bölüm 3 · Klasik algoritmalar · Ders 14
Karar ağacı
Çizgi izleyen robotun kararını evet/hayır sorularına bölmek
Veri. Bir uzman, çizgi izleyen robotu elle sürerken 160 an kaydettik: sol ve sağ çizgi sensörünün okuması (0–1023) ve o an seçtiği eylem: sola, düz ya da sağa. Çizgi koyu; sensör koyu yüzeyde büyük değer okur. Robot aynı kararları kendisi versin istiyoruz, ama okunabilir kurallarla.
import numpy as npD = np.genfromtxt('cizgi-izleyen.csv', delimiter=',', names=True) # 160 eğitim, 80 test anıA, e, tr = np.c_[D['sol'], D['sag']], D['eylem'].astype(int), D['grup'] == 0 # [sol, sağ], 0 sola 1 düz 2 sağaX, y, X_test, y_test = A[tr], e[tr], A[~tr], e[~tr]def gini(y): p = np.bincount(y, minlength=3) / max(len(y), 1); return 1 - (p ** 2).sum()def best_split(X, y):best = (gini(y), None, None)for f in range(2): # her sensörfor t in np.unique(X[:, f]): # her eşikL = X[:, f] <= tg = (L.sum() * gini(y[L]) + (~L).sum() * gini(y[~L])) / len(y) # bölmeden sonraki safsızlıkif 0 < L.sum() < len(y) and g < best[0]: best = (g, f, t)return bestdef grow(X, y, depth):g, f, t = best_split(X, y)if depth == 0 or f is None: return np.bincount(y).argmax() # yaprak: çoğunlukL = X[:, f] <= treturn (f, t, grow(X[L], y[L], depth - 1), grow(X[~L], y[~L], depth - 1))tree = grow(X, y, depth=3)def predict(t, x):while isinstance(t, tuple): t = t[2] if x[t[0]] <= t[1] else t[3] # evet: sol dal, hayır: sağ dalreturn tacc = lambda X, y: np.mean([predict(tree, x) == c for x, c in zip(X, y)])print(acc(X, y), acc(X_test, y_test)) # eğitim ve saklı veride doğrulukn_leaves = lambda t: n_leaves(t[2]) + n_leaves(t[3]) if isinstance(t, tuple) else 1history = {'depth': [], 'train_acc': [], 'test_acc': [], 'leaves': []} # derinliğe göre geçmişfor d in range(1, 11):tree = grow(X, y, d) # aynı veriyle daha derin ağaçfor k, v in zip(history, (d, acc(X, y), acc(X_test, y_test), n_leaves(tree))): history[k].append(float(v))tree = grow(X, y, depth=3)p = np.array([predict(tree, x) for x in X_test])M = np.zeros((3, 3), int); np.add.at(M, (y_test, p), 1) # karışıklık matrisi: satır gerçek, sütun tahminprint(M)prec, rec = np.diag(M) / np.maximum(M.sum(0), 1), np.diag(M) / np.maximum(M.sum(1), 1)f1 = 2 * prec * rec / np.maximum(prec + rec, 1e-12)for k, v in [('test_accuracy', np.trace(M) / M.sum()), ('precision_m', prec.mean()), ('recall_m', rec.mean()), ('f1_m', f1.mean())]: # son ölçümler tablosuprint(f'{k:<14}{v:>8.3f}')import csvwith open('egitim_gecmisi.csv', 'w', newline='') as f: # geçmişi CSV'ye yazcsv.writer(f).writerows([list(history), *zip(*history.values())]) # satır başına bir derinliktry:import matplotlib.pyplot as plt # varsa grafik çizfor k in ('train_acc', 'test_acc'): plt.plot(history['depth'], history[k], 'o-', label=k)plt.xlabel('depth'); plt.ylabel('accuracy'); plt.legend(); plt.show()except ImportError:print('matplotlib yok: grafik atlandı')
Eğitim paneli
Eğitim çalıştırılıyor…
Sahnedeki her sayı, aynı algoritmanın tarayıcında yapılan gerçek çalıştırmasından gelir (sabit tohum, her seferinde aynı sonuç). Python kodunu kendi bilgisayarında çalıştırırsan rastgele başlangıçlar farklı olacağı için sayılar biraz değişebilir.
Veri seti
Tüm veri setleri →- Çizgi izleyen robot: uzman sürüşüVeri setini indir
- Kredi başvurularıalıştırmaVeri setini indir
Kodu tarayıcıda çalıştırPython · NumPy · matplotlib · Pyodide
Python ve NumPy bu sayfada, tarayıcında çalışır (Pyodide). Kodu değiştirip yeniden çalıştırabilirsin; dersin veri setleri çalışma klasöründe hazır. Kod matplotlib kullanırsa grafikler çıktının altında görünür, yazdığı dosyalar (ör. egitim_gecmisi.csv) indirilebilir.
Çıktı
Çıktı burada görünecek.Nasıl çalışır
- Gini safsızlığı, bir kutudaki eylemlerin ne kadar karışık olduğunu ölçer: tek eylem varsa 0.
- Her düğümde iki sensörün de bütün eşikleri denenir; safsızlığı en çok azaltan tek soru seçilir ("sol ≤ 612 mi?").
- İki yarıya aynı işlem uygulanır, derinlik sınırına kadar. Yapraklar çoğunluk eylemini verir.
- Derinlik 1 kaba kalır; 2–3 kuralı bulur ve son karede kurallar Arduino’ya aktarılacak if-else satırları olarak yazılır.
- İkinci veri kümesi bir banka: 500 müşterinin aylık geliri, kaçırdığı ödeme sayısı ve krediyi ödeyip ödemediği (400’ü eğitim, 100’ü yeni müşteri). Arkadaki kural “gelir 3.000’in üstünde ve en fazla 1 kaçan ödeme, ya da gelir 5.000’in üstünde”; müşterilerin %12’si sürpriz yapar. Veriyi 1 yap: derinlik 3’te ağaç kuralı neredeyse aynen bulur ve her reddi tek satırla açıklar.
- Şunu dene: derinliği 3’ten 10’a çıkar. Eğitim verisinde doğruluk %100’e çıkar, saklı veride ise derinlik 4’ten sonra hiç kıpırdamaz: fazladan yapraklar yalnızca uzmanın yanlış etiketlerini ezberler. Aradaki fark ezberin ölçüsüdür (aşırı öğrenme dersindeki durumun aynısı) ve 21 yapraklı ağacın kuralları artık okunamaz.
- Aynısını kredi verisinde dene: derinliği 3’ten 10’a çıkar. Eski müşterilerde doğruluk %89’dan %95’e çıkar, yeni müşterilerde %85’ten %77’ye düşer ve yaprak sayısı 8’den 60’a fırlar. Ağaç sürprizleri kural sanıp ezberlemiştir.
Neden önemli
Karar ağacının kuralları okunabilir ve doğrudan bir Arduino if-else zincirine çevrilebilir. Kararın gerekçesinin gösterilmesi gereken her yerde bu yüzden tercih edilir: bir banka krediyi neden reddettiğini (“gelir ≤ 3.000 ve kaçırılan ödeme > 1”) müşteriye açıklayabilmelidir. Yüzlerce ağaç birleşince (rastgele orman, gradyan artırma) tablo verisinde bugün de en güçlü yöntemler arasındadır.
ESOF 323, 11. hafta: robotlarda derin öğrenme →