Kesinlik ve duyarlılık
Zorluk: Orta Çözüldümetrikler
Doğruluk (accuracy), sınıflar dengesizken yanıltır. Doğruluk, bir modelin kaç tahminini (prediction) doğru yaptığını sayar. Örneklerin (sample) %98’i negatifse, her örneğe “negatif” diyen bir model %98 accuracy’ye ulaşır.
Böyle bir model tek bir pozitifi bile bulamaz. Bu yüzden iki ayrı oran kullanırsın:
- Kesinlik (precision): modelin pozitif dediklerinin ne kadarı gerçekten pozitiftir.
- Duyarlılık (recall): gerçek pozitiflerin ne kadarını model bulmuştur.
precision_recall(y, y_hat) fonksiyonunu yaz. Girdiler şunlardır:
y: gerçek etiketler (label).y_hat: modelin tahmin ettiği label’lar.
İkisi de şekli (shape) (n,) olan, 0 ve 1’lerden oluşan birer tam sayı dizisidir (array). 1 pozitif sınıftır. Önce üç sayıyı say:
- doğru pozitif (true positive, TP):
y_hat1 vey1. - yanlış pozitif (false positive, FP):
y_hat1 amay0. - yanlış negatif (false negative, FN):
y_hat0 amay1.
Sonra iki oranı hesapla:
Paydalar şöyledir:
- Precision’ın paydası, modelin pozitif dediği örneklerin sayısıdır.
- Recall’un paydası, gerçek pozitiflerin sayısıdır.
(precision, recall) çiftini bir demet (tuple) olarak döndür.
Payda sıfır olabilir:
- Model hiç pozitif tahmin etmediyse precision olur.
- Veride hiç gerçek pozitif yoksa recall olur.
İkisi de tanımsızdır. Bu durumda ilgili değeri say ve 0.0 döndür.
Örnekler
Girdi: y = [1, 1, 1, 1, 0, 0, 0, 0], y_hat = [1, 1, 1, 0, 1, 1, 0, 0]
Çıktı: (0.6, 0.75)
Girdi: y = [1, 0, 1, 0, 0], y_hat = [0, 0, 0, 0, 0]
Çıktı: (0.0, 0.0)
Girdi: y = [1, 0, 0, 0, 1, 0], y_hat = [1, 1, 1, 1, 1, 1]
Çıktı: (0.3333333333333333, 1.0)
İpucu 1
TP, FP ve FN’nin her biri bir koşula uyan örneklerin sayısıdır. Her koşul için şunları yap:
True/Falsedeğerlerinden oluşan bir array kur.True’ları say.
İpucu 2
NumPy’da &, iki boolean array’in eleman bazında (element-wise) “ve”sidir. (y_hat == 1) & (y == 1) doğru pozitif olan örneklerde True verir. Parantezleri unutma.
np.sum True’ları sayar. FP ve FN için koşulları buna göre değiştir.
İpucu 3
Paydayı kontrol et:
tp + fp > 0isetp / (tp + fp)hesapla, değilse0.0kullan.- Aynı kontrolü recall’un paydası için ayrıca yap.
Sonuçları float(...) ile Python float’una çevir ve bir tuple olarak döndür.
Gereksinimler
yvey_hataynı(n,)shape’inde, yalnızca 0 ve 1 içeren tam sayı array’leridir. En az bir örnek içerirler.- Dönüş değeri
(float, float)biçiminde bir tuple: önce precision, sonra recall. np.float64değerleri de kabul edilir.float(...)ile çevirmek zorunda değilsin.- Payda sıfırsa o değer
0.0olur: hiç pozitif tahmin yoksa precision, hiç gerçek pozitif yoksa recall.nanya da hata döndürme. y’yi vey_hat’ı değiştirme. Fonksiyon bittiğinde onu çağıran kodun array’leri aynı kalmalı.
Accuracy, sınıflar dengesizken yanıltır. 100 örnekten yalnızca 2’si pozitif olsun ve model her örneğe 0 desin:
- Accuracy %98’dir.
- TP olduğu için recall ‘dır.
Precision ile recall bu açığı gösterir.
Precision ile recall arasında bir denge vardır:
- Model her örneğe 1 derse hiçbir pozitifi kaçırmaz (recall ). Ama pozitif dediklerinin çoğu yanlıştır: aynı veride precision yalnızca olur.
- Modelin eşiğini (threshold) yükseltirsen model daha seçici olur. Precision genellikle artar, recall düşer.
Hangisinin önemli olduğu uygulamaya bağlıdır:
- Bir spam filtresinde önemli bir e-postayı silmek (FP) pahalıdır.
- Bir hastalık taramasında hastayı kaçırmak (FN) pahalıdır.
TP, FP, FN ve doğru negatiflerin (TN) oluşturduğu ‘lik tabloya karışıklık matrisi (confusion matrix) denir. Tablo şöyle görünür:
| Tahmin 1 | Tahmin 0 | |
|---|---|---|
| Gerçek 1 | TP | FN |
| Gerçek 0 | FP | TN |
Precision ve recall bu tablodan okunur.
Daha fazlası için Lojistik regresyon dersine bak.
Çözüm üç adımdır:
- Boolean koşullarla TP, FP ve FN’yi say.
- Paydası sıfır olmayan oranları hesapla.
- İkisini bir tuple olarak döndür.
Kodda bu adımlar şöyle görünür:
import numpy as npdef precision_recall(y: np.ndarray, y_hat: np.ndarray) -> tuple[float, float]: tp = np.sum((y_hat == 1) & (y == 1)) fp = np.sum((y_hat == 1) & (y == 0)) fn = np.sum((y_hat == 0) & (y == 1)) precision = tp / (tp + fp) if tp + fp > 0 else 0.0 recall = tp / (tp + fn) if tp + fn > 0 else 0.0 return float(precision), float(recall)
Sık yapılan hata, paydaları karıştırmaktır. Precision’ın paydası modelin pozitif dediği örneklerdir (). Recall’un paydası gerçek pozitiflerdir ().
Bir diğer hata sıfıra bölmedir. Hiç pozitif tahmin etmeyen bir modelde tp / (tp + fp) şunu verir:
np.int64değerleriylenan.- Python tam sayılarıyla
ZeroDivisionError.
Bölmeden önce paydayı kontrol et.
Bu problemde bir sorun mu var?