【因果推断python】53_效应异质性和非线性带来的挑战1

news2024/11/18 3:22:27

目录

Treatment Effects on Binary Outcomes

合成一些数据


由于缺乏基本事实,在单位层面预测治疗效果极为困难。因为我们只能观察到一个潜在结果 T(t)
,我们无法直接估计它。相反,我们必须依靠目标变换(也可以看作是设计巧妙的损失函数)来估计条件治疗效果,但只能是期望值。但这并不是唯一的挑战。由于治疗效果非常不稳定,其估计值通常会有相当大的噪声。这对于我们想根据治疗效果来划分治疗单位的应用(比如我们想进行个性化治疗分配)来说,会产生巨大的实际影响。

现在我们将看到,有时如果我们不直接估算 CATE,而是关注另一个通常方差较小的替代目标,就能获得更好的治疗效果分割。出现这种情况的常见情况是,所关注的结果变量Y是二元变量。

Treatment Effects on Binary Outcomes

import pandas as pd
import numpy as np
import seaborn as sns
import statsmodels.formula.api as smf
from matplotlib import pyplot as plt
from matplotlib import style
style.use("ggplot")
from typing import List

import numpy as np
import pandas as pd
from toolz import curry, partial

@curry
def avg_treatment_effect(df, treatment, outcome):
    return df.loc[df[treatment] == 1][outcome].mean() - df.loc[df[treatment] == 0][outcome].mean()
    
    

@curry
def cumulative_effect_curve(df: pd.DataFrame,
                            treatment: str,
                            outcome: str,
                            prediction: str,
                            min_rows: int = 30,
                            steps: int = 100,
                            effect_fn = avg_treatment_effect) -> np.ndarray:
    
    size = df.shape[0]
    ordered_df = df.sort_values(prediction, ascending=False).reset_index(drop=True)
    n_rows = list(range(min_rows, size, size // steps)) + [size]
    return np.array([effect_fn(ordered_df.head(rows), treatment, outcome) for rows in n_rows])


@curry
def cumulative_gain_curve(df: pd.DataFrame,
                          treatment: str,
                          outcome: str,
                          prediction: str,
                          min_rows: int = 30,
                          steps: int = 100,
                          effect_fn = avg_treatment_effect) -> np.ndarray:
    

    size = df.shape[0]
    n_rows = list(range(min_rows, size, size // steps)) + [size]

    cum_effect = cumulative_effect_curve(df=df, treatment=treatment, outcome=outcome, prediction=prediction,
                                         min_rows=min_rows, steps=steps, effect_fn=effect_fn)

    return np.array([effect * (rows / size) for rows, effect in zip(n_rows, cum_effect)])

如果你在一家科技公司工作,你可能会遇到一个非常常见的问题:管理层希望通过某种手段提高客户对产品的转化率。例如,他们可能希望通过提供 10 BRL 的优惠券让客户进行应用内购买,从而增加应用的安装数量。或者在您首次使用他们的共享乘车应用时提供免费乘车服务。或者降低投资平台前三个月的交易费用。由于 "怂恿 "往往成本高昂,他们很希望不必为每个人都这样做。相反,如果我们能只对那些最敏感的客户使用促进转换的暗示,那就再好不过了。

从因果推理的角度来看,您现在可能已经知道,这类业务问题属于治疗效果异质性(TEH)范畴。具体来说,你有一个代价高昂的激励作为处理 T,转换为二元结果 Y 以及客户治疗前的具体特征 X
. 然后,您就可以用类似于双重/偏差异质性(Double/Debiased)的方法来估计条件平均治疗效果 E[Y_1-Y_0|X] 然后,您可以使用类似于双重/偏差 ML 的方法来估算条件平均处理效果 ,最后只对估算出的处理效果最高的客户进行激励。用商业术语来说,这就是个性化转换策略。您将找到转化增量高的客户群,并只对他们使用激励。

然而,这里有一个复杂因素,使得 TEH 方法并不那么明显。事实上,结果是二进制的,这让事情变得相当复杂。因为这有点违背直觉,所以我更愿意先说明发生了什么,然后再解释为什么会发生。

合成一些数据

让我们把这个问题简单化,但仍然可以联系起来。我们将模拟处理方法 "推移"(nudge)是完全随机的,从伯努利(Bernoulli)中抽取,p=0.5. 这意味着治疗是根据一枚公平的硬币分配的。这也意味着我们不需要注意任何混杂因素。

nudge\sim\mathcal{B}(0.5)

接下来,让我们按照伽马分布模拟客户的协变量年龄和收入。这些都是您所了解的客户信息,因此,您希望根据这些信息进行个性化定制。换句话说,您希望找到由年龄和收入定义的客户群体,从而使其中一个群体对推理处理反应强烈。

\begin{aligned}&age\sim G(10,4)\\&income\sim G(20,2)\end{aligned}

最后,我们将模拟转换。为此,我们将首先创建一个遵循随机噪声线性模型的潜变量。重要的是,请注意收入对 Y_{latent} 有很高的预测性,但它不会改变治疗效果。简单地说,"推导 "对所有收入水平的 Y_{latent} 对所有收入水平的影响都是一样的。与此相反,年龄只通过与推导治疗的交互作用影响 Y_{latent} 的影响。

Y_{latent}\sim N(-4.5+0.001 income+nudge+0.01 nudge age,1)

得到 Y_{latent} 值后,我们可以通过设置 Y_{latent}>x 来模拟转换。首先,让我们设置 x=0,这样转化率大致为 50%。也就是说,平均有 50%的客户转化为我们的产品。

conversion=1\{Y_{latent}>0\}

np.random.seed(123)

n = 100000
nudge = np.random.binomial(1, 0.5, n)
age = np.random.gamma(10, 4, n)
estimated_income = np.random.gamma(20, 2, n)*100

latent_outcome = np.random.normal(-4.5 + estimated_income*0.001 + nudge + nudge*age*0.01)
conversion = (latent_outcome > .1).astype(int)

为了方便起见,我们还可以将所有内容存储在 DataFrame 中。另外,检查一下平均转换率是否接近 50%。

df = pd.DataFrame(dict(conversion=conversion,
                       nudge=nudge,
                       age=age,
                       estimated_income=estimated_income,
                       latent_outcome=latent_outcome))

df.mean()

至于平均治疗效果,由于治疗是随机进行的,我们可以用治疗组和对照组平均值的简单差值来估算: E[Y|T=1]-E[Y|T=0]. 那么,让我们来看看这些治疗平均值是什么样的。我们将从潜在结果和转换角度来研究它们。这里有一点很重要。

df.groupby("nudge")[["latent_outcome", "conversion"]].mean()

avg_treatment_effect(df, "nudge", "latent_outcome")
1.4023163965477656
avg_treatment_effect(df, "nudge", "conversion")
0.39477273768476406

潜在结果的 ATE 非常简单。根据我们的数据生成模型,我们知道这一效应应为 1 + avg(年龄)*0.01。由于平均年龄约为 40 岁,因此 ATE 约为 1.4。更有趣(也更复杂)的地方在于转换的 ATE。由于转换的界限在 0 和 1 之间,因此其 ATE 不会是线性的。因此,我们无法像处理潜在结果那样,通过一个简单的公式来推导它(有一个公式,但相当复杂)。我们只能说影响较小。这有道理吧?我的意思是,治疗不可能使转化率提高 1.4 个百分点,因为转化率不可能超过 100%。现在,我要你们牢牢记住这个事实,因为它对我们理解接下来的内容至关重要。

现在让我们来谈谈条件平均治疗效果(CATE)。纵观我们的数据生成过程,我们知道一个事实,即估计收入会预测转化率,但不会改变激励对转化率的影响。因此,根据估计收入对客户进行细分将产生具有相同处理效果的细分。相比之下,年龄只会通过与诱导的交互作用影响转化率。因此,不同年龄的细分市场对治疗的反应会截然不同,而不同收入的细分市场则不会。换句话说,估计收入不应该是一个好的个性化变量,而年龄应该是。

通过累积效应曲线可以看出这一点。年龄的曲线应该从离 ATE 很远的地方开始,然后慢慢向 ATE 靠拢,而估计收入的曲线应该只在 ATE 附近波动。这正是我们在绘制对潜在结果的推移效应的累积效应曲线时所看到的。

cumulative_effect_fn = cumulative_effect_curve(df, "nudge", "latent_outcome", min_rows=500)

age_cumm_effect_latent = cumulative_effect_fn(prediction="age")
inc_cumm_effect_latent = cumulative_effect_fn(prediction="estimated_income")

plt.plot(age_cumm_effect_latent, label="age")
plt.plot(inc_cumm_effect_latent, label="est. income")
plt.legend()
plt.xlabel("Percentile")
plt.ylabel("Effect on Latet Outcome");

同样,潜在结果也非常好。由于它的线性,我们的预期与现实非常吻合。但在现实生活中,我们并不关心(也没有)潜在结果。我们有的只是转换。在转换过程中,事情看起来要复杂得多。如果我们绘制累积效应曲线,年龄仍然显示出一定的治疗效果异质性,从 ATE 以上开始,慢慢向 ATE 靠拢。这意味着年龄越大,治疗效果越高。到目前为止还不错。这正是我们所期望的。

cumulative_effect_fn = cumulative_effect_curve(df, "nudge", "conversion", min_rows=500)

age_cumm_effect_latent = cumulative_effect_fn(prediction="age")
inc_cumm_effect_latent = cumulative_effect_fn(prediction="estimated_income")

plt.plot(age_cumm_effect_latent, label="age")
plt.plot(inc_cumm_effect_latent, label="est. income")
plt.legend()
plt.xlabel("Percentile")
plt.ylabel("Effect on Conversino");

然而,根据估计收入的不同,治疗效果也存在很大的异质性。估计收入较高的客户的治疗效果要低得多,这导致累积效果曲线在开始时一直趋于零,然后慢慢向 ATE 收敛。这就告诉我们,就个性化而言,估计收入将产生比年龄产生的细分市场具有更多治疗效果异质性(TEH)的细分市场。

这很不方便吧?为什么我们知道年龄这一特征会导致治疗效果异质性,但与我们知道不会改变治疗效果的特征(估计收入)相比,年龄这一特征却更不利于个性化呢?答案就在于结果函数的非线性。虽然估计收入不会改变激励对潜在结果的影响,但一旦我们将该潜在结果转换为转换(至少是间接转换),它就会改变。转换不是线性的。这意味着它的导数会根据你所处的位置而变化。由于转换率最高只能达到 1,如果转换率已经很高,就很难再提高。换句话说,高转换率的导数非常低。但是,由于转换率也以 0 为界,如果转换率已经很低,导数也会很低。转换率呈 S 型,两端的导数都很低。我们可以通过绘制按估计收入分段(100 乘以 100 的分段)计算的平均转换率来了解这一点。

(df
 .assign(estimated_income_bins=(df["estimated_income"]/100).astype(int)*100)
 .groupby("estimated_income_bins")
 [["conversion"]]
 .mean()
 .plot()
);

请注意,当转换率非常高时,这条曲线的斜率(导数)非常小。当转换率很低时,斜率(导数)也很小(不过由于该地区样本较少,这一点比较难看出来)。有了这些信息,我们就可以解释为什么 estimated_income 会产生具有高度治疗效果异质性的区段。

由于 "估计收入 "对转换具有很高的预测性,我们可以说,"估计收入 "不同的客户属于 S 型转换曲线的不同位置。估计收入非常高或非常低的客户位于曲线的两端,导数较低,这意味着提高转换率的难度更大,进而意味着治疗效果可能较小。另一方面,报告收入在中间范围的客户也位于转换曲线的中间,导数较高,因此治疗效果也可能较高。我之所以说 "可能",是因为从理论上讲,一个变量有可能具有很强的效果修正力,以至于在我们穿越转换曲线时,它主导了导数的变化。然而,至少从我的经验来看,S 型转换曲线的曲率往往会主导我们的其他所有效应修正。

不过,这并不只是我一个人的看法。这是我从苏珊-阿特伊斯(Susan Atheys)在哥伦比亚数据科学研究所的演讲中获得的一张幻灯片。在这里,她讨论的是让学生申请联邦财政援助以支付大学学费的激励效果。这也是一个转换问题。她发现,最好的策略是针对那些已经有可能转化的学生。她还说,针对那些转化可能性低的学生是个坏主意

等一下 但这不是你第一次说的话!你说,无论是很高的转化率还是很低的转化率,其衍生率都很低,因此治疗效果也很低!

嗯,这是正确的。然而,在现实生活中,转换率很少会挤满整个 S 型曲线。我们通常看到的是,每个人都挤在曲线的一端或另一端。就商业而言,你的平均转化率很少达到 50%。更常见的是 70% 到 90% 或者 1% 到 20%。在这些更有可能的情况下,针对那些基线较高的人可能是一个好主意,也可能是一个坏主意。

我的意思是这样的: 让我们使用之前的潜在结果,但现在通过将其设置为 latent_outcome > 2,生成一种平均转化率较低的情况。接下来,让我们通过设置 latent_outcome > -2 来生成一种转换率高的情况。

df["conversion_low"] = conversion = (latent_outcome > 2).astype(int)
df["conversion_high"] = conversion = (latent_outcome > -2).astype(int)

print("Avg. Low Conversion: ", df["conversion_low"].mean())
print("Avg. High Conversion: ", df["conversion_high"].mean())
Avg. Low Conversion:  0.12119
Avg. High Conversion:  0.9275

根据我们对转化率非线性的了解,我们已经可以预测会发生什么。在低转化率的情况下,针对高基线转化率(高估计收入)的目标群体会更有效。这是因为我们处于 S 型转换曲线的左侧,基线转换率越低,导数就越小。在这一区域,高基线转换率将转化为高治疗效果。因此,我们应该对基线转换率高的人群,也就是估计收入较高的人群进行干预。

cumulative_effect_fn = cumulative_effect_curve(df, "nudge", "conversion_low", min_rows=500)

age_cumm_effect_latent = cumulative_effect_fn(prediction="age")
inc_cumm_effect_latent = cumulative_effect_fn(prediction="estimated_income")

plt.plot(age_cumm_effect_latent, label="age")
plt.plot(inc_cumm_effect_latent, label="est. income")
plt.xlabel("Percentile")
plt.ylabel("Effect on Conversino");
plt.legend();

就像我们预测的那样,估计收入高的人,也就是基线转换率高的人,治疗效果要高得多。

现在,对于转换率高的另一种情况,平均而言,基线转换率高的人的治疗效果会较低。因此,以估计收入高的人群为目标并不是一个好主意。我们可以从倒置的累积效应曲线看出这一点,即估计收入高的人的治疗效果较低。

cumulative_effect_fn = cumulative_effect_curve(df, "nudge", "conversion_high", min_rows=500)

age_cumm_effect_latent = cumulative_effect_fn(prediction="age")
inc_cumm_effect_latent = cumulative_effect_fn(prediction="estimated_income")

plt.plot(age_cumm_effect_latent, label="age")
plt.plot(inc_cumm_effect_latent, label="est. income")
plt.xlabel("Percentile")
plt.ylabel("Effect on Conversino")
plt.legend();

总之,我们看到的是,当结果是二元时,治疗效果往往受 Logistic 函数的曲率(导数)支配。

例如,在我们的转化问题中,如果平均转化率较低,我们就会处于逻辑曲线的左侧,在高基线转化率的情况下,治疗效果会更高。这将转化为一种激励政策,主张对转化概率已经很高的客户进行治疗(激励)。另一方面,如果平均转化率较高,我们就会处于逻辑曲线的右侧,基线转化率较低的客户的导数(以及治疗效果)会更高。

这当然需要记住很多东西,但我们完全可以简化:只要谁的基线转换率更接近 50%,就对谁进行治疗。这里的数学论证非常可靠:逻辑导数的峰值是 50%,因此只需处理更接近这一点的单位。

更妙的是,这是少有的常识与数学相符的情况。在市场营销中,这些转换问题非常常见,有一种观点认为,我们不应该针对输掉的赌注(转换概率非常低的赌注),也不应该针对稳赢的赌注(转换概率非常高的赌注)。相反,我们应该瞄准那些处于中间位置的人。这一点非常吸引人,因为这与我们使用更正式的因果论证所得出的结论完全相同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1858756.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Pytorch框架构建ResNet模型

Pytorch 一、训练模型1.导入资源包2.定义数据预处理3.读取数据 二、定义卷积神经网络1.导入必要的库2.定义名为convolutional_block的卷积块类3.定义了一个名为identity_block的恒等块类4.定义了一个名为Resnet的深度卷积神经网络类 三、创建模型1. 检查GPU设备2. 训练过程 四、…

编译原理大题自解(活前缀DFA、LR(0)分析表)

目录 4. (简答题) (1)给出识别活前缀的DFA (2)设计此文法的 LR(0)分析表 第一种解法 第二种解放 首先声明这是作者的写法(不保证正确!)仅供参考。本题因为可能存在冲突的原因,所…

【C语言小例程26/100】

题目&#xff1a;有一分数序列&#xff1a;2/1&#xff0c;3/2&#xff0c;5/3&#xff0c;8/5&#xff0c;13/8&#xff0c;21/13...求出这个数列的前20项之和。 程序分析&#xff1a;请抓住分子与分母的变化规律。 程序源代码&#xff1a; #include <stdio.h>int ma…

windows上运行arm32架构的安卓模拟器

说明 主要功能&#xff1a;在win10上研究和学习32位arm汇编指令的执行 环境如下 主机环境: windows10 目标模拟器环境:armeabi-v7a调试环境搭建 1、下载android studio 下载地址&#xff1a;https://developer.android.com/studio?hlzh-cn 2、安装android studio 直接下…

互联网应用主流框架整合之Spring Boot开发

Spring Boot数据库开发 通常SpringBoot数据库开发&#xff0c;会引入spring-boot-starter-jdbc&#xff0c;而如果引入了spring-boot-starter-jdbc&#xff0c;但没有可用的数据源或者没有配置&#xff0c;那么在运行Spring Boot时会出现异常&#xff0c;因为spring-boot-star…

思考-生涯思考-GPT-5对人们的影响

GPT-5 一年半后发布&#xff1f;对此你有何期待&#xff1f; IT之家6月22日消息&#xff0c;在美国达特茅斯工程学院周四公布的采访中&#xff0c;OpenAI首席技术官米拉穆拉蒂被问及GPT-5是否会在明年发布&#xff0c;给出了肯定答案并表示将在一年半后发布。此外&#xff0c;…

Java知识点整理 11— 后端 Spring Boot 万用初始化模板使用

一. 模块简介 annotation&#xff1a;自定义注解aop&#xff1a;请求日志和权限校验common&#xff1a;通用类config&#xff1a;配置类constant&#xff1a;常量 controller&#xff1a;控制层esdao&#xff1a;方便操作ESexception&#xff1a;异常类job&#xff1a;定时任务…

企业邮箱老板如何看员工邮件往来记录

员工离职&#xff0c;删除邮箱内重要邮件&#xff1f;已删除的邮件能否恢复&#xff1f;企业邮箱老板如何查看员工邮件的往来记录呢&#xff1f;本篇文章将为您详细介绍企业邮件自动备份的原理以及邮箱内的设置方法。 一、为何查看员工邮件往来记录&#xff1f; 企业邮箱关乎…

了解SD-WAN与传统WAN的区别

近年来&#xff0c;许多企业选择了SD-WAN作为他们的网络解决方案。云基础架构的SD-WAN不仅具备成本效益&#xff0c;而且提供更安全、更可靠的WAN连接&#xff0c;有助于实现持续盈利。客户能够更好地控制他们的网络&#xff0c;个性化定制且无需额外成本。 那么&#xff0c;为…

第二十八篇——复盘:世界不完美,我们该怎么办?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 对于信息传递过程中的相关知识的总结&#xff0c;让我又仿佛回到了每一个…

猫头虎 分享已解决Error || API Rate Limits: HTTP 429 Too Many Requests

猫头虎 分享已解决Error || API Rate Limits: HTTP 429 Too Many Requests &#x1f42f; 摘要 &#x1f4c4; 大家好&#xff0c;我是猫头虎&#xff0c;一名专注于人工智能领域的博主。在AI开发中&#xff0c;我们经常会遇到各种各样的错误&#xff0c;其中API Rate Limits…

多路h265监控录放开发-(15)回放页面中的三个槽函数进行视频的录放(0.1版本项目完结篇)

xviewer.h 中的回放页面的三个槽函数&#xff1a; void SelectCamera(QModelIndex index);//选择摄像机129void SelectDate(QDate date); //选择日期129void PlayVideo(QModelIndex index); //选择时间播放视频129 SelectCamera槽函数解析&#xff1a; 点击相机列表日…

【路由交换技术】Cisco Packet Tracer基础入门教程(四)

Hello各位&#xff0c;好久不见&#xff0c;第四期我准备讲一下Packet Tracer中DHCP的配置&#xff0c;使用方法。 本章实验我们将拓扑中的某个路由器作为DHCP服务器&#xff08;它仍然可作为路由器使用&#xff09;&#xff0c;通过命令配置DHCP服务。独立的服务器可通过图形化…

【AI大模型】GPTS 与 Assistants API

前言 2023 年 11 月 6 日&#xff0c;OpenAI DevDay 发表了一系列新能力&#xff0c;其中包括&#xff1a;GPT Store 和 Assistants API。 GPTs 和 Assistants API 本质是降低开发门槛 可操控性和易用性之间的权衡与折中&#xff1a; 更多技术路线选择&#xff1a;原生 API、…

创新指南|品牌电商新策略:五大转型思路与RGM举措

在流量红利过去的背景下&#xff0c;品牌电商面对多渠道运营的难题&#xff0c;如缺乏统盘经营、绩效管理分散、价格战失控、用户体验不足以及流量过度依赖&#xff0c;品牌电商如何有效应对这些挑战&#xff0c;本文从5个维度探讨全渠道电商RGM破局之路&#xff0c;实现品牌的…

利用chrome_remote_interface实现程序化、自动化Web安全测试

2024软件测试面试刷题&#xff0c;这个小程序&#xff08;永久刷题&#xff09;&#xff0c;靠它快速找到工作了&#xff01;&#xff08;刷题APP的天花板&#xff09;-CSDN博客跳槽涨薪的朋友们有福了&#xff0c;今天给大家推荐一个软件测试面试的刷题小程序。https://blog.c…

MOE学习笔记

MOE网络结构 和传统的 transformer 网络结构相比&#xff0c;我们将 Transformer 模型的每个 FFN 层替换为 MoE 层&#xff0c;MoE 层由门网络&#xff08;Router&#xff09;和一定数量的专家&#xff08;Expert&#xff09;组成。 这些 Expert 其实也是 FFN 层&#xff0c;…

LeetCode 算法:二叉树的直径 c++

原题链接&#x1f517;&#xff1a;二叉树的直径 难度&#xff1a;简单⭐️ 题目 给你一棵二叉树的根节点&#xff0c;返回该树的 直径 。 二叉树的 直径 是指树中任意两个节点之间最长路径的 长度 。这条路径可能经过也可能不经过根节点 root 。 两节点之间路径的 长度 由…

审美进阶:7个小程序模板,助你提高设计感!

小程序是一种无需下载和安装即可使用的应用程序。小程序实现了应用程序“触手可及”的梦想。用户可以通过扫描或搜索打开应用程序。对于开发者来说&#xff0c;小程序也大大降低了开发成本。因此&#xff0c;越来越多的品牌争相制作小程序应用程序。本文将为您带来优秀的微信小…

ESP32-S3方案应用设备无线交互技术,产品远程控制与语音交互

在物联网和人工智能(AI)技术融合的浪潮中&#xff0c;ESP32-S3芯片以其卓越的性能和多功能性&#xff0c;成为智能家居和工业自动化领域的明星产品。 ESP32-S3是一款基于Xtensa LX6处理器的嵌入式系统级芯片&#xff0c;具有高效、低功耗的特点。集成的Wi-Fi和蓝牙功能&#x…