【因果推断python】44_评估因果模型2

2024-06-20 05:28

本文主要是介绍【因果推断python】44_评估因果模型2,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

累积弹性曲线

累积增益曲线

考虑差异

关键思想


累积弹性曲线

再次考虑将价格转换为二元处理的说明性示例。我们会从我们离开的地方拿走它,所以我们有弹性处理带。我们接下来可以做的是根据乐队的敏感程度对乐队进行排序。也就是说,我们把最敏感的组放在第一位,第二个最敏感的组放在第二位,依此类推。对于模型 1 和 3,无需重新订购,因为它们已经订购。对于模型 2,我们必须颠倒排序。

一旦我们有了有序的组,我们就可以构建我们称之为累积弹性曲线的东西。我们首先计算第一组的弹性;然后,第一个和第二个等等,直到我们包含所有组。最后,我们将只计算整个数据集的弹性。这是我们的说明性示例的外观。

img

请注意,累积弹性中的第一个 bin 只是根据该模型来自最敏感组的 ATE。此外,对于所有模型,累积弹性将收敛到同一点,即整个数据集的 ATE。

在数学上,我们可以将累积弹性定义为直到单位 k 之前估计的弹性。\widehat{y^{\prime}(t)}_k=\hat{\beta}_{1k}=\frac{\sum_i^k(t_i-\bar{t})(y_i-\bar{y})}{\sum_i^k(t_i-\bar{t})^2}

为了构建累积弹性曲线,我们在数据集中迭代地运行上述函数以产生以下序列。\widehat{(y^{\prime}(t)_1,\widehat{y^{\prime}(t)_2},\widehat{y^{\prime}(t)_3},\ldots,\widehat{y^{\prime}(t)_N})}

就模型评估而言,这是一个非常有趣的序列,因为我们可以对其进行偏好陈述。首先,模型更好的程度

\hat{y}'(t)k > \hat{y}'(t){k+a}

对于任何 k 和 a>0。换句话说,如果一个模型擅长对弹性进行排序,那么在前 k个样本中观察到的弹性应该高于在前 k+a 个样本中观察到的弹性。或者,简单地说,如果我查看顶部单位,它们应该比它们下面的单位具有更高的弹性。

其次,模型更好的程度

\hat{y}'(t)k - \hat{y}'(t){k+a}

是最大的,对于任何 k 和 a>0。直觉是,我们不仅希望顶部 k 单位的弹性高于其下方单位的弹性,而且我们希望这种差异尽可能大。

为了使其更具体,这是用代码表示的这个想法。

def cumulative_elast_curve(dataset, prediction, y, t, min_periods=30, steps=100):size = dataset.shape[0]# orders the dataset by the `prediction` columnordered_df = dataset.sort_values(prediction, ascending=False).reset_index(drop=True)# create a sequence of row numbers that will define our Ks# The last item is the sequence is all the rows (the size of the dataset)n_rows = list(range(min_periods, size, size // steps)) + [size]# cumulative computes the elasticity. First for the top min_periods units.# then for the top (min_periods + step*1), then (min_periods + step*2) and so onreturn np.array([elast(ordered_df.head(rows), y, t) for rows in n_rows])

关于此功能的一些注意事项。 它假定对弹性进行排序的事物存储在传递给“预测”参数的列中。 此外,第一组有 min_periods 单位,因此它可以与其他组不同。 原因是,由于样本量小,弹性在曲线开始时可能过于嘈杂。 为了解决这个问题,我们可以传递一个已经足够大的第一组。 最后,steps 参数定义了我们在每个后续组中包含多少额外单元。

使用此功能,我们现在可以根据每个模型产生的顺序绘制累积弹性曲线。

plt.figure(figsize=(10,6))for m in range(3):cumu_elast = cumulative_elast_curve(prices_rnd_pred, f"m{m+1}_pred", "sales", "price", min_periods=100, steps=100)x = np.array(range(len(cumu_elast)))plt.plot(x/x.max(), cumu_elast, label=f"M{m+1}")plt.hlines(elast(prices_rnd_pred, "sales", "price"), 0, 1, linestyles="--", color="black", label="Avg. Elast.")
plt.xlabel("% of Top Elast. Days")
plt.ylabel("Cumulative Elasticity")
plt.title("Cumulative Elasticity Curve")
plt.legend();

解释累积弹性曲线可能有点挑战性,但这是我的看法。同样,考虑二分类情况可能更容易。曲线的 X 轴代表我们正在处理的样本数量。在这里,我将轴归一化为数据集的比例,所以 0.4 意味着我们正在处理 40% 的样本。 Y 轴是我们在这么多样本上应该预期的弹性。因此,如果一条曲线在 40% 处的值为 -1,则意味着前 40% 单位的弹性为 -1。理想情况下,我们希望尽可能大的样本具有最高的弹性。理想的曲线将在 Y 轴上从高处开始,然后非常缓慢地下降到平均弹性,这表示我们可以处理高百分比的单位,同时仍保持高于平均弹性。

不用说,我们的模型都没有接近理想的弹性曲线。随机模型 M3 围绕平均弹性波动,并且永远不会离它太远。这意味着该模型无法找到弹性与平均弹性不同的组。至于预测模型 M1,它似乎是反向排序的弹性,因为曲线从低于平均弹性开始。不仅如此,它还在大约 50% 的样本处很快收敛到平均弹性。最后,因果模型 M2 似乎更有趣。一开始它有这种奇怪的行为,累积弹性增加远离平均值,但随后它达到了一个点,我们可以处理大约 75% 的单位,同时保持几乎为 0 的相当不错的弹性。这可能是因为这个模型可以识别非常低弹性(高价格敏感度)的日子。因此,如果我们在那些日子不提价,我们可以对大部分样本(约 75%)进行提价,同时价格敏感度仍然较低。

在模型评估方面,累积弹性曲线(Cumulative Elasticity Curve) 已经远远好于简单的分区间的弹性概念。在这里,我们设法对我们的模型做出更精确的偏好陈述。不过,这是一条复杂的曲线,难以理解。出于这个原因,我们可以做进一步的改进。

累积增益曲线

下一个想法是在累积弹性之上进行非常简单但强大的改进。我们将累积弹性乘以比例样本量。例如,如果累积弹性在 40% 时为 -0.5,那么此时我们将得到 -0.2 (-0.5 * 0.4)。然后,我们将其与随机模型产生的理论曲线进行比较。这条曲线实际上是一条从 0 到平均干预效果的直线。可以这样想:随机模型的累积弹性中的每个点都是 ATE,因为该模型只生成数据的随机代表性分区。如果在 (0,1) 线上的每一点,我们将 ATE 乘以该点,我们最终会得到一条介于 0 和 ATE 之间的直线。

img

一旦我们有了理论上的随机曲线,我们就可以将其用作基准,并将我们的其他模型与它进行比较。所有曲线将在同一点开始和结束。然而,模型的弹性排序越好,曲线在零到一之间的点处偏离随机线的程度就越大。例如,在上图中,M2 优于 M1,因为它在到达终点 ATE 之前发散得更多。对于熟悉 ROC 曲线的人,您可以将累积增益视为因果模型的 ROC。

从数学上讲,

\widehat{F(t)}_k=\hat{\beta}_{1k}*\frac kN=\frac{\sum_i^k(t_i-\bar{t})(y_i-\bar{y})}{\sum_i^k(t_i-\bar{t})^2}*\frac kN

要在代码中实现它,我们所要做的就是添加比例样本大小归一化。

def cumulative_gain(dataset, prediction, y, t, min_periods=30, steps=100):size = dataset.shape[0]ordered_df = dataset.sort_values(prediction, ascending=False).reset_index(drop=True)n_rows = list(range(min_periods, size, size // steps)) + [size]## add (rows/size) as a normalizer. return np.array([elast(ordered_df.head(rows), y, t) * (rows/size) for rows in n_rows])

 使用我们的冰激凌数据,我们会得到如下曲线。

plt.figure(figsize=(10,6))for m in range(3):cumu_gain = cumulative_gain(prices_rnd_pred, f"m{m+1}_pred", "sales", "price", min_periods=50, steps=100)x = np.array(range(len(cumu_gain)))plt.plot(x/x.max(), cumu_gain, label=f"M{m+1}")plt.plot([0, 1], [0, elast(prices_rnd_pred, "sales", "price")], linestyle="--", label="Random Model", color="black")plt.xlabel("% of Top Elast. Days")
plt.ylabel("Cumulative Gain")
plt.title("Cumulative Gain")
plt.legend();

现在很清楚,因果模型(M2)比其他两个要好得多。它与随机线的差异远大于 M1 和 M3。此外,请注意随机模型 M3 如何非常接近理论随机模型。两者之间的区别可能只是随机噪声。

有了这个,我们介绍了一些关于如何评估因果模型的非常好的想法。仅此一项就是一件大事。即使我们没有要比较的基本事实,我们也设法评估了模型在排序弹性方面的好坏。只缺少最后一件事,即包括围绕这些测量值的置信区间。毕竟,我们不是野蛮人,不是吗?

考虑差异

当我们处理弹性曲线时,不考虑方差是错误的。特别是由于它们都使用线性回归理论,因此在它们周围添加置信区间应该相当容易。

为此,我们将首先创建一个函数,该函数返回线性回归参数的 CI。我在这里使用简单线性回归的公式,但可以随意提取 CI。s_{\hat{\beta}_1}=\sqrt{\frac{\sum_i\hat{\epsilon}_i^2}{(n-2)\sum_i(t_i-\bar{t})^2}}

def elast_ci(df, y, t, z=1.96):n = df.shape[0]t_bar = df[t].mean()beta1 = elast(df, y, t)beta0 = df[y].mean() - beta1 * t_bare = df[y] - (beta0 + beta1*df[t])se = np.sqrt(((1/(n-2))*np.sum(e**2))/np.sum((df[t]-t_bar)**2))return np.array([beta1 - z*se, beta1 + z*se])

通过对我们的cumulative_elast_curve函数进行一些小的修改,我们可以输出弹性的置信区间。

def cumulative_elast_curve_ci(dataset, prediction, y, t, min_periods=30, steps=100):size = dataset.shape[0]ordered_df = dataset.sort_values(prediction, ascending=False).reset_index(drop=True)n_rows = list(range(min_periods, size, size // steps)) + [size]# just replacing a call to `elast` by a call to `elast_ci`return np.array([elast_ci(ordered_df.head(rows), y, t)  for rows in n_rows])

最后,这是因果 (M2) 模型的 95% CI 的累积弹性曲线。

plt.figure(figsize=(10,6))cumu_gain_ci = cumulative_elast_curve_ci(prices_rnd_pred, "m2_pred", "sales", "price", min_periods=50, steps=200)
x = np.array(range(len(cumu_gain_ci)))
plt.plot(x/x.max(), cumu_gain_ci, color="C0")plt.hlines(elast(prices_rnd_pred, "sales", "price"), 0, 1, linestyles="--", color="black", label="Avg. Elast.")plt.xlabel("% of Top Elast. Days")
plt.ylabel("Cumulative Elasticity")
plt.title("Cumulative Elasticity for M2 with 95% CI")
plt.legend();

注意随着我们积累更多的数据集,CI 是如何变得越来越小的。 那是因为样本量增加了。

至于累积增益曲线,获取 CI 也同样简单。 同样,我们只是将调用 elast 函数替换为调用 elast_ci 函数。

def cumulative_gain_ci(dataset, prediction, y, t, min_periods=30, steps=100):size = dataset.shape[0]ordered_df = dataset.sort_values(prediction, ascending=False).reset_index(drop=True)n_rows = list(range(min_periods, size, size // steps)) + [size]return np.array([elast_ci(ordered_df.head(rows), y, t) * (rows/size) for rows in n_rows])

这是因果模型的样子。 请注意,现在 CI 开始时很小,即使曲线开始时的样本量较小。 原因是归一化因子 \frac{k}{N} 回避了 ATE 参数,并且它是 CI。 由于这条曲线应该用于比较模型,所以这应该不是问题,因为曲线会将这个推卸因子平等地应用于所有正在评估的模型。

plt.figure(figsize=(10,6))cumu_gain = cumulative_gain_ci(prices_rnd_pred, "m2_pred", "sales", "price", min_periods=50, steps=200)
x = np.array(range(len(cumu_gain)))
plt.plot(x/x.max(), cumu_gain, color="C0")plt.plot([0, 1], [0, elast(prices_rnd_pred, "sales", "price")], linestyle="--", label="Random Model", color="black")plt.xlabel("% of Top Elast. Days")
plt.ylabel("Cumulative Gain")
plt.title("Cumulative Gain for M2 with 95% CI")
plt.legend();

关键思想

在这里,我们看到了三种方法来检查模型在排序弹性方面的好坏。我们使用这些方法来比较和决定具有因果关系的模型。这是非常重要的。我们已经设法检查了一个模型是否擅长识别具有不同弹性的组,即使无法看到弹性!

在这里,我们严重依赖随机数据。我们在非随机数据上训练了模型,但所有评估都是在随机处理的样本上完成的。那是因为我们需要某种方法来自信地估计弹性。如果没有随机数据,我们在这里使用的简单公式将不起作用。正如我们现在非常清楚的那样,简单的线性回归在存在混杂变量的情况下忽略了变量偏差。

这篇关于【因果推断python】44_评估因果模型2的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1077227

相关文章

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

使用Python实现快速搭建本地HTTP服务器

《使用Python实现快速搭建本地HTTP服务器》:本文主要介绍如何使用Python快速搭建本地HTTP服务器,轻松实现一键HTTP文件共享,同时结合二维码技术,让访问更简单,感兴趣的小伙伴可以了... 目录1. 概述2. 快速搭建 HTTP 文件共享服务2.1 核心思路2.2 代码实现2.3 代码解读3.

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

Java的IO模型、Netty原理解析

《Java的IO模型、Netty原理解析》Java的I/O是以流的方式进行数据输入输出的,Java的类库涉及很多领域的IO内容:标准的输入输出,文件的操作、网络上的数据传输流、字符串流、对象流等,这篇... 目录1.什么是IO2.同步与异步、阻塞与非阻塞3.三种IO模型BIO(blocking I/O)NI

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤