Uplift模型计算AUUC和QINI
指标纵轴含义基线面积计算对象AUUC累积增量响应人数占比(NCGkNCGky0y=0y0(不干预)Uplift Curve与y0y=0y0的面积QINI累积净新增转化占比(NCQkNCQk随机策略线(RandompRandompQINI Curve与随机线的面积差图形对比AUUC Curve:从00(0,0)00升至1OverallIR1OverallIR,面积越大越好。QINI Curve:高于
以下内容由大模型生成,如有错误恳求指正
1. 定义与公式
1.1 定义与计算方式
AUUC(Uplift Curve下的面积)
-
计算公式:
f(k)=(YkTNkT−YkCNkC)⋅(NkT+NkC) f(k) = \left( \frac{Y_k^T}{N_k^T} - \frac{Y_k^C}{N_k^C} \right) \cdot (N_k^T + N_k^C) f(k)=(NkTYkT−NkCYkC)⋅(NkT+NkC)
其中:- YkTY_k^TYkT 和 YkCY_k^CYkC:在Top-k样本中,处理组(Treatment)和对照组(Control)的响应数(如购买数)。
- NkTN_k^TNkT 和 NkCN_k^CNkC:在Top-k样本中,处理组和对照组的总样本数。
- f(k)f(k)f(k) 表示Top-k样本中干预带来的提升(ATE)。
-
AUUC的计算:
对所有样本按Uplift值降序排序后,累加每个k对应的f(k)f(k)f(k),即:
AUUC=∑k=1nf(k) AUUC = \sum_{k=1}^{n} f(k) AUUC=k=1∑nf(k) -
特点:
- 直接反映干预组和对照组在Top-k样本中的响应差异,并乘以样本总数,强调绝对提升量。
Qini Coefficient(Qini Curve下的面积)
-
计算公式:
g(k)=YkT−YkC⋅NkTNkC g(k) = Y_k^T - \frac{Y_k^C \cdot N_k^T}{N_k^C} g(k)=YkT−NkCYkC⋅NkT- g(k)g(k)g(k) 表示Top-k样本中,处理组的实际响应数减去对照组按比例调整后的响应数。
-
Qini Coefficient的计算:
累加每个k对应的g(k)g(k)g(k),即:
Qini=∑k=1ng(k) Qini = \sum_{k=1}^{n} g(k) Qini=k=1∑ng(k) -
特点:
- 通过缩放对照组的响应数,消除样本数量不平衡的影响。
由计算公式可得:
f(k)=g(k)NkT⋅(NkT+NkC) f(k) = \frac{g(k)}{N_k^T} \cdot (N_k^T + N_k^C) f(k)=NkTg(k)⋅(NkT+NkC)
1.2 曲线形态与面积意义
- 关键区别:
- AUUC的曲线横轴是样本数量(kkk),纵轴是绝对提升量(f(k)f(k)f(k));
- Qini曲线的横轴是样本比例,纵轴是调整后的相对提升量(g(k)g(k)g(k))。
1.3 应用场景
AUUC适用场*:处理组和对照组样本数量相近。
Qini Coefficient适用场景:处理组和对照组样本数量不均衡。
示例说明:
- AUUC:若模型能精准识别Top 20%的用户,则AUUC面积较大。
- Qini Coefficient:若模型在Top 20%用户中,干预组的响应数远高于对照组,Qini面积仍会较大。
2. 代码实现AUUC
2.1 Python实现版
def calculate_auuc_with_curve(y_true, uplift_score, treatment):
"""
计算 AUUC 及其曲线上的每个点
:param y_true: array-like, 用户是否转化,如 [0, 1, 0, 1]
:param uplift_score: array-like, 模型预测的uplift分数
:param treatment: array-like, 是否为处理组(1表示处理组,0表示对照组)
:return: auuc_value: float, 使用梯形法则计算的AUUC值;
curve_values: list, 每个划分点的AUUC值(包括第0行);
indexes: list, 每个分档的下标(从0到n-1)
"""
df = np.array(list(zip(y_true, uplift_score, treatment)))
# 按uplift分数从高到低排序
df_sorted = df[df[:, 1].argsort()[::-1]]
cum_treatment_response = 0
cum_control_response = 0
cum_treatment_count = 0
cum_control_count = 0
curve_values = [0.0] # 初始第0行值为0
indexes = [0] # 第0行对应索引0
for i in range(len(df_sorted)):
label, score, treat = df_sorted[i]
if treat == 1:
cum_treatment_response += label
cum_treatment_count += 1
else:
cum_control_response += label
cum_control_count += 1
if cum_treatment_count > 0 and cum_control_count > 0:
avg_treat = cum_treatment_response / cum_treatment_count
avg_control = cum_control_response / cum_control_count
delta = avg_treat - avg_control
elif cum_treatment_count > 0:
delta = cum_treatment_response / cum_treatment_count
else:
delta = -cum_control_response / cum_control_count
total_samples = cum_treatment_count + cum_control_count
current_auuc = delta * total_samples
curve_values.append(current_auuc)
indexes.append(i + 1) # 索引从1开始对应后续绘图点
# 使用梯形法则求面积
auuc_value = 0
for i in range(1, len(curve_values)):
base = 1 # 每次增加一个样本单位
height_avg = (curve_values[i - 1] + curve_values[i]) / 2
auuc_value += base * height_avg
return auuc_value, curve_values, indexes
2.2 开源代码scikit-uplift版
from sklift.metrics import uplift_curve, uplift_auc_score
from sklift.viz import plot_uplift_curve
# 计算auuc曲线的每个点
cnts, gains = uplift_curve(df['y_true'], df['uplift_pred'], df['treatment'])
# 与perfect曲线对比的分值(例如perfect是100分,模型预测值是85分即0.85)
score = uplift_auc_score(df['y_true'], df['uplift_pred'], df['treatment'])
# 画图,包含3条曲线:模型预测、perfect、random
plot_uplift_curve(
df['y_true'], df['uplift_pred'], df['treatment'],
perfect=True, name='mode_pred', #ax=ax
);
从uplift_curve到uplift_auc_score:
from sklift.metrics import uplift_curve, uplift_auc_score, perfect_uplift_curve
from sklift.viz import plot_uplift_curve
from sklearn.metrics import auc
cnt, gains = uplift_curve(df['y_true'], df['uplift_pred'], df['treatment'])
cnt_p, perfect_gains = perfect_uplift_curve(df['y_true'], df['treatment'])
cnt_rand = [0, cnt[-1]]
gains_rand = [0, gains[-1]]
rand_auc = auc(cnt_rand, gains_rand)
pred_auc = auc(cnt, gains)
perfect_auc = auc(cnt_p, perfect_gains)
score2 = (pred_auc - rand_auc) / (perfect_auc - rand_auc) # score2 与 score 相等
2.2 开源代码causalml版
from causalml.metrics import auuc_score
outcome_col="y_true"
treatment_col="treatment"
score = auuc_score(df1, outcome_col, treatment_col)
score
# uplift_pred 0.767181
# Random 0.470098
# dtype: float64
这个auuc score是如何计算的:
from causalml.metrics import auuc_score, get_cumgain, get_cumlift
outcome_col="y_true"
treatment_col="treatment"
treatment_effect_col="tau"
normalize=True
random_seed=42
df1 = df[['y_true', 'treatment', 'uplift_pred']].copy()
lift = get_cumlift(df1, outcome_col, treatment_col, treatment_effect_col, random_seed) # 计算每个分位点的增益率
gains = lift.mul(lift.index.values, axis=0) # 乘数量得到增益值
if normalize:
gains2 = gains.div(np.abs(gains.iloc[-1, :]), axis=1)
gains2.sum() / len(gains2) # 等于上面的score
与scikit-uplift的异同:
- 相同:uplift_curve计算得到的gains与上面的gains结果是相同的(略有小差别,两种方法对T和C缺失的处理不太一样,对整体影响不大)
- 不同:
- sklift中uplift_auc_score:增加了与baseline和perfect的对比,并计算出一个相对分值
- causalml:
- 有两处归一化:gains除以gains[-1],gains[-1]是用所有样本算的一个整体增益;gains2.sum() / len(gains2),相当于对gains2求了个均值
- 增加了一个random对比对象:源码中是随机生成了10组random的uplift_pred,计算完增益后求了个均值
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐


所有评论(0)