在线广告预估ctr的AUC计算方法

一、auc选特征的原理

在优化模型的时候,我们期望能够加入足够多有典型区分度的特征。特征有良好的区分度,有助于在筛选广告阶段进行准确的排序。准确的排序意味着,在排序好的候选广告中,可以选择top1,或者top2等这样高预估ctr的广告进行展现。也就是说,加入的特征能够触发高ctr高的广告排在前面。

二、ctr的auc计算方法

(1)定义法:

     根据discrimination threshold阈值,每次在一个pCTR上进行划分,取划分这个pCTR为阈值,高于这个阈值的是预估的正样本,低于这个阈值,是预估的负样本。在这种情况下,计算当前这个划分的tprfpr。得到一个点对(fpr, tpr)。每个划分都会得到一个点对,那么就可以绘制出ROC,进而计算出AUC。

     tpr = tp/p = 预测是正样本实际也是正样本的个数(把正样本预测为正样本的个数)/正样本的个数

     fpr = fp/N = 预测是正样本实际是负样本的个数(把负样本预测为正样本的个数)/负样本的个数

给定一组样本如下,其中正样本4个,负样本4个:

 

样本真实值pctr
10.9
10.8
00.7
10.5
00.4
10.3
00.2
00.1

在本例中,tp即为预测为正样本中,1的个数,fp即为预测为正样本中,0的个数

根据阈值0.9进行划分,大于等于0.9预测为正样本,小于0.9预测为负样本,tpr=1/4=0.25,fpr=0/4=0;

根据阈值0.8进行划分,大于等于0.8预测为正样本,小于0.8预测为负样本,tpr=2/4=0.5,fpr=0/4=0;

根据阈值0.7进行划分,大于等于0.7预测为正样本,小于0.7预测为负样本,tpr=2/4=0.5,fpr=1/4=0.25;

根据阈值0.5进行划分,大于等于0.5预测为正样本,小于0.5预测为负样本,tpr=3/4=0.75,fpr=1/4=0.25;

根据阈值0.4进行划分,大于等于0.4预测为正样本,小于0.4预测为负样本,tpr=3/4=0.75,fpr=2/4=0.5;

根据阈值0.3进行划分,大于等于0.3预测为正样本,小于0.3预测为负样本,tpr=4/4=1,fpr=1/4=0.25;

根据阈值0.2进行划分,大于等于0.2预测为正样本,小于0.2预测为负样本,tpr=4/4=1,fpr=3/4=0.75;

根据阈值0.1进行划分,大于等于0.1预测为正样本,小于0.1预测为负样本,tpr=4/4=1,fpr=4/4=1;

(2)Wilcoxon-Mann-Witney Test惠特尼检验的方法;

   Wilcoxon-Mann-Witney Test就是测试任意给一个正类样本和一个负类样本,正类样本的score有多大的概率大于负类样本的score.首先对score从大到小排序,然后令最大score对应的sample 的rank为n,第二大score对应sample的rank为n-1,以此类推。然后把所有的正类样本的rank相加,再减去正类样本的score为最 小的那M个值的情况。得到的就是所有的样本中有多少对正类样本的score大于负类样本的score。然后再除以M×N

还以上面的例子来计算,(M为正样本的个数,N为负样本的个数):

 

样本真实值pctrrank
10.98
10.87
00.76
10.55
00.44
10.33
00.22
00.11

 

auc = (正样本的各个rank的和 - M*(M+1)/2)/M*N=[(8+7+5+3)-4*5/2]/4*4=13/16

也即总共有13的(正,负)的点对,正样本的ctr高于负样本的ctr

rank之和: 8 +7 + 5 + 3

                 4    3    2    1

实际:       4 + 4 + 3 + 2

实验方法:

1、从AUC统计意义去计算。所有的正负样本对中,正样本排在负样本前面占样本对数的比例,即这个概率值。 
具体的做法就是它也是首先对prob score从大到小排序,然后令最大prob score对应的sample 的rank为n,第二大score对应sample的rank为n-1,以此类推。然后把所有的正类样本的rank相加,再减去M-1种两个正样本组合的情况。得到的就是所有的样本中有多少对正类样本的score大于负类样本的score。最后再除以M×N。公式如下

def calAUC(prob,labels):
    f = list(zip(prob,labels))
    rank = [values2 for values1,values2 in sorted(f,key=lambda x:x[0])]
    rankList = [i+1 for i in range(len(rank)) if rank[i]==1]
    posNum = 0
    negNum = 0
    for i in range(len(labels)):
        if(labels[i]==1):
            posNum+=1
        else:
            negNum+=1
    auc = 0
    auc = (sum(rankList)- (posNum*(posNum+1))/2)/(posNum*negNum)
    print(auc)
    return auc

其中:其中输入prob是得到的概率值[0.5,0.6,04,0.3,0.1],labels是分类的标签[1,0,1,0,1]

2、通过计算梯形的面积

注意:(1)首先按ctr从大到小排序;(2)对于正样本来说,每个ctr的正样本,需要对前面的进行累加

得出当前的正样本,因为每次ctr划分。比如:>ctr1的为正样本,小于ctr1为负样本,前面的ctr都比ctr1大,

因此需要把前面的正样本累加到本次当中,负样本no_click不用累加。(3)横坐标为FPR=no_click/no_click_sum,

纵坐标为TPR = click_num/click_num_sum。

def scoreClickAUC(predicted_ctr):
    """
     利用梯形面积计算auc
     @predictd_ctr: {score:[show,click]}
    """
    i_sorted = sorted(predicted_ctr.iteritems(),key=lambda x:x[0],reverse=True)
    auc_temp = 0.0
    click_sum = 0.0 
    old_click_sum = 0.0 
    no_click = 0.0 
    no_click_sum = 0.0 
    for (pscore, [show, click]) in i_sorted:
        no_click = show - click
        #每次ctr的划分,需要对前面的正样本进行累加,前面的正样本对当前ctr来说也是
        #正样本
        click_sum += click
        auc_temp += (click_sum + old_click_sum) * no_click / 2.0 
        old_click_sum = click_sum
        #累加负样本
        no_click_sum += show - click
    auc = auc_temp / (click_sum * no_click_sum)
    return auc 

 

# coding=utf-8

import sys

import math

import time

import datetime

import numpy as np

class get_single_feature_auc(object):

    def __init__(self):

        self.thresh_hold_nums = 5 #最大序列长度

    def process(self,data_str,thresh_hold_nums):

        """

           返回每个区块周边的区块特征拼接

        """

        #feature_size = 0

        #if data_str is None: return

        score_dict = {}

        for elem in data_str.split(';'):

            p = elem.split(',')           

            if len(p) != 2:continue

            score_dict.setdefault(float(p[0]),[])

            score_dict[float(p[0])].append(int(p[1]))

        feature_distribute = {}

        score_list = sorted(score_dict.iteritems(), key=lambda x:x[0],reverse = False)

        #将实值列表,分到thresh_hold_nums个桶里

        seed = len(score_list) / thresh_hold_nums

        for i in range(len(score_list)):

            bucket_num = i / seed 

            click_ = len([e for e in score_list[i][1] if e == 1])

            no_click_ = len([e for e in score_list[i][1] if e == 0])

            feature_distribute.setdefault(bucket_num, [0,0])

            feature_distribute[bucket_num][0] += click_ + no_click_

            feature_distribute[bucket_num][1] += click_

        #基于每个桶,统计正负样本,并计算不同的阈值

        predicted_ctr = dict()

        for key in feature_distribute:

            show_,click_ = feature_distribute[key][:]

            pscore = click_ * 1.0/show_

            predicted_ctr.setdefault(pscore, [0,0])

            predicted_ctr[pscore][0] += show_

            predicted_ctr[pscore][1] += click_

        #计算梯形面积,累计出auc的值

        i_sorted = sorted(predicted_ctr.iteritems(), key=lambda x:x[0],reverse = True)

        auc_temp = 0.0

        click_sum = 0.0

        old_click_sum = 0.0

        no_click = 0.0

        no_click_sum = 0.0

        for (pscore, [show, click]) in i_sorted:

            no_click = show - click

            click_sum += click

            auc_temp += (click_sum + old_click_sum) * no_click /2.0

            old_click_sum = click_sum

            no_click_sum += show - click

        auc = auc_temp / (click_sum * no_click_sum)

        print auc

if __name__ == '__main__':

    op = get_single_feature_auc()

    op.process("0.3,1;0.45,0;0.56,1;0.3,0;0.21,1;0.33,0;0.43,1;0.78,0;0.65,1;0.98,0;0.75,0",5)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值