【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");
相关推荐
漫漫进阶路1 小时前
VS C++ 配置OPENCV环境
开发语言·c++·opencv
BinaryBardC2 小时前
Swift语言的网络编程
开发语言·后端·golang
code_shenbing2 小时前
基于 WPF 平台使用纯 C# 制作流体动画
开发语言·c#·wpf
邓熙榆2 小时前
Haskell语言的正则表达式
开发语言·后端·golang
大懒猫软件3 小时前
如何运用python爬虫获取大型资讯类网站文章,并同时导出pdf或word格式文本?
python·深度学习·自然语言处理·网络爬虫
ac-er88883 小时前
Yii框架中的队列:如何实现异步操作
android·开发语言·php
马船长3 小时前
青少年CTF练习平台 PHP的后门
开发语言·php
XianxinMao4 小时前
RLHF技术应用探析:从安全任务到高阶能力提升
人工智能·python·算法
hefaxiang4 小时前
【C++】函数重载
开发语言·c++·算法
落幕5 小时前
C语言-构造数据类型
c语言·开发语言