Sıradaki

Kesinlik ve duyarlılık

Zorluk: Orta

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_hat 1 ve y 1.
  • yanlış pozitif (false positive, FP): y_hat 1 ama y 0.
  • yanlış negatif (false negative, FN): y_hat 0 ama y 1.

Sonra iki oranı hesapla:

precision=TPTP+FP,recall=TPTP+FN\text{precision} = \frac{TP}{TP + FP}, \qquad \text{recall} = \frac{TP}{TP + FN}

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 0/00 / 0 olur.
  • Veride hiç gerçek pozitif yoksa recall 0/00 / 0 olur.

İkisi de tanımsızdır. Bu durumda ilgili değeri 00 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:

  1. True/False değerlerinden oluşan bir array kur.
  2. 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 > 0 ise tp / (tp + fp) hesapla, değilse 0.0 kullan.
  • 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

  • y ve y_hat aynı (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.float64 değerleri de kabul edilir. float(...) ile çevirmek zorunda değilsin.
  • Payda sıfırsa o değer 0.0 olur: hiç pozitif tahmin yoksa precision, hiç gerçek pozitif yoksa recall. nan ya da hata döndürme.
  • y’yi ve y_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 =0= 0 olduğu için recall 00‘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 =1= 1). Ama pozitif dediklerinin çoğu yanlıştır: aynı veride precision yalnızca 0,020{,}02 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 2×22 \times 2‘lik tabloya karışıklık matrisi (confusion matrix) denir. Tablo şöyle görünür:

Tahmin 1Tahmin 0
Gerçek 1TPFN
Gerçek 0FPTN

Precision ve recall bu tablodan okunur.

Daha fazlası için Lojistik regresyon dersine bak.

Çözüm üç adımdır:

  1. Boolean koşullarla TP, FP ve FN’yi say.
  2. Paydası sıfır olmayan oranları hesapla.
  3. İ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 (TP+FPTP + FP). Recall’un paydası gerçek pozitiflerdir (TP+FNTP + FN).

Bir diğer hata sıfıra bölmedir. Hiç pozitif tahmin etmeyen bir modelde tp / (tp + fp) şunu verir:

  • np.int64 değerleriyle nan.
  • Python tam sayılarıyla ZeroDivisionError.

Bölmeden önce paydayı kontrol et.

Bu problemde bir sorun mu var?

solution.py
import numpy as npdef precision_recall(y: np.ndarray, y_hat: np.ndarray) -> tuple[float, float]:    """Gerçek ve tahmin edilen etiketlerden kesinliği ve duyarlılığı bir demet olarak döndürür."""    # Kodunu buraya yaz.    return 0.0, 0.0

İçindekiler

Geri bildirim

Tür