前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >跟着开源项目学因果推断——mr_uplift(十五)

跟着开源项目学因果推断——mr_uplift(十五)

作者头像
悟乙己
发布2021-12-07 16:46:03
9360
发布2021-12-07 16:46:03
举报
文章被收录于专栏:素质云笔记素质云笔记

文章目录

在这里插入图片描述
在这里插入图片描述

1 mr_uplift 介绍

1.1 介绍

官方地址:https://github.com/Ibotta/mr_uplift

目前有几个升级模型包(参见EconML、GRF、PTE)。他们倾向于用有趣的方法来估计异质处理效果。然而,主要模型中倾向于关注单一response、单一treatment 情景。

mr_uplift开源库,试图为Uplift建模构建一个自动化的解决方案,包括以下特性:

  • 允许多种treatments 。可以在每一种干预下,合并元特征,比如用向量来表示treatment
  • 允许多responses
  • response under proposed treatments (ERUPT)functionality that estimates model performance on OOS data.

它通过估计一个形式为y ~ f(t,x)的神经网络来做到这一点,其中y、x和t是响应、解释变量和treatment变量。 如果optim_loss=True,则使用实验损失函数来估计函数,如果treatment不是随机分配的,则有倾向评分功能得分。 同时可以预测所有treatment的反事实逻辑结果

代码语言:javascript
复制
import numpy as np
import pandas as pd

from mr_uplift.dataset.data_simulation import get_simple_uplift_data
from mr_uplift.mr_uplift import MRUplift

#Generate Data
y, x, t = get_simple_uplift_data(10000)
y = pd.DataFrame(y)
y.columns = ['revenue','cost', 'noise']
y['profit'] = y['revenue'] - y['cost']

#Build / Gridsearch model
uplift_model = MRUplift()
param_grid = dict(num_nodes=[8], dropout=[.1, .5], activation=[
                      'relu'], num_layers=[1, 2], epochs=[25], batch_size=[30])
uplift_model.fit(x, y, t.reshape(-1,1), param_grid = param_grid, n_jobs = 1)

#OOS ERUPT Curves
erupt_curves, dists = uplift_model.get_erupt_curves()

#predict optimal treatments with new observations
_, x_new ,_  = get_simple_uplift_data(5)
uplift_model.predict_optimal_treatments(x_new, objective_weights = np.array([.6,-.4,0,0]).reshape(1,-1))

MRUplift初始化模型,这里响应y有四个维度

在这里插入图片描述
在这里插入图片描述

1.2 ERUPT 准则

参考: https://medium.com/building-ibotta/erupt-expected-response-under-proposed-treatments-ff7dd45c84b4

Expected Response Under Proposed Treatments (ERUPT) Metric 建议治疗(ERUPT)指标下的预期反应

在网格搜索之后,我们想知道模型比当前状态好多少。 评估样本外重要性是确保模型在生产中按预期运行的关键。 虽然有其他指标,如QINI指标,它们通常限于单一的治疗情况。 ERUPT是我所知道的唯一一个可以应用于多种治疗的指标,并提供了如果应用该模型将会发生什么情况的无偏估计。 假设您有一个观察,代表是否给予奖金,

𝜋(x)提出不给予奖金的处理,而随机分配的处理给予奖金。 由于这些不一致,我们不清楚我们能说什么。

然而,如果模型的最优处理等于指定的处理,我们可以在我们提出的处理示例中包括该观察结果。 我们对所有的观察进行这个练习,并仅计算𝜋(x) =指定treatment时候,Y的均值。 这是我们在模型下估算的y值!

\frac{\sum_i y_i I(\pi(x_i) = t_i)} {\sum_i I(\pi(x_i)=t_i)}

注意,这个公式假设处理的分布是均匀的(每个处理的数量相同)和随机分配。 这个包中的功能不需要统一的处理,但是需要随机分配。 详情见 blog post here.

输出的两个表格:

  • 1 第一个数据帧显示了模型分配的爆发度量和标准偏差。在这个例子中,如果我们使用这个模型,它会告诉我们期望利润。 此外,我们还可以看到分配列下的“随机”行。它使用了与𝜋(𝑥)相同的分布,但打乱了处理,使其成为一个随机分配。观察模型和随机分配之间的区别应该告诉我们模型是否学习了个体治疗的效果好。 下面我们可以看到,该模型比随机处理的效果好得多,说明该模型很好地了解了治疗效果的异质性。如果我们采用这种模式,我们预计利润为0.16。
在这里插入图片描述
在这里插入图片描述
  • 2 数据帧显示了处理在最优分配下的分布。在这个例子中,我们可以看到大约一半被分配了治疗,另一半没有。tmt 代表 treatment,num_observations代表不同treatment的样本量
在这里插入图片描述
在这里插入图片描述

2 案例模拟

可以参考官方文档:mr_uplift_multiple_response_example

本笔记本将介绍使用MRUplift框架优化多个响应变量。这里将设定:

  • 假设问题和数据生成过程
  • 建立uplift模型
  • 用样本外out-of-sample ERUPT度量来评估模型
  • 预测新的观察结果分配

业务问题 假设我们是数据科学家,为一家初创公司工作,这家公司希望以更有效的方式发展业务。

作为一种增加用户活跃度的策略,该公司为所有用户提供了一种 收费的干预条件,比如大会员, 这里需要找到哪些人愿意接受这样的大会员充值,同时让这些人购买。 不过不是特别确认,

为了降低成本,我们的任务是利用数据找到一个用户子集,这些用户应该继续接受昂贵的治疗,同时继续增长(以收入衡量)。当然这里会出现几种想要达到的响应Y:

  • 最大化收入
  • 最大化利润
  • 最大化收益(利润 - 成本)

这里模拟数据会生成几类协变量X,随机生成是否接受大会员条件的treatment变量T以及最后的响应Y

生成的逻辑如下:

在这里插入图片描述
在这里插入图片描述

2.1 生成模拟数据

代码语言:javascript
复制
# 生成数据
y, x, t = get_simple_uplift_data(10000)

y = pd.DataFrame(y)
y.columns = ['revenue','cost', 'noise']
y['profit'] = y['revenue'] - y['cost']

其中Y为多个,有收入,成本,净收益:

在这里插入图片描述
在这里插入图片描述

新建模型 Model Building / Gridsearch

代码语言:javascript
复制
#Build / Gridsearch model
uplift_model = MRUplift()
param_grid = dict(num_nodes=[8], dropout=[.1, .5], activation=[
                      'relu'], num_layers=[1, 2], epochs=[25], batch_size=[30])
uplift_model.fit(x, y, t.reshape(-1,1), param_grid = param_grid, n_jobs = 1)

param_grid 就是神经网络的一些参数; t就是干预,这里是[0,1,0,1,xxxxx]这样的单变量干预

2.2 绘制ERUPT Curves曲线

代码语言:javascript
复制
erupt_curves, dists = uplift_model.get_erupt_curves()

#I create a new variable that shows the weight of the revenue variable
dists['weights_1'] = [np.float(x.split(',')[0]) for x in dists['weights']]
erupt_curves['weights_1'] = [np.float(x.split(',')[0]) for x in erupt_curves['weights']]

ggplot(aes(x='weights_1', y='mean', group = 'assignment', colour = 'assignment'), data=erupt_curves) +\
    geom_line()+\
    geom_point()+facet_wrap("response_var_names")

get_erupt_curves 会输出两个表格,第一个表格:

在这里插入图片描述
在这里插入图片描述

weight权重代表的四要素分别为:[收入,成本,噪声,利润] 第一个是在给定一组模型权重的情况下,所有响应变量的ERUPT 度量和标准偏差。 在这个例子中,权重设置是从成本最小化到收益最大化的目标。 我们看到成本和收入都在上升,但速度不同。当收入权重为0.5,成本权重为0.5时,利润最大化。 最后我们还可以看到噪声响应变量没有受到预期的影响。

简单解读一下图中的第一行,response_var_names指的是在revenue收入上,设置weights[收入,成本]各自为[0.5,0.5]下,收入的平均值为0.501,收入标准差0.0051; assignment表示:model模型加持下;random随机安排加持下;best_single_tmt状态加持下的收入水平。

在这里插入图片描述
在这里插入图片描述

再来0/2/3行,在相同weights下,收入这个response,在不同的assignment加持下(best_single_tmt / model / random)的收入水平,分别是0.501 / 0.350 / 0.274; 从这可以看到best_single_tmt效果最佳

第二个表格是:

在这里插入图片描述
在这里插入图片描述

第二个df显示了在一组客观权重的最优分配下处理的分布。 在这个例子中,我们可以看到,当我们将目标函数加权为更大的收益最大化时,分配处理的次数会增加。 tmt代表treatment,第一行代表,在[0,1,0,0]weight状态下,所有的样本都是未治疗的,,7000个样本,占比为1; 在[0.1,0.9,0,0]weight状态下,第二行+第三行是这个状态的,tmt = 1有8个样本,占比0.001;tmt = 0有6992样本

在这里插入图片描述
在这里插入图片描述

因为这里响应Y有多个,其实可以当作综合评价,计算一个综合指数Y:

y_{new} = weight_0*\hat{y_0} + weight_1*\hat{y_1} + ... + weight_{num responses}*\hat{y_{num responses}}

这里的weight可以自由设立,不同的权重象征着不同的项目诉求,可以更看重收入,也可以更看重净收入。

2.3 为新的观测结果分配最佳处理方法

在建立和评估一个uplift模型后,如果需要上线到生产环境,就要为新用户分配最佳处理,可以使用predict_optimal_therapies函数,但现在需要进行权重分配。 我设置了0.6收入和0.4成本

代码语言:javascript
复制
#generate 5 new observation
_, x_new ,_  = get_simple_uplift_data(5)
uplift_model.predict_optimal_treatments(x_new, weights = np.array([.6,-.4,0,0]).reshape(1,-1))

输出结果为:

代码语言:javascript
复制
array([[1],
       [1],
       [1],
       [1],
       [0]])

2.4 协变量X的重要性

来自:mr_uplift_variable_importance_example.ipynb 这里描述的变量重要性度量是排列重要性的一种变化; 对一列进行洗牌并测量输出与原始数据输出的不一致程度。

代码语言:javascript
复制
uplift_model.permutation_varimp(objective_weights = np.array([.6,-.4,0,0]).reshape(1,-1))

导出:

代码语言:javascript
复制
   permutation_varimp_metric
0                   0.347571
1                   0.238286

两个变量的在weight - [.6,-.4,0,0]下的重要性

3 mr_uplift + 倾向得分

主要的变化是为倾向模型构建了一个形式为𝑡=𝑓(𝑥)的随机森林。 他们预测并计算反概率作为观测权值:1/f(x)。 注意,倾向模型是一个多分类模型,支持两种以上的处理方法。 然后,这个weight被输入到ERUPT 计算和uplift模型的loss 损失函数中。

代码语言:javascript
复制
import numpy as np
import pytest

from mr_uplift.dataset.data_simulation import get_observational_uplift_data_2
from mr_uplift.mr_uplift import MRUplift, get_t_data
from mr_uplift.keras_model_functionality import prepare_data_optimized_loss
import sys
import pandas as pd

# 生成数据
y, x, t = get_observational_uplift_data_2(10000)

y = y[:,0].reshape(-1,1)

# 模型一:未加入倾向得分
uplift_model = MRUplift()
param_grid = dict(num_nodes=[8,64], dropout=[.1, .5], activation=[
                          'relu'], num_layers=[1], epochs=[25], batch_size=[512])

uplift_model.fit(x, y, t.reshape(-1,1), 
                 param_grid = param_grid, n_jobs = 1)

# 模型二:加入倾向得分
uplift_model_propensity = MRUplift()
param_grid_propensity = dict(num_nodes=[8, 64], dropout=[.1, .5], activation=[
                          'relu'], num_layers=[1], epochs=[25], batch_size=[512],
                 alpha = [.9999,.99], copy_several_times = [1])

uplift_model_propensity.fit(x, y, t.reshape(-1,1), 
                 param_grid = param_grid_propensity, n_jobs = 1,
                optimized_loss = True, use_propensity = True)


#calculate oos predictions 
# 计算OOS 预测
y_test, x_test, t_test = get_observational_uplift_data_2(10000)

pred_uplift = uplift_model.predict_optimal_treatments(x = x_test)
pred_uplift_propensity = uplift_model_propensity.predict_optimal_treatments(x = x_test, 
                use_propensity_score_cutoff = True)
correct_tmt = (x_test[:,0]>0).reshape(-1,1)*1

# 两个模型正确treatment的数量
print('Uplift Model Correct Decisions')
print((pred_uplift == correct_tmt).mean())

print('Uplift Model using Propensity Correct Decisions')
print((pred_uplift_propensity == correct_tmt).mean())

两个模型的差异:

代码语言:javascript
复制
Uplift Model Correct Decisions
0.5754
Uplift Model using Propensity Correct Decisions
0.9886

4 简单看一下:class:MRUplift

关于fit

代码语言:javascript
复制
fit(self, x, y, t, test_size=0.7, random_state=22, param_grid=None,
            n_jobs=-1, cv=5, optimized_loss = False, PCA_x = False, PCA_y = False, bin = False,
            use_propensity = False, propensity_score_cutoff = 100)

param_grid代表模型参数,cv数量,还可以对数据进行降维PCA_x use_propensity = True的话,会使用RF下的一个倾向得分; mruplift里面自带了调参工具,GridSearchCV

代码语言:javascript
复制
GridSearchCV(
        estimator=model,
        param_grid=param_grid,
        n_jobs=n_jobs,
        scoring=mse_loss_multi_output_scorer,
        verbose=False,
        cv=cv)

模型利用了KerasRegressor,默认:

代码语言:javascript
复制
    model = KerasRegressor(
        build_fn=hete_mse_loss_multi_output,
        input_shape=x.shape[1],
        output_shape=y.shape[1],
        num_nodes=32,
        num_layers=1,
        epochs=100,
        verbose=False,
        dropout=.2,
        batch_size=1000)
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-10-09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 文章目录
  • 1 mr_uplift 介绍
    • 1.1 介绍
      • 1.2 ERUPT 准则
      • 2 案例模拟
        • 2.1 生成模拟数据
          • 2.2 绘制ERUPT Curves曲线
            • 2.3 为新的观测结果分配最佳处理方法
              • 2.4 协变量X的重要性
              • 3 mr_uplift + 倾向得分
              • 4 简单看一下:class:MRUplift
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档