【python因果推断库16】使用 PyMC 模型进行回归拐点设计

目录

[例子 1 - 连续分段线性函数](#例子 1 - 连续分段线性函数)


python 复制代码
import arviz as az
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

import causalpy as cp
%load_ext autoreload
%autoreload 2
%config InlineBackend.figure_format = 'retina'
seed = 42
rng = np.random.default_rng(seed)

回归拐点设计应当通过分段连续函数来进行分析。具体来说:

  • 我们想要一个函数能够捕捉拐点左边和右边的数据。
  • 我们想要一个具有一个断点或拐点的分段函数。
  • 该函数应在拐点处连续。

一个这样的函数的例子是一个分段连续多项式:

其中:

  • 是未知参数,

  • x 是连续变量,

  • t 是一个指示变量,如果 x>=k 则取值为1,否则为 0

  • k 是 x 在拐点处的值。

我们可以通过绘制一系列随机选择的 系数的函数图像来直观地展示这些函数的样子,但所有这些函数都具有相同的拐点在0.5。

python 复制代码
def f(x, beta, kink):
    return (
        beta[0]
        + beta[1] * x
        + beta[2] * x**2
        + beta[3] * (x - kink) * (x >= kink)
        + beta[4] * (x - kink) ** 2 * (x >= kink)
    )


def gradient_change(beta, kink, epsilon=0.01):
    gradient_left = (f(kink, beta, kink) - f(kink - epsilon, beta, kink)) / epsilon
    gradient_right = (f(kink + epsilon, beta, kink) - f(kink, beta, kink)) / epsilon
    gradient_change = gradient_right - gradient_left
    return gradient_change


x = np.linspace(-1, 1, 1000)
kink = 0.5
cols = 5

fig, ax = plt.subplots(2, cols, sharex=True, sharey=True, figsize=(15, 5))

for col in range(cols):
    beta = rng.random(5)
    ax[0, col].plot(x, f(x, beta, kink), lw=3)
    ax[1, col].plot(x, np.gradient(f(x, beta, kink), x), lw=3)
    ax[0, col].set(title=f"Random  {col+1}")
    ax[1, col].set(xlabel="x")

ax[0, 0].set(ylabel="$y = f(x)$")
ax[1, 0].set(ylabel=r"$\frac{dy}{dx}$");

回归拐点分析的思想是拟合一个合适的函数到数据上,并估计在拐点处函数梯度是否有变化。

下面我们将生成一些数据集并演示如何进行回归拐点分析。我们将使用一个函数来生成具有所需特性的模拟数据集。

python 复制代码
def generate_data(beta, kink, sigma=0.05, N=50):
    if beta is None:
        beta = rng.random(5)
    x = rng.uniform(-1, 1, N)
    y = f(x, beta, kink) + rng.normal(0, sigma, N)
    df = pd.DataFrame({"x": x, "y": y, "treated": x >= kink})
    return df

例子 1 - 连续分段线性函数

在这个例子中,我们将坚持使用一个简单的连续分段函数。

python 复制代码
kink = 0.5
# linear function with gradient change of 2 at kink point
beta = [0, -1, 0, 2, 0]
sigma = 0.05
df = generate_data(beta, kink, sigma=sigma)

fig, ax = plt.subplots()
ax.scatter(df["x"], df["y"], alpha=0.5)
ax.axvline(kink, color="red", linestyle="--")
ax.set(title=f"Change in gradient at kink point: {gradient_change(beta, kink):.2f}");

我们可以使用常规的 cp.pymc_models.LinearRegression 模型,并通过巧妙地通过 formula 输入指定设计矩阵来强制执行连续分段特性。

在这个例子中,将公式设置为 "y ~ 1 + x + I((x-0.5)*treated)"(其中 0.5 是拐点)等同于以下模型:

拐点两侧的梯度变化是通过数值方法评估的。epsilon 参数决定了用于计算梯度变化的拐点两侧的距离。

python 复制代码
result1 = cp.pymc_experiments.RegressionKink(
    df,
    formula=f"y ~ 1 + x + I((x-{kink})*treated)",
    model=cp.pymc_models.LinearRegression(sample_kwargs={"random_seed": seed}),
    kink_point=kink,
    epsilon=0.1,
)

fig, ax = result1.plot()

如果你想绘制推断出的梯度变化的后验分布,你可以按照以下方式进行。

python 复制代码
ax = az.plot_posterior(result1.gradient_change, ref_val=gradient_change(beta, kink))
ax.set(title="Gradient change");
相关推荐
尘浮生5 分钟前
Java项目实战II基于微信小程序的电影院买票选座系统(开发文档+数据库+源码)
java·开发语言·数据库·微信小程序·小程序·maven·intellij-idea
hopetomorrow19 分钟前
学习路之PHP--使用GROUP BY 发生错误 SELECT list is not in GROUP BY clause .......... 解决
开发语言·学习·php
小牛itbull29 分钟前
ReactPress vs VuePress vs WordPress
开发语言·javascript·reactpress
请叫我欧皇i37 分钟前
html本地离线引入vant和vue2(详细步骤)
开发语言·前端·javascript
nuclear201140 分钟前
使用Python 在Excel中创建和取消数据分组 - 详解
python·excel数据分组·创建excel分组·excel分类汇总·excel嵌套分组·excel大纲级别·取消excel分组
闲暇部落40 分钟前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
GIS瞧葩菜1 小时前
局部修改3dtiles子模型的位置。
开发语言·javascript·ecmascript
chnming19871 小时前
STL关联式容器之set
开发语言·c++
Lucky小小吴1 小时前
有关django、python版本、sqlite3版本冲突问题
python·django·sqlite
熬夜学编程的小王1 小时前
【C++篇】深度解析 C++ List 容器:底层设计与实现揭秘
开发语言·数据结构·c++·stl·list