學習筆記26— roc曲線(python)


一、概念:

准確率(Accuracy), 精確率(Precision), 召回率(Recall)和F1-Measure

機器學習(ML), 自然語言處理(NLP), 信息檢索(IR)等領域, 評估(Evaluation)是一個必要的工作, 而其評價指標往往有如下幾點: 准確率(Accuracy), 精確率(Precision), 召回率(Recall) 和 F1-Measure.(注:相對來說,IR 的 ground truth 很多時候是一個 Ordered List, 而不是一個 Bool 類型的 Unordered Collection,在都找到的情況下,排在第三名還是第四名損失並不是很大,而排在第一名和第一百名,雖然都是“找到了”,但是意義是不一樣的,因此更多可能適用於 MAP 之類評估指標.)

本文將簡單介紹其中幾個概念. 中文中這幾個評價指標翻譯各有不同, 所以一般情況下推薦使用英文.

現在我先假定一個具體場景作為例子.

假如某個班級有男生 80 人, 女生20人, 共計 100 人. 目標是找出所有女生. 現在某人挑選出 50 個人, 其中 20 人是女生, 另外還錯誤的把 30 個男生也當作女生挑選出來了. 作為評估者的你需要來評估(evaluation)下他的工作

首先我們可以計算准確率(accuracy), 其定義是: 對於給定的測試數據集,分類器正確分類的樣本數與總樣本數之比. 也就是損失函數是0-1損失時測試數據集上的准確率[1].

這樣說聽起來有點抽象,簡單說就是,前面的場景中,實際情況是那個班級有男的和女的兩類,某人(也就是定義中所說的分類器)他又把班級中的人分為男女兩類. accuracy 需要得到的是此君分正確的人總人數的比例. 很容易,我們可以得到:他把其中70(20女+50男)人判定正確了, 而總人數是100人,所以它的 accuracy 就是70 %(70 / 100).

由准確率,我們的確可以在一些場合,從某種意義上得到一個分類器是否有效,但它並不總是能有效的評價一個分類器的工作. 舉個例子, google 抓取了 argcv 100個頁面,而它索引中共有10,000,000個頁面, 隨機抽一個頁面,分類下, 這是不是 argcv 的頁面呢?如果以 accuracy 來判斷我的工作,那我會把所有的頁面都判斷為"不是 argcv 的頁面", 因為我這樣效率非常高(return false, 一句話), 而 accuracy 已經到了99.999%(9,999,900/10,000,000), 完爆其它很多分類器辛辛苦苦算的值, 而我這個算法顯然不是需求期待的, 那怎么解決呢?這就是 precision, recall 和 f1-measure 出場的時間了.

再說 precision, recall 和 f1-measure 之前, 我們需要先需要定義 TP, FN, FP, TN 四種分類情況.

按照前面例子, 我們需要從一個班級中的人中尋找所有女生, 如果把這個任務當成一個分類器的話, 那么女生就是我們需要的, 而男生不是, 所以我們稱女生為"正類", 而男生為"負類".

  相關(Relevant), 正類 無關(NonRelevant), 負類
被檢索到(Retrieved) true positives (TP 正類判定為正類, 例子中就是正確的判定"這位是女生") false positives (FP 負類判定為正類,"存偽", 例子中就是分明是男生卻判斷為女生, 當下偽娘橫行, 這個錯常有人犯)
未被檢索到(Not Retrieved) false negatives (FN 正類判定為負類,"去真", 例子中就是, 分明是女生, 這哥們卻判斷為男生--梁山伯同學犯的錯就是這個) true negatives (TN 負類判定為負類, 也就是一個男生被判斷為男生, 像我這樣的純爺們一准兒就會在此處)

或者

 

可以很容易看出, 所謂 TRUE/FALSE 表示從結果是否分對了, Positive/Negative 表示我們認為的是"是"還是"不是".

通過這張表, 我們可以很容易得到這幾個值:

  • TP=20
  • FP=30
  • FN=0
  • TN=50

精確率(precision)的公式是P=TPTP+FPP = \frac{TP}{TP+FP}P=TP+FPTP, 它計算的是所有"正確被檢索的結果(TP)"占所有"實際被檢索到的(TP+FP)"的比例.

在例子中就是希望知道此君得到的所有人中, 正確的人(也就是女生)占有的比例. 所以其 precision 也就是40%(20女生/(20女生+30誤判為女生的男生)).

召回率(recall)的公式是R=TPTP+FNR = \frac{TP}{TP+FN}R=TP+FNTP, 它計算的是所有"正確被檢索的結果(TP)"占所有"應該檢索到的結果(TP+FN)"的比例.

在例子中就是希望知道此君得到的女生占本班中所有女生的比例, 所以其 recall 也就是100%(20女生/(20女生+ 0 誤判為男生的女生))

F1值就是精確值和召回率的調和均值, 也就是

2F1=1P+1R\frac{2}{F_1} = \frac{1}{P} + \frac{1}{R} F12=P1+R1

調整下也就是

F1=2PRP+R=2TP2TP+FP+FNF_1 = \frac{2PR}{P+R} = \frac{2TP}{2TP + FP + FN} F1=P+R2PR=2TP+FP+FN2TP

例子中 F1-measure 也就是約為 57.143%(2∗0.4∗10.4+1\frac{2 * 0.4 * 1}{0.4 + 1}0.4+120.41).

需要說明的是, 有人[3]列了這樣個公式, 對非負實數β\betaβ

Fβ=(β2+1)∗PRβ2∗P+RF_\beta = (\beta^2 + 1) * \frac{PR}{\beta^2*P+R}Fβ=(β2+1)β2P+RPR

將 F-measure 一般化.

F1-measure 認為精確率和召回率的權重是一樣的, 但有些場景下, 我們可能認為精確率會更加重要, 調整參數 β\betaβ , 使用 Fβ_\betaβ-measure 可以幫助我們更好的 evaluate 結果.

 

注意:召回率就是tpr(TP/(TP+FN)) (命中率),fpr(FP/(FP+TN)):特異性(specificity),TNR(TN/(FP+TN)):敏感性

 

參考鏈接:http://mlwiki.org/index.php/ROC_Analysis#ROC_Analysis

                 https://blog.argcv.com/articles/1036.c

                http://www.cnblogs.com/pinard/p/5993450.html

 

 

1、簡單(源碼):

print(__doc__)

import numpy as np
import matplotlib.pyplot as plt
from itertools import cycle


from sklearn import svm, datasets
from sklearn.metrics import roc_curve, auc
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import label_binarize
from sklearn.multiclass import OneVsRestClassifier
from scipy import interp

# Import some data to play with
iris = datasets.load_iris()
X = iris.data
y = iris.target

# Binarize the output
y = label_binarize(y, classes=[0, 1, 2])
n_classes = y.shape[1]

# Add noisy features to make the problem harder
random_state = np.random.RandomState(0)
n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 200 * n_features)]

# shuffle and split training and test sets
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.5,
                                                    random_state=0)

# Learn to predict each class against the other
classifier = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True,
                                 random_state=random_state))
y_score = classifier.fit(X_train, y_train).decision_function(X_test)

# Compute ROC curve and ROC area for each class
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
    fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
    roc_auc[i] = auc(fpr[i], tpr[i])

# Compute micro-average ROC curve and ROC area
fpr["micro"], tpr["micro"], _ = roc_curve(y_test.ravel(), y_score.ravel())
roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])

#Plot of a ROC curve for a specific class

plt.figure()
lw = 2
plt.plot(fpr[2], tpr[2], color='darkorange',
         lw=lw, label='ROC curve (area = %0.2f)' % roc_auc[2])
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlim([0.0, 1.0])
plt.ylim([0.0, 1.05])
plt.xlabel('False Positive Rate')
plt.ylabel('True Positive Rate')
plt.title('Receiver operating characteristic example')
plt.legend(loc="lower right")
plt.show()
2、復雜(源碼):

print(__doc__) import numpy as np from scipy import interp import matplotlib.pyplot as plt from itertools import cycle from sklearn import svm, datasets from sklearn.metrics import roc_curve, auc from sklearn.model_selection import StratifiedKFold # ############################################################################# # Data IO and generation # Import some data to play with iris = datasets.load_iris() X = iris.data y = iris.target X, y = X[y != 2], y[y != 2] n_samples, n_features = X.shape # Add noisy features random_state = np.random.RandomState(0) X = np.c_[X, random_state.randn(n_samples, 200 * n_features)] # ############################################################################# # Classification and ROC analysis # Run classifier with cross-validation and plot ROC curves cv = StratifiedKFold(n_splits=6) classifier = svm.SVC(kernel='linear', probability=True, random_state=random_state) tprs = [] aucs = [] mean_fpr = np.linspace(0, 1, 100) i = 0 for train, test in cv.split(X, y): probas_ = classifier.fit(X[train], y[train]).predict_proba(X[test]) # Compute ROC curve and area the curve fpr, tpr, thresholds = roc_curve(y[test], probas_[:, 1]) tprs.append(interp(mean_fpr, fpr, tpr)) tprs[-1][0] = 0.0 roc_auc = auc(fpr, tpr) aucs.append(roc_auc) plt.plot(fpr, tpr, lw=1, alpha=0.3, label='ROC fold %d (AUC = %0.2f)' % (i, roc_auc)) i += 1 plt.plot([0, 1], [0, 1], linestyle='--', lw=2, color='r', label='Chance', alpha=.8) mean_tpr = np.mean(tprs, axis=0) mean_tpr[-1] = 1.0 mean_auc = auc(mean_fpr, mean_tpr) std_auc = np.std(aucs) plt.plot(mean_fpr, mean_tpr, color='b', label=r'Mean ROC (AUC = %0.2f $\pm$ %0.2f)' % (mean_auc, std_auc), lw=2, alpha=.8) std_tpr = np.std(tprs, axis=0) tprs_upper = np.minimum(mean_tpr + std_tpr, 1) tprs_lower = np.maximum(mean_tpr - std_tpr, 0) plt.fill_between(mean_fpr, tprs_lower, tprs_upper, color='grey', alpha=.2, label=r'$\pm$ 1 std. dev.') plt.xlim([-0.05, 1.05]) plt.ylim([-0.05, 1.05]) plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title('Receiver operating characteristic example') plt.legend(loc="lower right") plt.show()

Best threshold:

    • we know the slope of the accuracy line: it's 1
    • the best classifier for this slope is the 6th one
    • roc-curve-ex1.png
    • threshold value θ
    • so we take the score obtained on the 6th record
    • and use it as the threshold value θ
  • i.e. predict positive if θ0.54
  • if we check, we see that indeed we have accuracy = 0.7
 
       


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM