【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");
相关推荐
YFJ_mily3 分钟前
**Python 实战:写一个论文 PDF 投稿自检工具|附 IPAT 2026 智能光子学会议征稿信息
人工智能·python·pdf·量子计算·论文投稿·智能光子学
三川6984 分钟前
Tkinter库的学习记录05-文本框Entry
python
cui_ruicheng9 分钟前
Python从入门到实战(八):封装、多态与抽象类
开发语言·python
apihz10 分钟前
台风实时与历史详情查询免费 API 接口完整教程
android·开发语言·tcp/ip·dubbo·台风·天气预报
知无不研24 分钟前
c语言和c++中的静态关键字
开发语言·c++·静态关键字
bksczm39 分钟前
Linux之信号量(POSIX标准)
java·开发语言
吠品1 小时前
PHP里取月份最后一天的几种方式
java·开发语言·eureka
CallmeFoureyes1 小时前
使用 C# 提取 Word 文档中的表格数据
开发语言·c#·word
GEO_ai_zhijian1 小时前
饮料生产线质量检测系统哪家好
大数据·人工智能·python
精神底层1 小时前
拒绝 UI 卡死!我用 CSnakes 实时拦截 Python 训练流,在 WPF 中重构了 ScottPlot 5 高性能 AI 看板
python·ui·wpf