👇 连享会 · 推文导航 | www.lianxh.cn
🍓 连享会 · 2026 社会网络分析专题
嘉宾:杨张博 (西安交通大学)
时间:2026 年 8 月 18-19 日
咨询:王老师 18903405450(微信)

社会网络分析痛点:
课程结合理论讲解、模型实操(R 和 Codebuddy)与研究复现,帮助学员系统掌握社会网络分析的方法与工具,提升在实证研究中的应用能力。
课程特色:
作者:郭皑馨 (华南理工大学)
邮箱:valerie_guo@163.com[1]
reghdfe, fixest, DID, 事件研究如果你在 Stata 中习惯了 reghdfe,转到 Python 后最麻烦的往往不是不会做回归,而是同一个模型要拆成数据处理、虚拟变量、协方差设定和结果输出等多段代码。R 用户也有类似感受:fixest 的公式很紧凑,换到 Python 后却未必能找到完全对应的写法。
PyFixest 解决的正是这个问题。它借鉴 R 语言 fixest 的公式接口,把普通最小二乘、高维固定效应、聚类标准误和部分 DID 估计量放进较统一的语法体系。对 Stata 用户而言,最直观的对应关系是:reghdfe 中的 absorb() 被写到公式竖线 | 之后,vce(cluster ...) 则由 vcov 参数指定。
不过,命令相似不等于研究设计自动成立。固定效应吸收了什么、标准误应在哪一层聚类、交错处理下估计的究竟是哪一个 ATT,仍需研究者自行判断。本文因此不只列出命令,还把 PyFixest 语法与相应的计量模型逐项对照。
PyFixest 的核心函数是 feols()。其基本写法为:
model = pf.feols(
"y ~ x1 + x2 | fe1 + fe2",
data=df,
vcov={"CRV1": "cluster_id"},
)这段代码同时交代了三个问题:估计哪个方程、吸收哪些固定效应、标准误按什么层级聚类。它对应的线性模型为:
其中, 对应公式左侧的 y, 对应 x1 + x2,个体固定效应 与时间固定效应 对应 fe1 + fe2。vcov={"CRV1": "cluster_id"} 不改变 ,但会改变标准误、置信区间和显著性判断。
fixest 和 reghdfe 的关系PyFixest 的目标是尽量贴近 R fixest 的语法和功能,而不是机械复制某一个软件。它目前覆盖 OLS、WLS、IV、带高维固定效应的广义线性模型、分位数回归,以及 TWFE、DID2S、LP-DID 和 Sun-Abraham 事件研究等功能。本文集中介绍实证研究中最常用的两部分:固定效应回归和 DID。
需要说明的是,不能把“语法相似”写成“任何情况下都与 Stata 数值完全一致”。只有在样本筛选、缺失值处理、单例组删除、权重、小样本修正和聚类层级均一致时,系数和标准误才具有可比性。软件之间若采用不同默认值,最后几位数字甚至推断结果都可能不同。
以双向固定效应模型为例:
PyFixest 将它写成:
pf.feols(
"Y ~ X1 + X2 | id + year",
data=df,
vcov={"CRV1": "id"},
)各部分的对应关系如下。
Y | ||
X1 + X2 | ||
id | ||
year | ||
vcov={"CRV1": "id"} |
这几种写法并不是三套不同的方法,而是同一个估计问题的不同表达。公式说明模型中有哪些变量和固定效应;"Y ~ X1 + X2 | id + year" 把这个模型翻译成 PyFixest 能够识别的语法;vcov 则位于模型公式之外,只负责统计推断。换句话说,| id + year 决定“估计哪个模型”,vcov={"CRV1": "id"} 决定“怎样计算这个模型的标准误”。
对于单向个体固定效应模型,组内变换可写为:
因此,| id 的含义不是“额外控制一个名为 id 的连续变量”,而是吸收每个个体不随时间变化的截距。系数 主要由个体内部随时间变化的 识别。若某个变量在个体内完全不变,例如性别或出生地,它会与个体固定效应共线,无法单独估计。
双向固定效应进一步吸收每个时期共同经历的冲击。在平衡面板中,可以用双向去均值直观表示这一过程。对于任意变量 ,定义:
于是,原来的双向固定效应模型可以写成:
这里的 和 已同时剔除个体均值与时期均值,并加回总体均值。feols("Y ~ X | id + year") 所做的核心工作,就是在不显式生成成百上千个虚拟变量的情况下完成这类残差化运算,再利用剩余变动估计 。对于非平衡面板或多个高维固定效应,软件会通过迭代去均值等算法完成相应投影,而不是机械套用一次双向去均值公式。
| id + year 回答“模型吸收哪些系统性差异”,vcov={"CRV1": "id"} 回答“误差项允许在哪些观测之间相关”。二者不能相互替代。
若同一个体的误差项具有序列相关,在个体层面聚类通常比使用异方差稳健标准误更合适。其一般形式可写为:
其中, 表示聚类组, 和 分别表示吸收固定效应后的组内设计矩阵与残差。式中允许同一组内的误差相关,但仍依赖不同聚类组之间近似独立。聚类层级应由处理分配和误差相关结构决定,不能因为某种写法更容易得到显著结果而临时更换。
截至 2026 年 8 月,PyPI 上的稳定版为 0.60.0,要求 Python 3.10 或更高版本。建议在已有虚拟环境中安装,并记录实际版本:
# 安装或升级 PyPI 稳定版
python -m pip install -U pyfixestimport pyfixest as pf
# 记录版本,便于后续复现
print(pf.__version__)若项目需要长期复现,最好在 requirements.txt 中锁定版本:
pyfixest==0.60.0下面的对照以 PyFixest 0.60.0 为准。
reg y x1 x2pf.feols("y ~ x1 + x2", data=df)reg y x1 x2, vce(robust)pf.feols("y ~ x1 + x2", data=df, vcov="HC1")reghdfe y x, absorb(id) vce(cluster id)pf.feols("y ~ x \| id", data=df, vcov={"CRV1": "id"})reghdfe y x, absorb(id year) vce(cluster id)pf.feols("y ~ x \| id + year", data=df, vcov={"CRV1": "id"})reghdfe y x, absorb(province#year)pf.feols("y ~ x \| province^year", data=df)reghdfe y x, absorb(id year) vce(cluster id year)pf.feols("y ~ x \| id + year", data=df, vcov={"CRV1": "id+year"})在 PyFixest 公式中,~ 左侧只能放因变量,右侧放需要报告系数的解释变量;| 后面放要吸收的固定效应。聚类标准误不写在公式内部,而由 vcov 单独指定。
估计完成后,Feols 对象既可以打印回归结果,也可以把系数和标准误交给后续的数据处理流程。
# 估计模型
m = pf.feols(
"y ~ x1 + x2 | id + year",
data=df,
vcov={"CRV1": "id"},
)
# 查看完整回归结果
m.summary()
# 提取系数、标准误和整洁格式结果
coef = m.coef()
se = m.se()
tidy_result = m.tidy()
# 生成多个模型的对比表
pf.etable([m])这里应区分“面向读者的回归表”和“面向程序的结果对象”。summary()、etable() 适合检查和展示,coef()、se()、tidy() 更适合继续制图、检验或批量整理。
下面使用 linearmodels 项目提供的工资面板数据。样本包含 545 名劳动者在 1980-1987 年间的 4,360 条观测。因变量 lwage 为对数工资,主要解释变量包括工作经验平方、工会会员状态、婚姻状态和工时。
我们比较两个模型:
Model 1:
$$lwage_{it} = \beta_{1}expersq_{it}+\beta_{2}union_{it}+\beta_{3}married_{it}+\beta_{4}hours_{it} \
+\alpha_{i}+\varepsilon_{it}$$
Model 2:
$$lwage_{it} = \beta_{1}expersq_{it}+\beta_{2}union_{it}+\beta_{3}married_{it}+\beta_{4}hours_{it} \
+\alpha_{i}+\lambda_{t}+\varepsilon_{it}$$
模型 1 只吸收个体固定效应,模型 2 进一步吸收年份固定效应。两者都在个体层面聚类。这样设定的目的,是把“加入年份固定效应带来的变化”与“更换聚类方式带来的变化”分开。
下面的代码完成数据读取、模型估计和回归表输出。
import pandas as pd
import pyfixest as pf
# 读取公开的工资面板数据
data_url = (
"https://raw.githubusercontent.com/bashtage/linearmodels/"
"main/linearmodels/datasets/wage_panel/wage_panel.csv.bz2"
)
data_df = pd.read_csv(data_url)
# 模型 1:个体固定效应,标准误在个体层面聚类
m1 = pf.feols(
"lwage ~ expersq + union + married + hours | nr",
data=data_df,
vcov={"CRV1": "nr"},
)
# 模型 2:个体和年份固定效应,仍在个体层面聚类
m2 = pf.feols(
"lwage ~ expersq + union + married + hours | nr + year",
data=data_df,
vcov={"CRV1": "nr"},
)
# 输出 Markdown 回归表
pf.etable(
[m1, m2],
type="md",
signif_code=[0.01, 0.05, 0.10],
)在 PyFixest 0.60.0 下,核心结果如下。括号内为按劳动者聚类的标准误。
expersq | ||
union | ||
married | ||
hours | ||
模型 2 中,union 的系数为 0.0727。由于因变量是对数工资,近似解释是:同一劳动者在控制年份共同冲击后,工会会员状态与工资约 7.3% 的差异相关。使用精确换算,。
这里不宜直接写成“加入工会使工资提高 7.5%”。个体固定效应只能消除不随时间变化的个体异质性;若加入工会仍与同期未观测冲击相关, 仍可能存在内生性偏误。
expersq 在加入年份固定效应后由正转负,说明经验平方与共同时间趋势之间存在较强关联。这个变化不是软件造成的,而是模型识别来源发生了变化。模型 2 主要利用“相对于同年其他劳动者的个体内变化”识别系数。
还要区分总 与 Within 。总 包含固定效应解释的变异,而 Within 只衡量解释变量对剔除固定效应后剩余变异的解释能力。高维固定效应模型的总 很高,并不意味着核心解释变量具有很强的边际解释力。
最常见的静态 TWFE 回归为:
其中, 表示单元 在时期 已接受处理。对应的 PyFixest 写法是:
fit_twfe = pf.feols(
"dep_var ~ i(treat) | unit + year",
data=df_het,
vcov={"CRV1": "state"},
)若所有处理组在同一时期接受处理,并且平行趋势等识别条件成立, 可以对应熟悉的 DID 处理效应。若处理时点交错,且处理效应随队列或事件时间变化,TWFE 系数则可能混合多种二乘二比较,未必等于研究者想要的 ATT。
因此,估计前至少要检查三个变量:个体标识 unit、日历时间 year 和首次处理时间 g。不能只看到数据中有一个 treat 虚拟变量,就直接套用 TWFE。
DID2S 的直观思路是把固定效应和处理效应分两步估计。第一步只利用未处理观测估计反事实结果:
得到 和 后,构造残差化结果:
再用第二阶段估计处理效应:
did2s() 中的 first_stage="~ 0 | unit + year" 与 second_stage="~ i(treat)",正好对应上面两步。
LP-DID 更适合关心动态效应的场景。它按事件时间 估计:
并使用尚未处理或从未处理的“干净对照组”构造比较。lpdid() 中的 pre_window 和 post_window 决定报告哪些处理前后时期,att=True 则要求将动态效应进一步汇总为一个总体 ATT。
PyFixest 已内置交错处理示例数据。使用包内数据比依赖外部下载链接更稳定。
from importlib import resources
import pandas as pd
import pyfixest as pf
# 读取 PyFixest 自带的交错处理模拟数据
data_path = resources.files("pyfixest.did.data").joinpath("df_het.csv")
df_het = pd.read_csv(data_path)
# 估计量 1:静态 TWFE
fit_twfe = pf.feols(
"dep_var ~ i(treat) | unit + year",
data=df_het,
vcov={"CRV1": "state"},
)
# 估计量 2:Gardner 两阶段 DID
fit_did2s = pf.did2s(
data=df_het,
yname="dep_var",
first_stage="~ 0 | unit + year",
second_stage="~ i(treat)",
treatment="treat",
cluster="state",
)
# 估计量 3:Local Projections DID,并汇总总体 ATT
fit_lpdid = pf.lpdid(
data=df_het,
yname="dep_var",
gname="g",
tname="year",
idname="unit",
vcov={"CRV1": "state"},
pre_window=-20,
post_window=20,
att=True,
)
# 汇总三个模型的整洁格式结果
comparison = pd.concat(
[
fit_twfe.tidy().assign(estimator="TWFE"),
fit_did2s.tidy().assign(estimator="DID2S"),
fit_lpdid.tidy().assign(estimator="LP-DID").drop(
columns="N", errors="ignore"
),
],
axis=0,
)
print(comparison)PyFixest 0.60.0 的结果为:
三个估计量均为正,但数值并不相同。这里不能只凭“TWFE 最小”就断定全部差异来自负权重。更准确的说法是:在交错处理和异质性效应下,三种方法使用的比较组、事件时间权重和汇总方式不同,因而可能对应不同的加权平均处理效应。研究者应先确定目标参数,再选择估计量,而不是从多个结果中挑选最符合预期的一项。
若目标是动态效应,应进一步估计并绘制事件研究结果,检查各事件时间系数及同时置信带。只报告一个总体 ATT 会掩盖处理效应随时间上升、下降或反转的情况。
本文代码基于 PyPI 稳定版 0.60.0。PyFixest 的开发版 0.70.0 正在调整公式解析:交互固定效应的规范写法将由 f1^f2 改为 f1:f2,工具变量公式也计划转向 Formulaic 的方括号语法。若读者安装的是后续版本,应以对应版本的 changelog 和公式文档为准。
简便做法是在复现包中同时保留以下信息:
import platform
import pyfixest as pf
print("Python:", platform.python_version())
print("PyFixest:", pf.__version__)原始示例若按 nr + year 双向聚类,年份维度只有 8 个簇。此时常规聚类渐近近似可能不可靠。双向聚类不是“比单向聚类更稳健”的机械升级;若某一维聚类数很少,应结合研究设计考虑小样本修正、wild cluster bootstrap 或其他适当推断方法。
高维固定效应能够控制相应维度上不随另一维变化的未观测异质性,却不能消除所有随时间变化的混杂因素。一个模型吸收了企业和年份固定效应,并不等于核心解释变量已经外生。工具是否好用与研究设计是否可信,是两个层面的问题。
若要比较 PyFixest、R fixest 和 Stata reghdfe,至少应同步核对:
只有这些设定一致,跨软件的数值对照才有解释价值。
PyFixest 的优势不是替研究者选择模型,而是让模型设定、估计、推断和结果整理使用较统一的 Python 接口。对熟悉 reghdfe 或 fixest 的读者,迁移成本确实较低;对 DID 研究,仍应从处理时点、对照组和目标 ATT 出发选择估计量。
Note:产生如下推文列表的 Stata 命令为:
lianxh hdfe, md2 nocat
安装最新版lianxh命令:ssc install lianxh, replace
ppmlhdfe 到 ppml_fe_bias[33].log(1+y) 到 PPMLHDFE[34].🍓 连享会 · 2026 社会网络分析专题
嘉宾:杨张博 (西安交通大学)
时间:2026 年 8 月 18-19 日
咨询:王老师 18903405450(微信)

New! Stata 搜索神器:
lianxh和songblGIF 动图介绍
搜: 推文、数据分享、期刊论文、重现代码 ……
👉 安装:. ssc install lianxh. ssc install songbl
👉 使用:. lianxh DID 倍分法. songbl all

🍏 关于我们

[1] valerie_guo@163.com: mailto:valerie_guo@163.com[2] PyFixest 文档: https://pyfixest.org/[3] 安装与首个回归: https://pyfixest.org/getting-started.html[4] Stata 到 PyFixest 对照: https://pyfixest.org/how-to/stata-2-pyfixest.html[5] DID 教程: https://pyfixest.org/tutorials/difference-in-differences.html[6] 版本变更记录: https://pyfixest.org/changelog.html[7] GitHub 仓库: https://github.com/py-econometrics/pyfixest[8] Link: https://doi.org/10.48550/arXiv.2601.21749[9] PDF: https://arxiv.org/pdf/2601.21749[10] Google: https://scholar.google.com/scholar?q=Fast+and+user-friendly+econometrics+estimations+The+R+package+fixest[11] Link: https://doi.org/10.32614/RJ-2022-048[12] PDF: https://journal.r-project.org/articles/RJ-2022-048/RJ-2022-048.pdf[13] Google: https://scholar.google.com/scholar?q=did2s+Two-stage+difference-in-differences[14] Link: https://doi.org/10.1002/jae.70000[15] PDF: https://www.nber.org/system/files/working_papers/w31184/w31184.pdf[16] Google: https://scholar.google.com/scholar?q=A+local+projections+approach+to+difference-in-differences[17] Link: https://doi.org/10.1177/1536867X1101000406[18] Google: https://scholar.google.com/scholar?q=A+simple+feasible+procedure+to+fit+models+with+high-dimensional+fixed+effects[19] reghdfe 回归表格:固定效应 Yes/No 自动化标注之 esttab-reg2docx: https://www.lianxh.cn/details/1747.html[20] Stata:三维引力模型介绍与估计-ppmlhdfe-nbreg-reghdfe: https://www.lianxh.cn/details/848.html[21] ivreghdfe 命令安装失败解决方法: https://www.lianxh.cn/details/1477.html[22] PPML 估计 + 一般均衡求解?ge_gravity2 一套 Stata 命令全搞定: https://www.lianxh.cn/details/1755.html[23] Stata: 面板数据模型一文读懂: https://www.lianxh.cn/details/122.html[24] Stata:关于reghdfe命令常见问题解答: https://www.lianxh.cn/details/852.html[25] Stata:固定效应分析新命令-sumhdfe: https://www.lianxh.cn/details/631.html[26] Stata:为什么计数类变量不宜采用log(1+y)的形式?-ppmlhdfe: https://www.lianxh.cn/details/1094.html[27] reghdfe:多维面板固定效应估计: https://www.lianxh.cn/details/156.html[28] JF论文推介:FE和RE如何选择?: https://www.lianxh.cn/details/1303.html[29] Stata外部命令:SSC所有外部命令清单-按类别排序: https://www.lianxh.cn/details/141.html[30] Stata新命令:ppmlhdfe-面板计数模型-多维固定效应泊松估计: https://www.lianxh.cn/details/337.html[31] 连享会 - 课程主页: https://www.lianxh.cn/details/17.html[32] ppmlhdfe 实证指南:系数解释、固定效应与聚类标准误: https://www.lianxh.cn/details/1807.html[33] 三维 PPML 引力模型的偏误校正:从 `ppmlhdfe` 到 `ppml_fe_bias`: https://www.lianxh.cn/details/1813.html[34] 非负因变量如何做 DID?从 `log(1+y)` 到 PPMLHDFE: https://www.lianxh.cn/details/1809.html[35] IV 和 2SLS 估计中的 R2 为负怎么办?: https://www.lianxh.cn/details/1734.html[36] Stata:reghdfe命令报错问题: https://www.lianxh.cn/details/157.html[37] ivreghdfe-高维固定效应IV估计:错误信息处理-817 lines skipped: https://www.lianxh.cn/details/1299.html[38] ivreghdfe-高维固定效应IV估计:错误信息处理-817 lines skipped: https://www.lianxh.cn/details/1318.html