一个技术创新中心落地以后,影响可能越过行政边界,通过人才流动、面对面交流和示范效应传递给周边企业。此时只比较中心所在城市与其他城市,容易把地理距离很远的同城企业算作受影响对象,也可能把近在几公里外、只是位于相邻行政区的企业放进对照组。Ring-DID 提供了一种沿空间距离重新组织比较的方法。

Ring-DID:围绕事件地点建立局部比较
Ring-DID 以事件发生地点为圆心划定若干距离带。假设某中心在 2022 年投入运行,可以把距离中心 0—10 公里的企业划入内环,把 10—30 公里的企业划入外环,只保留这两个局部样本,比较中心落地前后两组企业结果变量的变化。内环相对于外环多出来的变化,可以写成:
ATTring = E(ΔY | d ≤ 10) − E(ΔY | 10 < d ≤ 30)
这种设计的直觉来自局部可比性。距离同一地点较近的企业通常共享相似的劳动力市场、基础设施和地方经济环境,外环因而可能为内环提供较可信的反事实变化。不过,这种可比性需要研究者用数据和制度背景支持。政策发生以前,两组企业的结果趋势应当接近;同时发生的其他冲击不应只覆盖其中一个环带;外环企业还要保持足够低的政策暴露。
最后一个条件尤其重要。如果中心的知识溢出能够延伸到 25 公里,10—30 公里的外环已经受到影响。用这批企业作为对照,会把“较强暴露”与“较弱暴露”之间的差异当成政策的完整效应,估计结果通常会被压向零。多个中心陆续落地时,环带还可能重叠,一家企业在同一时期可能同时受到几个中心影响。此时只计算“距离最近中心的距离”,会丢失处理强度与处理来源的信息。
环带半径也会直接改变估计对象。0—10 公里内的平均效应与 0—30 公里内的平均效应对应不同的企业群体;当真实效应随距离衰减时,两者本来就应当不同。研究者应根据知识传播、通勤范围或监管可见度等机制预先确定主要环带,再报告若干有实质含义的替代距离。逐一尝试大量半径并只保留显著结果,会把空间机制分析变成显著性筛选。
Butts 对地理编码微观数据中的 ring method 作了系统化处理。他指出,传统内环—外环估计依赖研究者知道影响究竟延伸多远;论文进一步使用非参数方法估计随距离变化的处理效应曲线,从而减少任意环带划分造成的问题。作者同时公开了论文复现代码,可用于理解参数化环带估计和非参数距离效应估计的具体实现。原论文与作者复现代码
实际计算的第一步是把企业和事件中心转换成地理对象,计算每家企业到中心的距离,再据此生成内环和外环变量。R 的 sf 包能够完成这一步:
library(sf)
library(dplyr)
library(fixest)
# firm_location: 每家企业一行,包含 firm_id、lon、lat
# center: 一个事件中心,包含 lon、lat
# panel: 企业—年份面板,包含 firm_id、year、outcome
firm_sf <- st_as_sf(
firm_location,
coords = c("lon", "lat"),
crs = 4326,
remove = FALSE
)
center_sf <- st_as_sf(
center,
coords = c("lon", "lat"),
crs = 4326
)
firm_sf$distance_km <-
as.numeric(st_distance(firm_sf, center_sf)[, 1]) / 1000
ring_panel <- panel |>
left_join(
st_drop_geometry(firm_sf) |>
select(firm_id, distance_km),
by = "firm_id"
) |>
filter(distance_km <= 30) |>
mutate(
near = as.integer(distance_km <= 10),
post = as.integer(year >= 2022)
)
ring_model <- feols(
outcome ~ near:post | firm_id + year,
cluster = ~firm_id,
data = ring_panel
)
summary(ring_model)
这段代码只展示一个事件中心、一个处理时点下的计算结构。跨地区数据要先确认坐标参考系统和距离单位;经纬度不能直接当作平面上的公里数使用。sf::st_distance() 官方文档 标准误的聚类层级还应与政策赋值和误差相关结构对应。只有少数事件中心时,有效处理簇过少会使常规聚类推断失真,增加企业观测数并不能自动解决这个问题。
当多个中心在不同时期投入运行,可以把每家内环企业第一次受到处理的年份记为 first_treat,把确实没有受到处理的比较单位记为 0,再使用分组—时期 DID 估计不同批次在不同时点的 ATT(g,t)。R 的 did 包允许处理时点错开,并能进一步汇总为事件时间效应:
library(did)
att_result <- att_gt(
yname = "outcome",
tname = "year",
idname = "firm_id",
gname = "first_treat", # 首次处理年份;从未处理为 0
xformla = ~ baseline_size + baseline_age + baseline_patents,
data = ring_panel,
panel = TRUE,
control_group = "nevertreated",
est_method = "dr"
)
event_result <- aggte(att_result, type = "dynamic")
summary(event_result)
ggdid(event_result)
att_gt() 的默认 dr 方法使用双重稳健估计,并允许条件平行趋势依赖给定协变量。该工具适合处理一旦发生便持续存在的错位处理设计;企业在环带之间反复进出,或同时接受多个中心暴露时,需要另行定义时间变化的处理过程。did 包的 att_gt() 文档

DML:在复杂协变量下估计低维因果参数
DML 的英文全称是 Double/Debiased Machine Learning,中文常译为“双重机器学习”或“去偏机器学习”。它面向这样一类问题:研究者只关心一个或少数几个因果参数,同时又需要处理很多辅助关系,例如根据大量协变量预测结果变化,或者预测一个单位接受处理的概率。这些辅助关系维度很高,可能包含非线性与复杂交互,普通线性设定难以充分表达。
直接用随机森林、提升树或 Lasso 估计这些关系,再把预测值代入因果参数的估计方程,会受到正则化偏差和过拟合影响。DML 使用两个关键机制控制这种影响。其一是 Neyman 正交得分,使目标参数对辅助函数的小幅估计误差不那么敏感;其二是交叉拟合,把样本分成若干折,用其他折训练模型,再为当前折生成样本外预测。Chernozhukov 等人的论文给出了这一框架的系统理论,并讨论了随机森林、Lasso、提升树和神经网络等学习器在辅助函数估计中的使用。DML 原始论文
在较容易理解的部分线性模型中,可以把 DML 想成分别剥离协变量能够预测的处理差异和结果差异,再利用剩余变化估计目标效应。DID 场景需要使用与条件平行趋势相匹配的正交得分,具体计算比“残差对残差回归”更严格。DML 能够降低辅助函数形式设错带来的风险,其有效性仍然依赖研究设计提供的识别条件。遗漏的时间变化混杂、已经受政策影响的中介变量、被空间溢出污染的对照组,都需要在进入 DML 之前处理。
Python 的 DoubleML 当前提供 DoubleMLDIDMulti 来估计多时期 DID。数据中的 first_treat 表示首次处理时期,官方接口使用 np.inf 标记从未处理单位。下面假定 analysis_panel 已经完成空间暴露定义,再用随机森林演示辅助函数的估计:
import numpy as np
from sklearn.ensemble import RandomForestRegressor, RandomForestClassifier
from doubleml.data import DoubleMLPanelData
from doubleml.did import DoubleMLDIDMulti
df = analysis_panel.copy()
df["first_treat"] = df["first_treat"].astype(float)
df.loc[df["first_treat"] == 0, "first_treat"] = np.inf
dml_data = DoubleMLPanelData(
data=df,
y_col="outcome",
d_cols="first_treat",
id_col="firm_id",
t_col="year",
x_cols=[
"baseline_size",
"baseline_age",
"baseline_patents",
"baseline_finance",
"industry_encoded"
],
)
dml_did = DoubleMLDIDMulti(
obj_dml_data=dml_data,
ml_g=RandomForestRegressor(
n_estimators=500,
min_samples_leaf=10,
random_state=2026
),
ml_m=RandomForestClassifier(
n_estimators=500,
min_samples_leaf=10,
random_state=2026
),
control_group="never_treated",
n_folds=5,
)
dml_did.fit()
print(dml_did.summary)
这里的 ml_g 学习条件结果关系,ml_m 学习处理概率,估计器完成交叉拟合。实际分析还需要检查样本外预测表现与处理概率重叠,并比较若干合理学习器和调参方案下的估计稳定性。模型选择应围绕辅助函数的泛化能力展开,不能根据最终因果效应是否显著来挑选学习器。安装方法与最新接口可查阅 DoubleML 官方安装说明和 DoubleMLDIDMulti 接口文档。Python 可运行 pip install -U DoubleML,R 版本可运行 install.packages("DoubleML")。

一套可执行的研究方案
假设研究问题是:国家级技术创新中心投入运行后,是否提高了周边企业的创新产出,这种影响能够传播多远?研究者可以收集各中心的准确地址和投入运行时间,将企业注册地址转换为经纬度,并构造企业—年份面板。结果变量可以使用发明专利申请量或高质量专利数量;处理变量由企业到已运行中心的距离与投入时间共同决定。
研究的第一阶段专门解决空间暴露。根据知识交流和通勤范围提出主要距离划分,例如以 0—10 公里为内环、10—30 公里为外环,同时估计 0—5、5—10、10—20、20—30 和 30—50 公里等距离带的动态效应。政策前的事件时间系数用于观察局部趋势,政策后的系数用于判断影响何时出现、持续多久。环带重叠的企业单独标记多重暴露;政策实施后才迁入附近的企业需要剔除或按迁址过程重新定义处理,避免企业主动选址造成反向选择。
研究的第二阶段评估协变量调整的复杂度。企业规模、年龄、所有制、历史专利、融资、产业和地区创新基础全部固定在处理前,先用分组—时期 DID 得到透明的基准结果。如果这些特征与处理概率及创新趋势之间呈现明显非线性,或者变量和交互项数量很大,再使用 DML-DID 估计同一组 ATT(g,t)。DML 在这里接手协变量相关的辅助函数,Ring-DID 已经完成空间处理组与局部比较组的定义。
最终结果应同时给出事件时间和空间距离两个维度。若中心运行后两三年内,0—10 公里企业的创新产出明显增加,10—30 公里效应较弱,30 公里外接近于零,并且这一距离梯度在基准 DID 与 DML-DID 中保持稳定,研究才能较有把握地提出“创新中心形成了具有边界的局部知识溢出”。如果 DML 调整后效应大幅变化,需要追查近环与外环在处理前特征上的可比性;如果外环也出现同步增长,则要重新审视控制环是否已经受到影响。这样收尾,Ring-DID 给出空间上的可信比较,DML 处理复杂协变量,二者共同服务于同一个清楚的因果问题。