最近在打天池的比賽,裏面須要用AUC來評測模型的性能,因此這裏介紹一下AUC的相關概念,並介紹TensorFlow含有的函數來計算AUC。python
先介紹一些前置的概念。在一個二分類問題中,若是自己是正例(positive),預測正確也預測成正例,則稱爲真正例(true positive),簡稱TP,而預測錯誤預測成了反例,則稱爲假反例(false negative),簡稱FN,若是自己是反例(negative),預測正確也預測成反例,則稱爲真反例(true negative),簡稱TN,而預測錯誤預測成了正例,則稱爲假正例(false positive),簡稱FP。查準率、查全率以及F1值都是根據上述四個值計算出來的,這裏不作贅述。apache
真正例率(True Positive Rate,簡稱TPR),計算公式爲TPR = TP / (TP + FN),和查全率的公式一致,表示預測爲正例且自己是正例的樣本數佔全部自己是正例的樣本數的比重。假正例率(False Positive Rate,簡稱FPR),計算公式爲FPR = FP / (TN + FP),表示預測爲正例且自己是反例的樣本數佔全部自己是反例的樣本數的比重。bash
ROC全稱是受訪者工做特徵(Receiver Operating Characteristic)曲線,用來研究通常狀況下模型的泛化性能。先根據模型的預測結果將樣本進行排序,將最多是正例,也就是預測出是正例的機率最高的樣本排在前面,而後機率依次下降,將最不多是正例也就是預測時正例機率最低的樣本排在最後。而後ROC曲線以真正例率做爲縱軸,假正例率做爲橫軸,按順序逐個把樣本預測成正例,在每一個樣本預測後TPR、FPR的值都會改變,就在圖像上增長一個新的點,直到全部點都預測爲正例爲止。能夠考慮一種極端狀況做爲例子,若是模型很是完美,泛化性能很好,則在排序後前面的全是預測正例實際上也是正例,後面的全是反例,實際上也是反例。一開始將全部樣本都預測爲反例,此時TP和FP都是0,因此曲線從原點(0,0)開始,將第一個樣本預測爲正例,此時它自己是正例,預測也是正例,因此TP爲1,TPR此時爲1/正例樣本數,而FP仍是爲0,因此曲線下一個點沿y軸向上。以此類推,一直預測到最後一個正例,此時TP爲正例樣本數,TPR爲1,因此曲線延伸到了(0,1),而後將第一個反例預測成了正例,此時TP值不變,FP變爲1,FPR此時爲1/反例樣本數,因此曲線在y值仍然爲1的狀況下沿x軸正方向增長一個點進行延伸,以此類推一直到把全部的反例都預測正正例,此時FP爲反例樣本數,FPR值也爲1。上面的例子是一個完美的模型,而若是有預測錯誤的,即按順序預測將全部的正例預測爲正例前遇到了 反例預測爲正例,則FP值會增長,此時仍有正例沒有被預測爲正例,因此TP不爲1,而FP會變爲1,即曲線沒有達到(0,1)點後就會向右延伸。下圖爲一個ROC曲線的實例。app
而直接對比兩個交叉的ROC曲線,仍然沒法很好地評測模型的性能,因此用曲線下的面積來表明模型的性能,也就是本文要介紹的AUC(Area Under ROC Curve)。從上文完美模型的例子可知,AUC的面積上限爲1。隨機猜想時AUC的值即爲0.5,因此在深度學習中通常模型的AUC都會大於0.5,若是模型的值遠遠小於0.5,多是你的標籤弄反了,我在天池一個比賽中,一開始AUC只有0.24,比胡亂猜想的0.5都要低,一開始百思不得其解,後來發現題目要求上傳的是反例的機率,我上傳的是正例的機率,因此實際上我模型的AUC是0.76,這點要注意。函數
因爲個人模型是用TensorFlow 代碼生成的,因此AUC也天然使用TensorFlow提供的函數來計算。網上不少的資料是用用tf.contrib.metrics.streaming_auc這個函數來計算的,但訪問官方文檔會提示該函數已經棄用,在將來版本會刪去,應該使用tf.metrics.auc函數,函數體以下:性能
tf.metrics.auc( labels, predictions, weights=None, num_thresholds=200, metrics_collections=None, updates_collections=None, curve='ROC', name=None, summation_method='trapezoidal' )
Args: labels: A Tensor whose shape matches predictions. Will be cast to bool. predictions: A floating point Tensor of arbitrary shape and whose values are in the range [0, 1]. weights: Optional Tensor whose rank is either 0, or the same rank as labels, and must be broadcastable to labels (i.e., all dimensions must be either 1, or the same as the corresponding labels dimension). num_thresholds: The number of thresholds to use when discretizing the roc curve. metrics_collections: An optional list of collections that auc should be added to. updates_collections: An optional list of collections that update_op should be added to. curve: Specifies the name of the curve to be computed, 'ROC' [default] or 'PR' for the Precision-Recall-curve. name: An optional variable_scope name. summation_method: Specifies the Riemann summation method used (https://en.wikipedia.org/wiki/Riemann_sum): 'trapezoidal' [default] that applies the trapezoidal rule; 'careful_interpolation', a variant of it differing only by a more correct interpolation scheme for PR-AUC - interpolating (true/false) positives but not the ratio that is precision; 'minoring' that applies left summation for increasing intervals and right summation for decreasing intervals; 'majoring' that does the opposite. Note that 'careful_interpolation' is strictly preferred to 'trapezoidal' (to be deprecated soon) as it applies the same method for ROC, and a better one (see Davis & Goadrich 2006 for details) for the PR curve. Returns: auc: A scalar Tensor representing the current area-under-curve. update_op: An operation that increments the true_positives, true_negatives, false_positives and false_negatives variables appropriately and whose value matches auc.
即最簡單的使用方法是直接傳兩個參數labels和predictions,也就是樣本的標籤和預測的機率,會獲得返回的auc的值,num_thresholds的值默認爲200,而越大auc的值會越精確,一直到你的樣本數量爲止,以後再增大不會改變,因此樣本數大於200須要對num_thresholds進行傳參。可是實際使用上會遇到一些問題。首先,在寫好該公式,在已經運行過sess.run(tf.global_variables_initializer())後進行sess.run該auc,會提示下列錯誤:學習
FailedPreconditionError (see above for traceback): Attempting to use uninitialized value auc/true_negatives
查閱網上相關資料後發現要在運行前添加這麼一句:編碼
sess.run(tf.local_variables_initializer()) 或 sess.run(tf.initialize_local_variables())
第二種方式運行時會建議你使用第一種。scala
這樣編碼後程序能順利運行不報錯,但這樣運行後的auc的值始終是0.0,怎麼調整參數都沒有用,我一度懷疑是代碼的問題,後來在stackoverflow,發如今sess.run(auc_value)之前,因爲tf.metrics.auc會返回兩個參數,第一個參數auc_value是auc的值,第二個參數auc_op是auc的更新操做,要先運行sess.run(auc_op)後再運行計算auc的值,纔會正確顯示auc的值。個人代碼例子以下: code
prediction_tensor = tf.convert_to_tensor(prediction_list) label_tensor = tf.convert_to_tensor(label_list) auc_value, auc_op = tf.metrics.auc(label_tensor, prediction_tensor, num_thresholds=2000) sess.run(tf.global_variables_initializer()) sess.run(tf.local_variables_initializer()) sess.run(auc_op) value = sess.run(auc_value) print(prediction_tensor) print(label_tensor) print("AUC:" + str(value))
其中prediction_list和label_list都是Python list類型,prediction_list每一個元素都是0~1的機率值,label_list每一個元素的值都是True或False,轉化爲tensor後便可計算對應的AUC,運行結果以下。
Tensor("Const:0", shape=(1544,), dtype=float32) Tensor("Const_1:0", shape=(1544,), dtype=bool) AUC:0.97267157
這樣就能成功運行並顯示AUC了。