回覆列表
  • 1 # 踩了一坨狗屎

    分三部分,第一部分是對AUC的基本介紹,包括AUC的定義,解釋,以及演算法和程式碼,第二部分用邏輯迴歸作為例子來說明如何透過直接最佳化AUC來訓練,第三部分,內容完全由@李大貓原創——如何根據auc值來計算真正的類別,換句話說,就是對auc的反向工程。

    1. 什麼是AUC?

    AUC是一個模型評價指標,只能用於二分類模型的評價,對於二分類模型,還有很多其他評價指標,比如logloss,accuracy,precision。如果你經常關注資料探勘比賽,比如kaggle,那你會發現AUC和logloss基本是最常見的模型評價指標。為什麼AUC和logloss比accuracy更常用呢?因為很多機器學習的模型對分類問題的預測結果都是機率,如果要計算accuracy,需要先把機率轉化成類別,這就需要手動設定一個閾值,如果對一個樣本的預測機率高於這個預測,就把這個樣本放進一個類別裡面,低於這個閾值,放進另一個類別裡面。所以這個閾值很大程度上影響了accuracy的計算。使用AUC或者logloss可以避免把預測機率轉換成類別。

    AUC是Area under curve的首字母縮寫。Area under curve是什麼呢,從字面理解,就是一條曲線下面區域的面積。所以我們要先來弄清楚這條曲線是什麼。這個曲線有個名字,叫ROC曲線。ROC曲線是統計裡面的機率,最早由電子工程師在二戰中提出來(更多關於ROC的資料可以參考維基百科)。

    ROC曲線是基於樣本的真實類別和預測機率來畫的,具體來說,ROC曲線的x軸是偽陽性率(false positive rate),y軸是真陽性率(true positive rate)。那麼問題來了,什麼是真、偽陽性率呢?對於二分類問題,一個樣本的類別只有兩種,我們用0,1分別表示兩種類別,0和1也可以分別叫做陰性和陽性。當我們用一個分類器進行機率的預測的時候,對於真實為0的樣本,我們可能預測其為0或1,同樣對於真實為1的樣本,我們也可能預測其為0或1,這樣就有四種可能性:

    真陽性率=(真陽性的數量)/(真陽性的數量+偽陰性的數量)

    偽陽性率=(偽陽性的數量)/(偽陽性的數量+真陰性的數量)

    有了上面兩個公式,我們就可以計算真、偽陽性率了。但是如何根據預測的機率得到真偽陽性、陰性的數量。

    我們來看一個具體例子,比如有5個樣本:

    真實的類別(標籤)是y=c(1,1,0,0,1)

    一個分類器預測樣本為1的機率是p=c(0.5,0.6,0.55,0.4,0.7)

    如文章一開始所說,我們需要選定閾值才能把機率轉化為類別,選定不同的閾值會得到不同的結果。如果我們選定的閾值為0.1,那5個樣本被分進1的類別,如果選定0.3,結果仍然一樣。如果選了0.45作為閾值,那麼只有樣本4被分進0,其餘都進入1類。一旦得到了類別,我們就可以計算相應的真、偽陽性率,當我們把所有計算得到的不同真、偽陽性率連起來,就畫出了ROC曲線,我們不需要手動做這個,因為很多程式包可以自動計算真、偽陽性率,比如在R裡面,下面的程式碼可以計算以上例子的真、偽陽性率並且畫出ROC曲線:

    library(ROCR)

    p=c(0.5,0.6,0.55,0.4,0.7)

    y=c(1,1,0,0,1)

    pred = prediction(p, y)

    perf = performance(pred,"tpr","fpr")

    plot(perf,col="blue",lty=3, lwd=3,cex.lab=1.5, cex.axis=2, cex.main=1.5,main="ROC plot")

    得到了ROC曲線,那麼曲線下面的面積也就可以算出來了,同樣,我們可以透過程式得到面積:

    auc = performance(pred,"auc")

    auc = unlist(slot(auc, "y.values"))

    這個ROC的面積也就是我們要計算的AUC值。

    透過AUC的定義我們知道了AUC是什麼,怎麼算,但是它的意義是什麼呢。如果從定義來理解AUC的含義,比較困難,實際上AUC和Mann–Whitney U test有密切的聯絡,我會在第三部說明。從Mann–Whitney U statistic的角度來解釋,AUC就是從所有1樣本中隨機選取一個樣本, 從所有0樣本中隨機選取一個樣本,然後根據你的分類器對兩個隨機樣本進行預測,把1樣本預測為1的機率為p1,把0樣本預測為1的機率為p0,p1>p0的機率就等於AUC。所以AUC反應的是分類器對樣本的排序能力。根據這個解釋,如果我們完全隨機的對樣本分類,那麼AUC應該接近0.5。另外值得注意的是,AUC對樣本類別是否均衡並不敏感,這也是不均衡樣本通常用AUC評價分類器效能的一個原因。

    有朋友用python,下面程式碼用於在python裡面計算auc:

    from sklearn import metrics

    def aucfun(act,pred):

    fpr, tpr, thresholds = metrics.roc_curve(act, pred, pos_label=1)

    return metrics.auc(fpr, tpr)

    2. 可以直接最佳化AUC來訓練分類器嗎?

    答案是肯定的,我在這裡給出一個簡單的例子,透過直接最佳化AUC來訓練一個邏輯迴歸模型。大家應該知道邏輯迴歸通常是透過極大似然估計來訓練的,也就是最大化極大似然函式,這是統計裡的概念,在機器學習裡,對應logloss函式。我們透過下面的例子來訓練一個邏輯迴歸是的AUC最大化:

    #生成訓練資料

    set.seed(1999)

    x1 = rnorm(1000)

    x2 = rnorm(1000)

    z = 1 + 2*x1 + 3*x2

    pr = 1/(1+exp(-z))

    y = rbinom(1000,1,pr)

    #使用logloss作為訓練目標函式

    df = data.frame(y=y,x1=x1,x2=x2)

    glm.fit=glm( y~x1+x2,data=df,family="binomial")

    #下面使用auc作為訓練目標函式

    library(ROCR)

    CalAUC <- function(real,pred){

    rocr.pred=prediction(pred,real)

    rocr.perf=performance(rocr.pred,&#39;auc&#39;)

    as.numeric([email protected])

    }

    #初始值

    beta0=c(1,1,1)

    loss <- function(beta){

    z=beta[1]+beta[2]*x1+beta[3]*x2

    pred=1/(1+exp(-z))

    -CalAUC(y,pred)

    }

    res=optim(beta0,loss,method = &#34;Nelder-Mead&#34;,control = list(maxit = 100))

    cat(&#34;直接用AUC訓練:&#34;,-res$value)

    cat(&#34;使用glm函式&#34;,CalAUC(y,glm.fit$fitted.values))

    程式輸出結果:

    直接用AUC訓練: 0.9339833

    使用glm函式 0.9338208

    可見,透過直接最佳化AUC,我們得到的AUC比直接最佳化logloss稍大一點點點點。

    根據@西方不得不敗 提示,glmnet包自帶根據AUC來訓練邏輯迴歸的功能,這裡就不展開說啦。

    理論上講,直接最佳化AUC在一定條件下就是rankboost演算法(感興趣可以參見paper)。

    對於最近十分火熱的xgboost包,也提供了直接最佳化AUC的功能,使用起來很簡單,只要把目標函式設定為:

    objective = &#39;rank:pairwise&#39;

    3. 從AUC到真實類別(label)?

    最開始思考這個問題是做一個網上的比賽,二分類問題,每次提交一組預測系統會計算出一個AUC值,因為這個比賽只有5000樣本,並且系統顯示的AUC值有小數點後面7、8位,所以我想是否可以透過可能透過AUC值計算出樣本的真實label來。也許並沒有實際價值,但是問題本身是很有趣的,像是在破解密碼。

    一個naive但是可行但是效率很低的辦法, 就是每次生成一組預測值,裡面只有一個樣本預測為1,其餘都是0,然後提交預測計算AUC,然後根據這個AUC來判斷此樣本的label,但是這樣效率太低了,5000個樣本,需要5000次提交。

    思考了很久,最後發現可以透過AUC的另一個計算公式入手。也就是第一部分說的U statistic。

    3.1 根據一個AUC值計算樣本中0,1的數目

    根據AUC與U statistic的聯絡,我們可以用下面的程式碼計算AUC:

    auc=(sum(rank(c(p(label==1),p(label==0)))[1:n1])-n1*(n1+1)/2)/n0/n1

    上面label表示樣本的真實類別,p表示預測為1的機率,rank是R的內建函式,n0表示真實資料中0的數目,n1表示1的數目,n0+n1=n表示資料所有樣本數目,根據這個簡單的一行程式碼,我們可以不用任何包來計算AUC。

    上面公式很有趣,n0,n1還有label都是固定的,p不同導致auc不一致,觀察sum裡面,可以發現這個sum本質是什麼?就是計算pred裡面對應的真實label為1的那些預測值的rank的和。

    繼續使用第一部分的例子,5個樣本的預測值的rank:

    rank(c(0.5,0.6,0.55,0.4,0.7))

    [1] 2 4 3 1 5

    其中真實為1的樣本(1,2,5)的對應rank是2,4,5,這三個rank值的和2+4+5=11,n0=2,n1=3,於是根據上面的AUC公式:(11-3*(3+1)/2)/2/3=5/6=0.83333,這個結果與我們在第一部分用AUC定義算的值完全一樣。

    所以說,真正影響auc的,就是預測值裡面對本來是1的樣本的預測的rank的和。

    要破解真實label,第一部要做的是找到樣本里面0和1的數目,也就是n0和n1等於多少。這個問題不復雜。要知道相同預測值的rank也一致,就是說如果所有樣本的預測只取0或者1,那對應的rank只有兩個unique數值。

    再觀察AUC公式裡面的sum:

    sum(rank(c(pred(label==1),pred(label==0)))[1:n1])

    這個sum是n1個數值的和,這n1個數值,當我們的pred只有兩個不同取值的時候,僅包括兩個unique的數值。繼續用上面例子,一共有5個樣本,我們生成第一組預測p如下:

    > p=c(1,1,1,0,0)

    > rank(p)

    [1] 4.0 4.0 4.0 1.5 1.5

    可見p的rank只有兩個不同取值,1.5和4,這是因為預測機率p也只有兩個不同取值。

    然後我們還知道sum是n1個數的sum,我們不知道的是這n1個數,裡面有幾個1.5,幾個4,假設其中有k1個1.5,k2個4,可以列出一個方程:

    k1+k2=n1

    k1*1.5+k2*4=sum(rank(c(p(label==1),p(label==0)))[1:n1])=auc*n0*n1+n1*(1+n1)/2

    所以最終得到下面的方程組:

    k1+k2=n1

    k1*1.5+k2*4=0.833333*n0*n1+n1*(1+n1)/2

    n0+n1=5

    其中k1,k2和n1未知,兩個方程,3個未知數,屬於不定方程組,但是要知道k1,k2,和n1都是整數,並且有取值範圍,要借出來很簡單,寫一個for 迴圈,1秒中就可以找到一組滿足3個方程多k1,k2以及n1。

    如果我們變更p,比如p=c(rep(1,m),rep(0,5-m)),透過一樣的演算法,可以計算出來前m個樣本中1的數量。

    透過這個演算法,我可以算出來這個貸款預測比賽測試資料中有509個1和4491個0。

    做到這裡,差點就放棄了,但是後來突然又有了靈感,找到了下面的演算法:

    3.2 根據AUC破解樣本的真實label

    這裡就省略思考過程了, 直接來破解演算法:

    對於一組總數為n的測試樣本,我們先來計算

    m=floor(log(n,base=2))+1

    這個m表示我們透過兩次auc計算可以計算出至少多少個樣本的真實label,比如n=5000,那麼m=13

    也就是說透過我們兩次提交,可以最少得到13個樣本的label。這13個樣本是可以自己隨便指定的,比如我們對前13個樣本感興趣,那麼具體做法如下:

    fix1=2^c(0:12)

    fix2=c(fix1[-1],fix1[1])

    unfixed=setdiff(1:5000,fix1)

    p1=c(fix1,unfixed)#第1組預測

    p2=c(fix2,unfixed)#第2組預測

    使用上面的兩組預測p1和p2分別計算AUC,得到auc1和auc2,根據上面給出的auc演算法:

    sum(rank(c(p1(label==1),p1(label==0)))[1:n1])-n1*(1+n1)/2=auc1*n0*n1

    sum(rank(c(p2(label==1),p2(label==0)))[1:n1])-n1*(1+n1)/2=auc2*n0*n1

    兩個公式相減:

    sum(rank(c(p1(label==1),p1(label==0)))[1:n1])-sum(rank(c(p2(label==1),p2(label==0)))[1:n1])-n1*(1+n1)/2=(auc1-auc2)*n0*n1

    得到的這個等式裡,我們已經透過上面的方法找到了n0和n1,auc1和auc2是已知,所以等式右面值可以算出,那麼等式左面呢,因為我們兩個預測結果p1和p2只有前三個點的預測之不一樣,其餘點的預測值一樣,rank也一樣,那麼等式左面的兩個sum的差,其實只由前13個樣本的真實label決定,具體來說:

    sum1-sum2=y1*(fix1[1]-fix2[1])+y2*(fix1[2]-fix2[2])+...+y13*(fix1[13]-fix2[13])

    =y1*(-1)+y2*(-2)+...+y12*(-2048)+y13*(4095)

    上面的方程裡面yi代表樣本i的真實label,有且只有唯一解,以為這個方程本質上就是10進位制數用2進製表達。所以透過兩次auc計算,我們可以找到13個點的真實標籤。比如對上面提到的貸款預測比賽,選定前13個label,auc1=0.50220853,auc2= 0.5017588,然後就可以算出來前13個test樣本只有第三個樣本是0,其餘都是1。

    但是13並不是上限,我有一些更好的結果,比較複雜,在這就不展開說了。

  • 2 # 踩了一坨狗屎

    分三部分,第一部分是對AUC的基本介紹,包括AUC的定義,解釋,以及演算法和程式碼,第二部分用邏輯迴歸作為例子來說明如何透過直接最佳化AUC來訓練,第三部分,內容完全由@李大貓原創——如何根據auc值來計算真正的類別,換句話說,就是對auc的反向工程。

    1. 什麼是AUC?

    AUC是一個模型評價指標,只能用於二分類模型的評價,對於二分類模型,還有很多其他評價指標,比如logloss,accuracy,precision。如果你經常關注資料探勘比賽,比如kaggle,那你會發現AUC和logloss基本是最常見的模型評價指標。為什麼AUC和logloss比accuracy更常用呢?因為很多機器學習的模型對分類問題的預測結果都是機率,如果要計算accuracy,需要先把機率轉化成類別,這就需要手動設定一個閾值,如果對一個樣本的預測機率高於這個預測,就把這個樣本放進一個類別裡面,低於這個閾值,放進另一個類別裡面。所以這個閾值很大程度上影響了accuracy的計算。使用AUC或者logloss可以避免把預測機率轉換成類別。

    AUC是Area under curve的首字母縮寫。Area under curve是什麼呢,從字面理解,就是一條曲線下面區域的面積。所以我們要先來弄清楚這條曲線是什麼。這個曲線有個名字,叫ROC曲線。ROC曲線是統計裡面的機率,最早由電子工程師在二戰中提出來(更多關於ROC的資料可以參考維基百科)。

    ROC曲線是基於樣本的真實類別和預測機率來畫的,具體來說,ROC曲線的x軸是偽陽性率(false positive rate),y軸是真陽性率(true positive rate)。那麼問題來了,什麼是真、偽陽性率呢?對於二分類問題,一個樣本的類別只有兩種,我們用0,1分別表示兩種類別,0和1也可以分別叫做陰性和陽性。當我們用一個分類器進行機率的預測的時候,對於真實為0的樣本,我們可能預測其為0或1,同樣對於真實為1的樣本,我們也可能預測其為0或1,這樣就有四種可能性:

    真陽性率=(真陽性的數量)/(真陽性的數量+偽陰性的數量)

    偽陽性率=(偽陽性的數量)/(偽陽性的數量+真陰性的數量)

    有了上面兩個公式,我們就可以計算真、偽陽性率了。但是如何根據預測的機率得到真偽陽性、陰性的數量。

    我們來看一個具體例子,比如有5個樣本:

    真實的類別(標籤)是y=c(1,1,0,0,1)

    一個分類器預測樣本為1的機率是p=c(0.5,0.6,0.55,0.4,0.7)

    如文章一開始所說,我們需要選定閾值才能把機率轉化為類別,選定不同的閾值會得到不同的結果。如果我們選定的閾值為0.1,那5個樣本被分進1的類別,如果選定0.3,結果仍然一樣。如果選了0.45作為閾值,那麼只有樣本4被分進0,其餘都進入1類。一旦得到了類別,我們就可以計算相應的真、偽陽性率,當我們把所有計算得到的不同真、偽陽性率連起來,就畫出了ROC曲線,我們不需要手動做這個,因為很多程式包可以自動計算真、偽陽性率,比如在R裡面,下面的程式碼可以計算以上例子的真、偽陽性率並且畫出ROC曲線:

    library(ROCR)

    p=c(0.5,0.6,0.55,0.4,0.7)

    y=c(1,1,0,0,1)

    pred = prediction(p, y)

    perf = performance(pred,&#34;tpr&#34;,&#34;fpr&#34;)

    plot(perf,col=&#34;blue&#34;,lty=3, lwd=3,cex.lab=1.5, cex.axis=2, cex.main=1.5,main=&#34;ROC plot&#34;)

    得到了ROC曲線,那麼曲線下面的面積也就可以算出來了,同樣,我們可以透過程式得到面積:

    auc = performance(pred,&#34;auc&#34;)

    auc = unlist(slot(auc, &#34;y.values&#34;))

    這個ROC的面積也就是我們要計算的AUC值。

    透過AUC的定義我們知道了AUC是什麼,怎麼算,但是它的意義是什麼呢。如果從定義來理解AUC的含義,比較困難,實際上AUC和Mann–Whitney U test有密切的聯絡,我會在第三部說明。從Mann–Whitney U statistic的角度來解釋,AUC就是從所有1樣本中隨機選取一個樣本, 從所有0樣本中隨機選取一個樣本,然後根據你的分類器對兩個隨機樣本進行預測,把1樣本預測為1的機率為p1,把0樣本預測為1的機率為p0,p1>p0的機率就等於AUC。所以AUC反應的是分類器對樣本的排序能力。根據這個解釋,如果我們完全隨機的對樣本分類,那麼AUC應該接近0.5。另外值得注意的是,AUC對樣本類別是否均衡並不敏感,這也是不均衡樣本通常用AUC評價分類器效能的一個原因。

    有朋友用python,下面程式碼用於在python裡面計算auc:

    from sklearn import metrics

    def aucfun(act,pred):

    fpr, tpr, thresholds = metrics.roc_curve(act, pred, pos_label=1)

    return metrics.auc(fpr, tpr)

    2. 可以直接最佳化AUC來訓練分類器嗎?

    答案是肯定的,我在這裡給出一個簡單的例子,透過直接最佳化AUC來訓練一個邏輯迴歸模型。大家應該知道邏輯迴歸通常是透過極大似然估計來訓練的,也就是最大化極大似然函式,這是統計裡的概念,在機器學習裡,對應logloss函式。我們透過下面的例子來訓練一個邏輯迴歸是的AUC最大化:

    #生成訓練資料

    set.seed(1999)

    x1 = rnorm(1000)

    x2 = rnorm(1000)

    z = 1 + 2*x1 + 3*x2

    pr = 1/(1+exp(-z))

    y = rbinom(1000,1,pr)

    #使用logloss作為訓練目標函式

    df = data.frame(y=y,x1=x1,x2=x2)

    glm.fit=glm( y~x1+x2,data=df,family=&#34;binomial&#34;)

    #下面使用auc作為訓練目標函式

    library(ROCR)

    CalAUC <- function(real,pred){

    rocr.pred=prediction(pred,real)

    rocr.perf=performance(rocr.pred,&#39;auc&#39;)

    as.numeric([email protected])

    }

    #初始值

    beta0=c(1,1,1)

    loss <- function(beta){

    z=beta[1]+beta[2]*x1+beta[3]*x2

    pred=1/(1+exp(-z))

    -CalAUC(y,pred)

    }

    res=optim(beta0,loss,method = &#34;Nelder-Mead&#34;,control = list(maxit = 100))

    cat(&#34;直接用AUC訓練:&#34;,-res$value)

    cat(&#34;使用glm函式&#34;,CalAUC(y,glm.fit$fitted.values))

    程式輸出結果:

    直接用AUC訓練: 0.9339833

    使用glm函式 0.9338208

    可見,透過直接最佳化AUC,我們得到的AUC比直接最佳化logloss稍大一點點點點。

    根據@西方不得不敗 提示,glmnet包自帶根據AUC來訓練邏輯迴歸的功能,這裡就不展開說啦。

    理論上講,直接最佳化AUC在一定條件下就是rankboost演算法(感興趣可以參見paper)。

    對於最近十分火熱的xgboost包,也提供了直接最佳化AUC的功能,使用起來很簡單,只要把目標函式設定為:

    objective = &#39;rank:pairwise&#39;

    3. 從AUC到真實類別(label)?

    最開始思考這個問題是做一個網上的比賽,二分類問題,每次提交一組預測系統會計算出一個AUC值,因為這個比賽只有5000樣本,並且系統顯示的AUC值有小數點後面7、8位,所以我想是否可以透過可能透過AUC值計算出樣本的真實label來。也許並沒有實際價值,但是問題本身是很有趣的,像是在破解密碼。

    一個naive但是可行但是效率很低的辦法, 就是每次生成一組預測值,裡面只有一個樣本預測為1,其餘都是0,然後提交預測計算AUC,然後根據這個AUC來判斷此樣本的label,但是這樣效率太低了,5000個樣本,需要5000次提交。

    思考了很久,最後發現可以透過AUC的另一個計算公式入手。也就是第一部分說的U statistic。

    3.1 根據一個AUC值計算樣本中0,1的數目

    根據AUC與U statistic的聯絡,我們可以用下面的程式碼計算AUC:

    auc=(sum(rank(c(p(label==1),p(label==0)))[1:n1])-n1*(n1+1)/2)/n0/n1

    上面label表示樣本的真實類別,p表示預測為1的機率,rank是R的內建函式,n0表示真實資料中0的數目,n1表示1的數目,n0+n1=n表示資料所有樣本數目,根據這個簡單的一行程式碼,我們可以不用任何包來計算AUC。

    上面公式很有趣,n0,n1還有label都是固定的,p不同導致auc不一致,觀察sum裡面,可以發現這個sum本質是什麼?就是計算pred裡面對應的真實label為1的那些預測值的rank的和。

    繼續使用第一部分的例子,5個樣本的預測值的rank:

    rank(c(0.5,0.6,0.55,0.4,0.7))

    [1] 2 4 3 1 5

    其中真實為1的樣本(1,2,5)的對應rank是2,4,5,這三個rank值的和2+4+5=11,n0=2,n1=3,於是根據上面的AUC公式:(11-3*(3+1)/2)/2/3=5/6=0.83333,這個結果與我們在第一部分用AUC定義算的值完全一樣。

    所以說,真正影響auc的,就是預測值裡面對本來是1的樣本的預測的rank的和。

    要破解真實label,第一部要做的是找到樣本里面0和1的數目,也就是n0和n1等於多少。這個問題不復雜。要知道相同預測值的rank也一致,就是說如果所有樣本的預測只取0或者1,那對應的rank只有兩個unique數值。

    再觀察AUC公式裡面的sum:

    sum(rank(c(pred(label==1),pred(label==0)))[1:n1])

    這個sum是n1個數值的和,這n1個數值,當我們的pred只有兩個不同取值的時候,僅包括兩個unique的數值。繼續用上面例子,一共有5個樣本,我們生成第一組預測p如下:

    > p=c(1,1,1,0,0)

    > rank(p)

    [1] 4.0 4.0 4.0 1.5 1.5

    可見p的rank只有兩個不同取值,1.5和4,這是因為預測機率p也只有兩個不同取值。

    然後我們還知道sum是n1個數的sum,我們不知道的是這n1個數,裡面有幾個1.5,幾個4,假設其中有k1個1.5,k2個4,可以列出一個方程:

    k1+k2=n1

    k1*1.5+k2*4=sum(rank(c(p(label==1),p(label==0)))[1:n1])=auc*n0*n1+n1*(1+n1)/2

    所以最終得到下面的方程組:

    k1+k2=n1

    k1*1.5+k2*4=0.833333*n0*n1+n1*(1+n1)/2

    n0+n1=5

    其中k1,k2和n1未知,兩個方程,3個未知數,屬於不定方程組,但是要知道k1,k2,和n1都是整數,並且有取值範圍,要借出來很簡單,寫一個for 迴圈,1秒中就可以找到一組滿足3個方程多k1,k2以及n1。

    如果我們變更p,比如p=c(rep(1,m),rep(0,5-m)),透過一樣的演算法,可以計算出來前m個樣本中1的數量。

    透過這個演算法,我可以算出來這個貸款預測比賽測試資料中有509個1和4491個0。

    做到這裡,差點就放棄了,但是後來突然又有了靈感,找到了下面的演算法:

    3.2 根據AUC破解樣本的真實label

    這裡就省略思考過程了, 直接來破解演算法:

    對於一組總數為n的測試樣本,我們先來計算

    m=floor(log(n,base=2))+1

    這個m表示我們透過兩次auc計算可以計算出至少多少個樣本的真實label,比如n=5000,那麼m=13

    也就是說透過我們兩次提交,可以最少得到13個樣本的label。這13個樣本是可以自己隨便指定的,比如我們對前13個樣本感興趣,那麼具體做法如下:

    fix1=2^c(0:12)

    fix2=c(fix1[-1],fix1[1])

    unfixed=setdiff(1:5000,fix1)

    p1=c(fix1,unfixed)#第1組預測

    p2=c(fix2,unfixed)#第2組預測

    使用上面的兩組預測p1和p2分別計算AUC,得到auc1和auc2,根據上面給出的auc演算法:

    sum(rank(c(p1(label==1),p1(label==0)))[1:n1])-n1*(1+n1)/2=auc1*n0*n1

    sum(rank(c(p2(label==1),p2(label==0)))[1:n1])-n1*(1+n1)/2=auc2*n0*n1

    兩個公式相減:

    sum(rank(c(p1(label==1),p1(label==0)))[1:n1])-sum(rank(c(p2(label==1),p2(label==0)))[1:n1])-n1*(1+n1)/2=(auc1-auc2)*n0*n1

    得到的這個等式裡,我們已經透過上面的方法找到了n0和n1,auc1和auc2是已知,所以等式右面值可以算出,那麼等式左面呢,因為我們兩個預測結果p1和p2只有前三個點的預測之不一樣,其餘點的預測值一樣,rank也一樣,那麼等式左面的兩個sum的差,其實只由前13個樣本的真實label決定,具體來說:

    sum1-sum2=y1*(fix1[1]-fix2[1])+y2*(fix1[2]-fix2[2])+...+y13*(fix1[13]-fix2[13])

    =y1*(-1)+y2*(-2)+...+y12*(-2048)+y13*(4095)

    上面的方程裡面yi代表樣本i的真實label,有且只有唯一解,以為這個方程本質上就是10進位制數用2進製表達。所以透過兩次auc計算,我們可以找到13個點的真實標籤。比如對上面提到的貸款預測比賽,選定前13個label,auc1=0.50220853,auc2= 0.5017588,然後就可以算出來前13個test樣本只有第三個樣本是0,其餘都是1。

    但是13並不是上限,我有一些更好的結果,比較複雜,在這就不展開說了。

  • 中秋節和大豐收的關聯?
  • 考科三都有哪些技巧?