1. 程式人生 > >二分類模型AUC評價法

二分類模型AUC評價法

對於二分類模型,其實既可以構建分類器,也可以構建迴歸(比如同一個二分類問題既可以用SVC又可以SVR,python的sklearn中SVC和SVR是分開的,R的e1701中都在svm中,僅當y變數是factor型別時構建SVC,否則構建SVR)。

二分類模型的評價指標很多,這裡僅敘述AUC這個指標。AUC的具體原理此處不再敘述,可以參考相關資料,比如這個還行:ROC和AUC介紹以及如何計算AUC

若構建regression,可以直接將predict的值和真實值直接扔進auc函式裡去計算,就是讓程式去逐個找predict的cutoff值就可以構建ROC了。

但是如果是classifier,因為直接predict的值是0或1,無法計算auc,此時需要藉助於“預測概率”,sklearn中常呼叫predict_proba函式來獲取。另外,Logistics迴歸,python的predict也是0或1,也需要呼叫predict_proba函式來獲取相應“預測概率”。還有個decision_function,其意義是當這個值大於0時,相應的樣本預測為正例。R中不會有這些問題,R都是簡單易用的。

AUC的計算舉例:

test_auc = metrics.roc_auc_score(y_test,y_test_pre)

ROC的計算舉例:
 

fpr, tpr, thresholds = metrics.roc_curve(y_test,y_test_pre)
plt.plot(fpr, tpr, 'b', label='AUC = %0.2f' % test_auc)

 

Classifier的其他相關評價指標

準確度accuracy:可以用classifier.score計算accuracy。理解為正確率,就是分類正確的佔總數的比例,即(TP+TN)/Total。

二分類問題中,當其中某一類數量遠小於另一類時,如果追求準確度,那麼只需要將分類結果全指定為數量多的那類即可。所以這種情況下僅用accuracy評價是不夠的。

精確度precision:又叫“查準率”、用P表示。這是針對其中一類而言。比如我建模的目的是找出正例,那麼precision就是真正的正例/找出來的所有,即TP/(TP+FP)。

召回率recall:又叫“查全率”、“靈敏度”、“真陽性率TPR”,用R表示。也是針對其中一類而言。比如建模的目的是找出正例,那麼recall就是真正的正例/所有的正例,即TP/(TP+FN)。另,假陰性率FNR(漏診率)=FN/(TP+FN),FNR=1-R。

真陰性率TNR:又叫“特異度”,TNR=TN/(TN+FP)。假陽性率FPR:又叫“誤診率”。TNR+FPR=1。(還記得ROC的橫座標嗎)

總而言之,準確率就是找得對,召回率就是找得全。

你問問一個模型,這堆東西是不是某個類的時候,準確率就是 它說是,這東西就確實是的概率吧,召回率就是, 它說是,但它漏說了(1-召回率)這麼多

F1值:是精確值和召回率的調和均值,即 2/F1=1/precision+1/recall。Fβ是更一般的形式,對precision和recall加權。而F1是其特殊情況,認為precision和recall同等重要。推廣的話還有macro-P、macro-R、macro-F1及micro-P、micro-R、micro-F1等。

貼張圖(來自:機器學習】分類效能度量指標 : ROC曲線、AUC值、正確率、召回率、敏感度、特異度

另外wiki上也有張圖:

準確率和召回率是互相影響的,理想情況下肯定是做到兩者都高,但是一般情況下準確率高、召回率就低,召回率低、準確率高,當然如果兩者都低,那是什麼地方出問題了

如果是做搜尋,那就是保證召回的情況下提升準確率;如果做疾病監測、反垃圾,則是保準確率的條件下,提升召回。

所以,在兩者都要求高的情況下,可以用F1來衡量。

P/R和ROC是兩個不同的評價指標和計算方式,一般情況下,檢索用前者,分類、識別等用後者。

參考一篇還不錯的部落格:【機器學習】分類效能度量指標 : ROC曲線、AUC值、正確率、召回率、敏感度、特異度

 

貼幾段程式碼

# SVR與SVC的AUC/ROC計算
import numpy as np
from sklearn.svm import SVR,SVC
from sklearn.model_selection import train_test_split
from sklearn import metrics

x_train, x_test, y_train, y_test = train_test_split(X, Y,  train_size=0.7)

print("------------------------------ SVC ------------------------------------------")
clf = SVC(kernel='rbf', C=100, gamma=0.0001, probability=True)
clf.fit(x_train, y_train)

y_train_pre = clf.predict(x_train)
y_test_pre = clf.predict(x_test)
print("Accuracy: "+str(clf.score(x_train,y_train)))  

y_train_predict_proba = clf.predict_proba(x_train) #每一類的概率
false_positive_rate, recall, thresholds = roc_curve(y_train, y_train_predict_proba[:, 1])
train_auc=auc(false_positive_rate,recall)
print("train AUC: "+str(train_auc))

print("------------------------------------")
print("Accuracy: "+str(clf.score(x_test,y_test)))

y_test_predict_proba = clf.predict_proba(x_test) #每一類的概率
false_positive_rate, recall, thresholds = roc_curve(y_test, y_test_predict_proba[:, 1])
test_auc=auc(false_positive_rate,recall)
print("test AUC: "+str(test_auc))

plt.figure(0)
plt.title('ROC of SVM in test data')
plt.plot(false_positive_rate, recall, 'b', label='AUC = %0.2f' % test_auc)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.xlim([0.0,1.0])
plt.ylim([0.0,1.0])
plt.ylabel('Recall')
plt.xlabel('Fall-out')
plt.show()

print("--------------------------- SVR ------------------------------------------")

reg = SVR(kernel='rbf', C=100, gamma=0.0001)
reg.fit(x_train, y_train)
y_train_pre = reg.predict(x_train)
y_test_pre = reg.predict(x_test)
train_auc = metrics.roc_auc_score(y_train,y_train_pre)
print("train AUC: "+str(train_auc))

print("--------------------------------")

test_auc = metrics.roc_auc_score(y_test,y_test_pre)
print("test AUC: "+str(test_auc))
fpr, tpr, thresholds = metrics.roc_curve(y_test,y_test_pre)

plt.figure(1)
plt.title('ROC of SVR in test data')
plt.plot(fpr, tpr, 'b', label='AUC = %0.2f' % test_auc)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.xlim([0.0,1.0])
plt.ylim([0.0,1.0])
plt.ylabel('Recall')
plt.xlabel('Fall-out')
plt.show()

Logistics迴歸程式碼段

# Logistics regression
from sklearn.datasets import load_iris
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_curve,auc
from sklearn.model_selection import train_test_split

# input X、y

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3) 
# clf = LogisticRegression(random_state=0, solver='lbfgs' ,multi_class='multinomial')
clf = LogisticRegression()
clf.fit(x_train, y_train)

# 一下幾行僅用於展現那幾個函式的作用,實際使用不應隨便挑幾個資料驗證
logi_pre=clf.predict(X[:5, :])
logi_pro=clf.predict_proba(X[:5, :]) 
logi_accuracy=clf.score(x_test, y_test)
logi_deci=clf.decision_function(X[-5:,:])
print(y)
print("prediction of first 5 samples: ",end=" ")
print(logi_pre)
print("prediction probability of first 5 samples: ")
print(logi_pro)
print("decision_function of last 5 samples(大於0時,正類被預測): ",end=" ")
print(logi_deci)
print("prediction accuracy of test data: ",end=" ")
print(logi_accuracy)

predictions=clf.predict_proba(x_test)#每一類的概率
false_positive_rate, recall, thresholds = roc_curve(y_test, predictions[:, 1])
roc_auc=auc(false_positive_rate,recall)
plt.title('ROC of logistics in test data')
plt.plot(false_positive_rate, recall, 'b', label='AUC = %0.2f' % roc_auc)
plt.legend(loc='lower right')
plt.plot([0,1],[0,1],'r--')
plt.xlim([0.0,1.0])
plt.ylim([0.0,1.0])
plt.ylabel('Recall')
plt.xlabel('Fall-out')
plt.show()

AUC/ROC計算的sklearn官網舉例

print(__doc__)
# ROC for model

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"])

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()

 

題外話:SVM引數設定的案例

import numpy as np
from sklearn.svm import SVR,SVC
import matplotlib.pyplot as plt

# #############################################################################
# Generate sample data
X = np.sort(16 * np.random.rand(80, 1), axis=0)
y = np.sin(X).ravel()

# #############################################################################
# Add noise to targets
y[::5] += 3 * (0.5 - np.random.rand(16))

# Fit regression model
svr_rbf = SVC(kernel='rbf', C=1e3, gamma=0.1)
# svr_rbf = SVR(kernel='rbf', C=1e3, gamma=100) #可能過擬合
# svr_lin = SVR(kernel='linear', C=1e3)
# svr_poly = SVR(kernel='poly', C=1e3, degree=2)
y_rbf = svr_rbf.fit(X, y).predict(X)

# Look at the results
lw = 2
plt.scatter(X, y, color='darkorange', label='data')
plt.plot(X, y_rbf, color='navy', lw=lw, label='RBF model')
# plt.plot(X, y_lin, color='c', lw=lw, label='Linear model')
# plt.plot(X, y_poly, color='cornflowerblue', lw=lw, label='Polynomial model')
plt.xlabel('data')
plt.ylabel('target')
plt.title('Support Vector Regression')
plt.legend()
plt.show()