【python因果推断库2】使用 PyMC 模型进行差分-in-差分(Difference in Differences, DID)分析

news2024/12/24 8:32:53

目录

 使用 PyMC 模型进行差分-in-差分(Difference in Differences, DID)分析

导入数据

分析

使用 PyMC 模型建模银行业数据集

导入数据

 分析 1 - 经典 2×2 差分-in-差分 (DiD)

分析 2 - 具有多个干预前后观测值的差分-in-差分 (DiD) 分析 


 使用 PyMC 模型进行差分-in-差分(Difference in Differences, DID)分析

import arviz as az

import causalpy as cp
%load_ext autoreload
%autoreload 2
%config InlineBackend.figure_format = 'retina'
seed = 42

导入数据

df = cp.load_data("did")
df.head()

分析

`random_seed` 这个关键词参数对于 PyMC 采样器来说并不是必需的。我们在这里使用它是为了确保结果是可以重现的。

result = cp.pymc_experiments.DifferenceInDifferences(
    df,
    formula="y ~ 1 + group*post_treatment",
    time_variable_name="t",
    group_variable_name="group",
    model=cp.pymc_models.LinearRegression(sample_kwargs={"random_seed": seed}),
)
fig, ax = result.plot()

result.summary()
===========================Difference in Differences============================
Formula: y ~ 1 + group*post_treatment

Results:
Causal impact = 0.5, $CI_{94\%}$[0.4, 0.6]
Model coefficients:
  Intercept                   	1.1, 94% HDI [1, 1.1]
  post_treatment[T.True]      	0.99, 94% HDI [0.92, 1.1]
  group                       	0.16, 94% HDI [0.094, 0.23]
  group:post_treatment[T.True]	0.5, 94% HDI [0.4, 0.6]
  sigma                       	0.082, 94% HDI [0.066, 0.1]
ax = az.plot_posterior(result.causal_impact, ref_val=0)
ax.set(title="Posterior estimate of causal impact");

使用 PyMC 模型建模银行业数据集

本笔记本分析了来自 Richardson (2009) 的历史银行业关闭数据,并将其作为差分-in-差分分析的一个案例研究,该案例研究来源于优秀的书籍《Mastering Metrics》(Angrist 和 Pischke, 2014)。在这里,我们复制了这项分析,但是使用了贝叶斯推断的方法。

import arviz as az
import pandas as pd

import causalpy as cp
%load_ext autoreload
%autoreload 2
%config InlineBackend.figure_format = 'retina'
seed = 42

导入数据

原始数据集包含一个日期列,这个列中的数字无法直接解读——对于我们分析而言只需要年份列。数据集中还有 `bib6`, `bio6`, `bib8`, `bio8` 这几列。我们知道数字 6 和 8 分别代表第 6 和第 8 联邦储备区。我假设 `bib` 表示“营业中的银行”,所以我们保留这些列。数据是以天为单位的,但我们将把它转换成年为单位。从 Angrist 和 Pischke (2014) 一书中的图 5.2 来看,他们似乎展示了每年营业银行数量的中位数。现在让我们加载数据并执行这些步骤。

df = (
    cp.load_data("banks")
    # just keep columns we want
    .filter(items=["bib6", "bib8", "year"])
    # rename to meaningful variables
    .rename(columns={"bib6": "Sixth District", "bib8": "Eighth District"})
    # reduce from daily resolution to examine median banks open by year
    .groupby("year")
    .median()
)

treatment_time = 1930.5

# set treatment time to zero
df.index = df.index - treatment_time
treatment_time = 0
ax = df[["Sixth District", "Eighth District"]].plot(style="o-")
ax.set(ylabel="Number of banks in business")
ax.axvline(x=treatment_time, c="r", lw=3, label="intervention")
ax.legend();

让我们可视化我们现在得到的数据。这与 Angrist 和 Pischke (2014) 一书中的图 5.2 完全匹配。 

只需几个最后的数据处理步骤,就可以使数据适合于分析。我们将把数据从宽格式转换为长格式。然后我们将添加一个新的列 `treated`,用来指示已经实施处理的观测值。 

df.reset_index(level=0, inplace=True)
df_long = pd.melt(
    df,
    id_vars=["year"],
    value_vars=["Sixth District", "Eighth District"],
    var_name="district",
    value_name="bib",
).sort_values("year")

# We also need to create a column called `unit` which labels each distinct
# unit. In our case we just have two treatment units (each district). So
# we can build a `unit` column from `district`.
df_long["unit"] = df_long["district"]

# We also need to create a `post_treatment` column to define times after
# the intervention.
df_long["post_treatment"] = df_long.year >= treatment_time
df_long

# Dummy coding for district
df_long = df_long.replace({"district": {"Sixth District": 1, "Eighth District": 0}})
df_long

 分析 1 - 经典 2×2 差分-in-差分 (DiD)

首先,我们只分析 1930 年和 1931 年的数据。这样我们就只有一个干预前的测量和一个干预后的测量。

我们将使用公式:`bib ~ 1 + district * post_treatment`,这等价于以下的期望值模型:\begin{aligned}\mu_{i}&=\beta_0\\&+\beta_d\cdot district_i\\&+\beta_p\cdot post\textit{ treatment}_i\\&+\beta_\Delta\cdot district_i\cdot\textit{post treatment}_i\end{aligned}

让我们逐一理解这些内容:

- \mu_{i} 是第 i个观测值的结果(营业中的银行数量)的期望值。
- \beta_{0} 是一个截距项,用来捕捉对照组在干预前营业中银行的基础数量。
- `district` 是一个虚拟变量,所以 \beta_{d} 将代表地区的主要效应,即相对于对照组,处理组的任何偏移量。
- `post_treatment` 也是一个虚拟变量,用来捕捉无论是否接受处理,在处理时间之后结果的任何变化。
- 两个虚拟变量的交互作用 `district:post_treatment` 只会在干预后处理组中取值为 1。因此,\beta_{\Delta} 将代表我们估计的因果效应。

result1 = cp.pymc_experiments.DifferenceInDifferences(
    df_long[df_long.year.isin([-0.5, 0.5])],
    formula="bib ~ 1 + district * post_treatment",
    time_variable_name="post_treatment",
    group_variable_name="district",
    model=cp.pymc_models.LinearRegression(
        sample_kwargs={"target_accept": 0.98, "random_seed": seed}
    ),
)

这里我们遇到了一些发散的情况,这是不好的迹象。这很可能与我们只有4个数据点却有5个参数有关。这对于贝叶斯分析来说并不总是致命的(因为我们有先验分布),不过当我们遇到发散的样本时,这确实是一个警告信号。

使用下面的代码,我们可以看到我们遇到了经典的“漏斗问题”,因为当采样器探索测量误差(即 σ 参数)接近零的值时出现了发散。

az.plot_pair(result1.idata, var_names="~mu", divergences=True);

为了进行“正规”的工作,我们需要解决这些问题以避免出现发散情况,例如,可以尝试探索不同的 σ 参数的先验分布。

fig, ax = result1.plot(round_to=3)

result1.summary()
===========================Difference in Differences============================
Formula: bib ~ 1 + district * post_treatment

Results:
Causal impact = 19, $CI_{94\%}$[15, 22]
Model coefficients:
  Intercept                      	165, 94% HDI [163, 167]
  post_treatment[T.True]         	-33, 94% HDI [-36, -30]
  district                       	-30, 94% HDI [-32, -27]
  district:post_treatment[T.True]	19, 94% HDI [15, 22]
  sigma                          	0.84, 94% HDI [0.085, 2.2]
ax = az.plot_posterior(result1.causal_impact, ref_val=0, round_to=3)
ax.set(title="Posterior estimate of causal impact");

分析 2 - 具有多个干预前后观测值的差分-in-差分 (DiD) 分析 

现在我们将对整个数据集进行差分-in-差分分析。这种方法与{术语}CITS(比较性中断时间序列)具有相似之处,其中涉及单个对照组随时间的变化。虽然这种区分稍微有些武断,但我们根据是否有足够的时间序列数据让CITS能够捕捉时间序列模式来区别这两种技术。

我们将使用公式:`bib ~ 1 + year + district*post_treatment`,这等价于以下的期望值模型:

\begin{aligned} \mu_{i}=& =\beta_{0} \\ &+\beta_y\cdot year_i \\ &+\beta_d\cdot district_i \\ &+\beta_p\cdot post treatment_i \\ &+\beta_\Delta\cdot district_i\cdot post treatment_i \end{aligned}

与上面的经典 2×2 差分-in-差分模型相比,这里唯一的改变是增加了年份的主要效应。因为年份是数值编码的(而不是分类编码),它可以捕捉结果变量随时间发生的任何线性变化。

result2 = cp.pymc_experiments.DifferenceInDifferences(
    df_long,
    formula="bib ~ 1 + year + district*post_treatment",
    time_variable_name="year",
    group_variable_name="district",
    model=cp.pymc_models.LinearRegression(
        sample_kwargs={"target_accept": 0.95, "random_seed": seed}
    ),
)
fig, ax = result2.plot(round_to=3)

result2.summary()
===========================Difference in Differences============================
Formula: bib ~ 1 + year + district*post_treatment

Results:
Causal impact = 20, $CI_{94\%}$[15, 26]
Model coefficients:
  Intercept                      	160, 94% HDI [157, 164]
  post_treatment[T.True]         	-28, 94% HDI [-33, -22]
  year                           	-7.1, 94% HDI [-8.5, -5.7]
  district                       	-29, 94% HDI [-34, -24]
  district:post_treatment[T.True]	20, 94% HDI [15, 26]
  sigma                          	2.4, 94% HDI [1.7, 3.2]

通过观察交互项,它可以捕捉干预措施的因果影响,我们可以看出干预似乎挽救了大约20家银行。尽管对此存在一定的不确定性,但我们可以在下方看到这一影响的完整后验估计。

ax = az.plot_posterior(result2.causal_impact, ref_val=0, round_to=3)
ax.set(title="Posterior estimate of causal impact");

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

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

相关文章

VSCode + Git的常规操作(一)【描述详细直白,小白一学就会】

目录 一、文章简介 二、具体操作流程 1、操作前提 2、设置用户名、用户邮箱 (1)打开命令框 (2)配置用户名 (3)配置用户名邮箱 (4)查看配置 3、SSH密钥对的介绍、生成及配置…

008、架构_MDS

​架构 什么是元数据 什么是元数据 元数据又称中介数据、中继数据,为描述数据的数据,主要是描述数据属性的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能;GoldenDB 数据库元数据大致分为两类: 数据字典:库、表、字段属性信息、视图、函数、存储过程属…

【代码随想录训练营第42期 Day48打卡 - 单调栈 - LeetCode 739. 每日温度 496.下一个更大元素 I 503.下一个更大元素II

目录 一、做题心得 二、题目与题解 题目一:739. 每日温度 题目链接 题解1:暴力--超时 题解2:单调栈 题目二:496.下一个更大元素 I 题目链接 题解:单调栈哈希 题目三:503.下一个更大元素II 题目链…

神经网络训练不起来怎么办(五)| Batch Normalization

Ⅰ,领域背景 训练困境:当 input feature 在不同 dimension 上差距很大的时候,会产生一个非常崎岖的 error surface(误差平面)。这种崎岖多变的误差平面容易导致训练陷入以下的几个困境。 收敛困难:在崎岖…

注释1111

3。3 Batch Normalization (BN) 的工作原理 Batch Normalization 是在处理一个 "批次" 数据时,计算这个批次内所有样本的平均值和方差,然后使用这些统计量对每个样本进行归一化。这就是说: 批次(batch)&a…

局部整体(五)利用python绘制旭日图

局部整体(五)利用python绘制旭日图 旭日图( Sunburst Charts)简介 由于其形状像太阳光由内向外辐射出来,所以叫SunBurst(太阳爆发),中文也叫日出图。是多个层级的环图/饼图的拓展,可以显示多个…

GNU的编译工具链

文章目录 GNU的编译工具链 GNU的编译工具链 预编译器cpp 编译器 cc1 汇编器 as 链接器 ld 其中cpp和cc1属于gcc的一部分,as和ld属于binutils的一部分。

MySQL-如何定位慢查询

慢查询:页面加载过慢,接口压测响应时间过长(超过1s)

STM32基础篇:PWR

PWR简介 PWR(Power Control),为电源控制模块,负责管理STM32内部的电源供电部分,可以实现可编程电压监测器和低功耗模式的功能。 1、可编程电压监测器 简称PVD,可以监控VDD电源电压。当VDD下降到PVD阀值以…

yum安装nexus3详细教程分享

创建nexus用户,类似于这种中间件,尽量做到专户管理,当然如果你喜欢直接用root权限安装,更改配置文件也是可以支持的。但是实际上大多情况下,在生产环境是拿不到root权限的。 useradd -m nexus为nexus用户设置密码 pass…

AS-V1000视频监控平台客户端播放实时视频时,一些视频画面显示的时间不准确的解决方法

目录 一、背景说明 二、解决过程 1、查看设备时间 2、查看服务器时间 3、ntp介绍 1) ntp的概念 2) ntp的同步方式 3) ntp的优势 4、自动校准服务器和设备时间 1) 下载ntp 2) 修改ntp.conf 3) 重启ntp服务,自动校准时间 4) 国标重新接入设备自动同步时间 三、问题解…

zStorage在海光CPU架构上的性能调优

前言 随着"信创"的东风吹遍大江南北,各家公司都开始了国产化的适配道路。zStorage团队当然也没有缺席,去年我们适配了华为的鲲鹏架构,整体性能水平达到了Intel架构的70%以上。今年我们开始着力于海光CPU架构的适配。与鲲鹏架构相比…

【linux学习指南】权限管理与文件访问设置方法

文章目录 📝前言🌠 bc指令🌉uname –r指令 🌠重要的几个热键[Tab],[ctrl]-c, [ctrl]-d🌉关机 🌠命令扩展🌉shell命令以及运行原理 🌠Linux权限的概念🌠 Linux权限管理&am…

善用工具:开发与效率

文章目录 常用工具Visual Studio Code(VS Code)GitDockerPostman 效率对比VS Code 与 Sublime TextGit 与 SVNDocker 与虚拟机Postman 与 cURL 近来趋势人工智能与编程工具的结合低代码与无代码平台版本控制的演进准备自适应的开发环境与新兴技术的整合 …

Linux驱动(三):字符设备驱动之杂项

目录 一、Linux设备分类二、设备号与字符设备的编码方式1.设备号2.字符设备的编码方式 三、杂项字符设备驱动的初级编写 一、Linux设备分类 Linux下一切皆文件,所有的硬件设备在Linux应用层中都会被抽象成文件,所有对硬件设备的操作到应用层中&#xff0…

电脑垃圾箱删除的东西怎么找回来?介绍四个有效方法

在日常使用电脑的过程中,‌我们可能会不小心删除一些重要文件,‌而这些文件往往会被放入垃圾箱(‌回收站)‌。‌但有时候,‌我们可能会清空垃圾箱,‌导致这些文件看似永久丢失。‌其实,‌即使垃…

RFID光触发标签在汽车制造行业的深度应用

汽车制造行业作为现代工业的重要支柱,面临着日益激烈的市场竞争和不断提高的客户需求。传统的汽车制造管理方式在生产过程监控、零部件管理、质量追溯等方面存在诸多不足,而 RFID 光触发标签技术的出现为汽车制造行业的转型升级提供了有力的解决方案。 …

用友大易:以AI创新驱动招聘未来,引领2024 AIGC商业新趋势

更多内容前往个人网站:孔乙己大叔 在科技日新月异的今天,人工智能(AI)正以前所未有的速度渗透并重塑各行各业,其中,企业招聘领域也不例外。8月22日,由创业邦及2024 AGI商业趋势大会组委会主办的…

Mysql基础练习题 610.判断三角形 (力扣)

题目: 对每三个线段报告它们是否可以形成一个三角形 题目连接: https://leetcode.cn/problems/triangle-judgement/description/ 建表插入数据: Create table If Not Exists Triangle (x int, y int, z int) Truncate table Triangle in…

综合评价 | 基于层次-熵权-博弈组合法的综合评价模型(Matlab)

目录 效果一览基本介绍程序设计参考资料 效果一览 基本介绍 AHP层次分析法是一种解决多目标复杂问题的定性和定量相结合进行计算决策权重的研究方法。该方法将定量分析与定性分析结合起来,用决策者的经验判断各衡量目标之间能否实现的标准之间的相对重要程度&#…