Bölüm 3 · Klasik algoritmalar · Ders 13
Naive Bayes ile spam süzgeci
Kelime saymak, +1 eklemek ve puanları toplamak: gelen kutusunu koruyan algoritma
Veri. Robot atölyesinin ortak e-posta kutusu: 400 e-posta, yarısı spam. Aralarında zor olanlar da var: iş yazışması gibi görünen spam ('yarın toplantı notları için hemen tıkla') ve üye olunan mağazanın bülteni. Süzgeç yalnızca ilk 300 e-postanın etiketini görür; kalan 100 e-postayla sınanır.
import mathfrom collections import Counterimport numpy as npD = np.genfromtxt('spam-epostalar.csv', delimiter=',', names=True, dtype=None, encoding='utf-8') # 400 e-postaposta = [(m.split(), s == 1) for m, s in zip(D['metin'], D['spam'])] # (kelimeler, spam_mi) çiftleriegitim, test = posta[:300], posta[300:] # ilk 300 eğitim, son 100 testsayac = {True: Counter(), False: Counter()}for kelimeler, spam in egitim:sayac[spam].update(kelimeler) # her kelimeyi saysozluk = set(sayac[True]) | set(sayac[False])toplam = {s: sum(c.values()) + len(sozluk) for s, c in sayac.items()} # +1 eklemedef puan(k):return math.log((sayac[True][k] + 1) / toplam[True]) - math.log((sayac[False][k] + 1) / toplam[False]) # kelimenin spam puanıdef spam_mi(kelimeler, esik=0.0):return sum(puan(k) for k in kelimeler if k in sozluk) > esik # eşiğin üstü spamdogru = sum(spam_mi(k) == s for k, s in test)print(dogru, "/", len(test))history = {'n_train': [], 'train_acc': [], 'test_acc': []} # öğrenme eğrisi: 50, 100, … 300 e-postafor n in range(50, 301, 50):sayac = {True: Counter(), False: Counter()} # yalnız ilk n e-postayla yeniden sayfor kelimeler, spam in egitim[:n]: sayac[spam].update(kelimeler)sozluk = set(sayac[True]) | set(sayac[False])toplam = {s: sum(c.values()) + len(sozluk) for s, c in sayac.items()}basari = lambda kume: sum(spam_mi(k) == s for k, s in kume) / len(kume)for k, v in zip(history, (n, basari(egitim[:n]), basari(test))): history[k].append(float(v)) # son turda n = 300: tam modelskor = [sum(puan(k) for k in kel if k in sozluk) for kel, _ in test] # e-posta puanları (ROC için)tp = sum(p > 0 and s for p, (_, s) in zip(skor, test)); fp = sum(p > 0 and not s for p, (_, s) in zip(skor, test))fn = sum(p <= 0 and s for p, (_, s) in zip(skor, test))for k, v in [('test_acc', history['test_acc'][-1]), ('precision', tp / max(tp + fp, 1)), ('recall', tp / max(tp + fn, 1))]: # son ölçümler tablosuprint(f'{k:<10}{v:>10.4f}')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 eğitim büyüklüğütry:import matplotlib.pyplot as plt # varsa grafik çizfor k in ('train_acc', 'test_acc'): plt.plot(history['n_train'], history[k], marker='o', label=k)plt.xlabel('n_train'); 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 →- Spam e-postalarVeri 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
- Süzgeç eğitim e-postalarındaki her kelimenin spam’de ve normal postada kaç kez geçtiğini sayar. Eğitimin tamamı budur.
- Her sayıya 1 eklenir (Laplace düzeltmesi): bir kelime spam’de hiç görülmediyse bile olasılığı sıfır olmaz ve tek bir kelime kararı kilitleyemez.
- Kelimenin puanı iki oranın logaritmasıdır: log P(kelime | spam) − log P(kelime | normal). Sıfırın üstü spam’e, altı normale işaret eder.
- “Naive” varsayım: kelimeler birbirinden bağımsız sayılır, bu yüzden e-postanın puanı kelime puanlarının toplamıdır. Süzgeç cümleyi anlamaz; kılık değiştirmiş spam bu yüzden bazen kaçar.
- Şunu dene: spam eşiğini −4’e indir. Kılık değiştirmiş spam’in çoğu yakalanır ama bu kez mağaza bültenlerinin hepsi spam kutusuna düşer. Eşiği +2’ye çıkar: bültenler kurtulur, kılık değiştirmiş spam hep kaçar. Hiçbir eşik ikisini birden çözmez; süzgeç cümleyi değil kelimeyi görür.
Neden önemli
İlk ciddi spam süzgeçleri tam olarak bu birkaç satırdı ve bugün de metin sınıflandırmada ilk denenen yöntemdir: eğitimi bir sayım, tahmini bir toplamdır, binlerce kelimeyle bile anında çalışır. Aynı kod robotun hata günlüklerini “donanım / yazılım / ağ” diye ayırmak ya da kullanıcı komutlarını sınıflandırmak için de kullanılır. Sensör verisiyle çalışan Gauss sürümü bir önceki derste.
ESOF 323, 11. hafta: robotlarda derin öğrenme →