简介:动态面板空间杜宾模型代码包,面向空间计量经济学研究方向的研究者,解决传统静态模型无法处理时间滞后与空间滞后并存的问题。该实现包含完整的模型估计与检验环节,适用于产业集聚、区域创新、技术扩散等动态空间溢出的实证分析。压缩包共19个文件,总大小仅337KB,其中12个.m脚本构成主要功能模块,包括模型估计核心函数、示例运行脚本、空间权重矩阵构造及长期效应计算等;4个xlsx数据文件提供面板数据与空间权重示例,便于直接复现案例;1个PDF文档则详细说明动态极大似然估计的原理和操作要点。已有1948人学习下载。通过运行示例脚本,读者能完整经历从模型设定、数据准备、参数估计到结果解读的流程,并可根据自己的研究课题修改函数接口或数据文件,快速迁移至其他空间面板场景,显著提升实证分析效率。
1. 动态面板空间杜宾模型:先别急着解压 rar,这套空间回归最容易让人栽跟头
桌面上的“动态面板空间杜宾模型.rar”通常装着讲稿、示例数据和一两个 do 文件,但真正能一次跑通的人不多。动态面板空间杜宾模型是空间计量里最“缠人”的一种:它同时处理时间惯性、空间溢出和时空反馈,估计出来的系数不能直接解释,还要拆成短期/长期、直接/间接效应。很多研究地级市财政竞争、污染排放、创新溢出的同学,都是卡在“怎么把 rar 里的资料变成自己数据的可复现结果”这一步。这个标题真正值钱的不是那个压缩包,而是背后的模型选择逻辑和参数设置经验。适合已经懂一点面板回归、想往上走空间计量的人。
2. 先立住理论:动态面板空间杜宾模型在识别什么,为什么不能只用静态
2.1 动态面板空间杜宾模型比普通空间杜宾多估了“时空惯性”
普通空间杜宾模型(SDM)已经比空间自回归(SAR)进了一步,因为它不但包含邻居被解释变量的当期影响 Wy,还包含每个解释变量的空间滞后 Wx。它解决的问题是:某地的 x 变化,除了影响本地 y,会不会通过空间溢出影响邻居的 y,甚至邻居的 y 再反过来影响本地 y。但静态 SDM 有一个致命前提:不考虑时间惯性。
现实里的区域创新、环境污染、财政支出,没有一个是“当期归当期”的。上一年度的污染会继续影响今年,这是时间滞后 y_{t-1};邻居上一年度的污染还会通过大气扩散或要素流动影响今年本地,这是时空滞后 W*y_{t-1}。动态面板空间杜宾模型就是在静态 SDM 的基础上,把这两个滞后项同时放进模型。不加这两个项,空间自回归系数 ρ 会被系统性高估,因为模型会把时间惯性误判成邻居的同步效应。很多论文被拒稿,根子就在这。
2.2 模型表达式里每个字母在说什么:从 τ 到 η 的识别链条
一个比较通用的动态面板空间杜宾模型可以写成:
y_{it} = τ y_{i,t-1} + ρ W y_{it} + η W y_{i,t-1} + X_{it} β + W X_{it} θ + μ_i + γ_t + ε_{it}
这里 τ 是时间滞后系数,衡量 y 自身的惯性;ρ 是空间自回归系数,衡量当期邻居的 y 对本地 y 的影响;η 是时空滞后系数,衡量邻居上一期 y 对本地当期 y 的影响;β 是自变量当期影响,θ 是自变量空间滞后影响,相当于邻居的 x 也会影响本地 y。μ_i 是个体固定效应,γ_t 是时间固定效应,ε_{it} 是扰动项。
看这个式子要注意一个点:ρ、τ、η 三个系数同时存在,模型才能识别“冲击的完整传播路径”。本地 x 变动,先通过 β 影响本地 y;再通过 W 和 ρ 传导给邻居;邻居下一期又带着 η 把部分影响传回来,同时时间惯性 τ 又让这个影响衰减或放大。静态模型把这一整套压缩到一个 ρ 里,自然会出问题。审稿人如果要你解释“长期效应是怎么算出来的”,你得能说清长期乘子来自 (1-τ) 和 (1-ρ-η) 的组合,而不是简单把系数乘一个年份数。
2.3 怎么选择空间面板模型:先跑 LM 检验,再决定要不要上 SDM
拿到任何数据,不要一上来就怼动态面板空间杜宾模型。先问一句:这个模型是不是被数据支持?常见做法是“一般到具体”的路径:先用普通动态面板或静态面板跑一个基准模型,把残差拿出来做空间相关检验,再决定模型形态。
R 里用 spdep 包的 lm.LMtests 可以同时给出针对空间误差和空间滞后的 LM 检验结果:
library(spdep) # 假设已经有坐标 coords 和面板数据 df # 构建 k 近邻权重矩阵,k 一般取 4 到 8 nb <- knn2nb(knearneigh(coords, k = 4)) listw <- nb2listw(nb, style = "W") # 先跑一个普通 OLS 基准模型 ols <- lm(y ~ x1 + x2, data = df) # 检验残差是否存在空间滞后或空间误差结构 lm.LMtests(ols, listw, test = "all")lm.LMtests 返回 LMerr、LMlag、RLMerr、RLMlag 四类统计量。LMerr 指向空间误差模型,LMlag 指向空间滞后模型;如果两个都显著,再比较稳健的 RLMerr 和 RLMlag。如果 RLMlag 更强,SAR 更合适;如果都不拒绝,再考虑 SDM。因为 SDM 是更一般的设定,包含了 SAR 和 SEM 作为约束情况,所以很多人会直接把 SDM 当作起点。但注意,动态面板空间杜宾模型的自由度更大,对数据长度和截面数要求也更高。T 不够长时,时空滞后加时间滞后会让工具变量数量爆炸,后面检验会变得非常脆弱。
3. 把 rar 变成可复现结果:Stata 与 R 的最小运行路径
3.1 解压前先看清这三样东西:数据、权重矩阵、do 文件
我下载这类课程资料踩过最大的坑,是解压密码被“后缀乱码”误导。类似“动态面板空间杜宾模型.rar_caughtuk3_空间回归_空间杜宾”这种命名,实际上“caughtuk3”多半是发布者自己的标记,不是密码。如果碰到“课程资料.rar 忘记解压密码”,先回原发布页看正文和置顶评论,比下载 Advanced RAR Password Recovery 靠谱得多。这类破解工具耗时不说,很多破解版还会夹带广告子程序,杀毒软件报完警你还要回头来找干净环境。
解压之后,先别急着打开 do 文件。先确认三样东西是否齐全:第一,面板数据,最好长这样:id、time、y、x1、x2 这种标准结构;第二,空间权重矩阵,是一个 n×n 的矩阵文件,或者至少有一列经纬度/多边形 shapefile;第三,do 文件或 R 脚本。如果压缩包里只有 do 文件没有权重矩阵,那大概率是在 do 文件里用坐标现场生成。你先运行到生成 W 的命令,确认没问题再继续。
3.2 Stata 路线:导入权重矩阵后跑通静态 SDM,再升级动态
Stata 15 以后有官方空间面板命令,权重矩阵可以手动导入。假设你有一个 W.csv,行和列都是区域 id,顺序和面板数据里的独立个体顺序一致:
* 1. 导入空间权重矩阵,W 是矩阵名称,W.csv 是第一行和第一列为 id 的 n×n 矩阵 spmatrix import W using "W.csv", replace * 2. 跑固定效应空间杜宾模型,dvarlag 加入 W*y,ivarlag 加入所有 x 的 W*x spxtregress y x1 x2, fe dvarlag(W) ivarlag(W) * 3. 输出直接、间接和总效应 estat impacts这里的 fe 是个体固定效应;dvarlag(W) 表示模型包含被解释变量的空间滞后;ivarlag(W) 表示所有解释变量的空间滞后也要进入模型。如果没有 ivarlag(W),模型就退化成空间自回归 SAR 了。estat impacts 对 SDM 尤其重要,它会输出直接效应、间接效应和总效应,还会给置信区间。注意,这个命令要求 W 的行标准化,且对角线必须为 0。
Stata 没有一条命令直接跑“动态”空间杜宾,常见做法是先造出空间滞后变量,再放到动态面板 GMM 里。可以用官方 spgenerate 生成 Wy,然后手动生成 Wy_{t-1},最后放到 xtabond2 或 xtdpdsys 里把这两个滞后变量当作内生变量处理。这里最容易犯的错是直接把 W*y 当作普通外生变量放进 GMM,审稿人大概率会质疑空间滞后变量的内生性。
3.3 R 路线:用 spdep 生成空间滞后变量,为动态面板 GMM 做准备
如果你拿到的是 R 代码,那核心工作就是构建正确的权重矩阵并生成空间滞后变量。下面是一个可以迁移的最小例子:
library(spdep) # 读入面板数据,必须包含 id、time、lon、lat df <- read.csv("panel_data.csv") # 构建 k=4 近邻,然后转成行标准化的权重矩阵 coords <- cbind(df$lon, df$lat) nb <- knn2nb(knearneigh(coords, k = 4)) listw <- nb2listw(nb, style = "W") # 生成本期空间滞后 W*y df$Wy <- lag.listw(listw, df$y) # 生成上一期 y,再求空间滞后,得到时空滞后 W*y_{t-1} df$y_lag <- ave(df$y, df$id, FUN = function(z) c(NA, head(z, -1))) df$Wy_lag <- lag.listw(listw, df$y_lag)lag.listw 返回每个区域邻居变量的加权平均,权重来自 listw。ave 是按 id 分组做滞后,c(NA, head(z, -1)) 是手动实现时间滞后,比用 reshape 的函数更直观。得到 Wy 和 Wy_lag 后,就可以用 plm 包的 pgmm 函数做动态空间面板估计:
library(plm) pdata <- pdata.frame(df, index = c("id", "time")) # 示意:把时间滞后和空间滞后都当作内生变量 # 工具变量集合需要根据 Arellano-Bond 检验调整 model <- pgmm(y ~ lag(y, 1) + Wy + Wy_lag + x1 + x2 | lag(y, 2:4) + Wx1 + Wx2, data = pdata, model = "twostep", effect = "twoways") summary(model, robust = TRUE)这里最需要留意的是工具变量集合。lag(y, 2:4) 是把 y 的第二到第四阶滞后作为工具变量,Wx1 和 Wx2 是解释变量的空间滞后。空间滞后变量 Wy 本身是内生的,需要在 gmm 或 iv 部分里处理,否则估计量不会一致。上面这段代码是一个落地起点,真正写进论文前必须读 Arellano-Bond AR(2) 检验和 Hansen 检验的输出。
4. 三个必调参数:空间权重矩阵、动态项与效应分解的置信区间
4.1 空间权重矩阵怎么选:从邻接到经济距离的四张牌
空间权重矩阵是整个模型的黑匣子。同样的数据,用邻接矩阵和用经济距离矩阵,估计出的 ρ 可能一个是正 0.5,一个是负 0.2。所以第一步不要急着跑模型,要把权重矩阵的生成理由写清楚。
常见的选择可以分成四类:
| 类型 | 适用场景 | 主要坑 |
|---|---|---|
| 简单邻接 | 行政区划、地理边界清楚 | 岛或孤立区域会被自动排除 |
| 距离衰减倒数 | 空气污染、技术溢出 | 阈值截断距离要给出依据 |
| k 近邻 | 城市网络、产业关联 | 每个地区邻居数固定,边界地区也硬凑 |
| 经济/社会距离 | 财政竞争、人口流动 | 存在明显内生性,要提前解释 |
权重矩阵一定要做行标准化,也就是每一行元素之和为 1,这样 W*y 才是邻居 y 的加权平均。对角线必须严格为 0,不然某地自己的 y 会通过权重矩阵传回自己,导致 ρ 虚高。在 Stata 里导入经济距离矩阵和导入地理权重矩阵完全一样,prepare 一个 csv 用 spmatrix import 就行。做稳健性时至少换一种权重矩阵,如果结果的直接效应符号都不变,才算过了基本门槛。
4.2 动态项参数:时间滞后和时空滞后该不该同时进模型
动态面板空间杜宾模型里最关键的参数不是 ρ,而是 τ 和 η 的组合。很多人在 Stata 里跑完静态 spxtregress,看到 ρ 显著就觉得大功告成。但如果你是做政策评估或实证因果,缺少时间滞后意味着所有估计都建立在“去年的事对今年没有任何影响”这个假设上,这在区域数据里几乎不可能成立。
我一般建议的做法是分层估计:先跑一个只含 y_{t-1} 的动态 SAR 模型,再把 W*y_{t-1} 加进去变成动态 SDM,用 LR 检验判断空间滞后因变量是不是多余。如果 η 不显著,就退回到动态 SAR,减少工具变量数量。如果 η 显著为正,说明邻居上一期的结果仍然在影响本地,这时候时空溢出不是短期扰动,而是长期累积的。R 里可以用 pgmm 修改公式,Stata 里则在 xtabond2 的 gmm 列表中加入 L.Wy。要特别注意,Wy 和 Wy_lag 都是内生变量,工具变量必须至少包含 y 的更高阶滞后和外生的 Wx。
4.3 效应分解的置信区间:审稿人要的不是点估计
动态面板空间杜宾模型的结果不能只报告回归系数,因为 ρ、τ、η 会交叉反馈。真正进入论文表格的是直接效应、间接效应和总效应。静态 SDM 中,直接效应和间接效应来自矩阵 (I - ρW)^(-1)(β + θW);动态模型还要考虑时间和时空滞后,长期效应进一步被 τ 和 η 调整。
效应分解光有点估计没有置信区间,几乎等于白做。Stata 的 estat impacts 在静态模型后面会直接给区间;动态模型没有现成命令,就得自己 bootstrap。这里有一个很容易翻车的地方:bootstrap 必须按整块个体抽样,也就是整个 id 的时间序列一起进组,不能逐行重抽样。逐行抽会破坏每个个体内部的时间相关性,空间关联结构也乱了,算出来的置信区间没有意义。R 里我一般这样写:
set.seed(123) nboot <- 200 results <- vector("list", nboot) id_list <- unique(pdata$id) for (b in 1:nboot) { # 按个体整块抽样 chosen <- sample(id_list, replace = TRUE) idx <- unlist(lapply(chosen, function(i) which(pdata$id == i))) df_boot <- pdata[idx, ] # 重新估计动态空间面板模型,并提取间接效应 model_b <- pgmm(y ~ lag(y, 1) + Wy + Wy_lag + x1 + x2 | lag(y, 2:4) + Wx1 + Wx2, data = df_boot, model = "twostep", effect = "twoways") results[[b]] <- summary(model_b, robust = TRUE)$coefficients } # 后续按分位数提取置信区间注意这里用到的不是 pdata.frame,而是 plm 对象,实际写代码时要先转换好。bootstrap 次数 200 到 500 比较常见,太少的话间接效应尾部很宽,写进论文没有说服力。如果模型本身计算很慢,可以先缩到 99 次看趋势,再决定要不要跑完整。
5. 动态面板空间杜宾模型避坑指南:五条翻车记录与排查路径
5.1 现象:do 文件报错 spxtregress not found
你拿到的课程资料多半来自某位老师或博主,里面可能写的是spxtregress y x1 x2, fe,结果你打开 Stata 一跑,直接红色报错 command not found。
原因基本就是两个:Stata 版本低于 15,或者运行前没有初始化空间数据。spxtregress 是 Stata 15 才加入的官方命令,14 及以前的版本无论如何都跑不了。另外,它依赖 spmatrix 导入的权重矩阵,如果 do 文件里没有执行 spmatrix import,命令本身也不会工作。
解决:先which spxtregress和which spmatrix看结果。如果 Stata 版本不够,要么升级,要么改用ssc install xsmle,xsmle 能做静态空间面板 SDM/SAR/SEM。如果是权重矩阵没导入,把 spmatrix import W using "W.csv", replace 放到 spxtregress 前面。这个坑是最“新手友好”的,但也有很多老手因为版本和命令库不同浪费一整天。
5.2 现象:权重矩阵维度对不上,数据里出现大量缺失
有时候模型能跑,但看结果发现变量数量不对,或者报错“W has missing values”。这通常不是代码问题,而是权重矩阵的行列顺序和面板数据的个体顺序不一致。
原因很具体:比如你用经济距离矩阵,excel 里删了几个省份,但权重矩阵还是原来的 n×n;或者面板数据是长面板,个体 id 的编码和矩阵行号不能对齐。另一个常见原因是非平衡面板:某个个体在某年缺失,但权重矩阵包含它,R 的 lag.listw 会把缺失位置变成 NA,然后蔓延到整个回归。
解决:先tab id数一下个体数,再数权重矩阵维度。确保权重矩阵不含对角线自环,行名和 id 一一对应。非平衡面板要先用 plm 的 make.pbalanced 或者 Stata 的 tsfill 补成平衡面板,再生成空间滞后变量。空间计量里,非平衡面板的权重矩阵处理本身就比较麻烦,最好在数据处理阶段就补平。
5.3 现象:ρ 接近 0.99 或模型不收敛
动态面板空间杜宾模型里 ρ 的取值范围受权重矩阵约束,行标准化后理论上小于 1,但接近 0.99 就已经是极大值了。如果你发现 ρ 每次估计都在 0.95 以上,且标准误巨大,通常不是“空间关联很强”,而是模型设定有问题。
最常见的原因是缺少时间固定效应。如果所有地区共享一个随时间上升的共同冲击,而你只加了地区固定效应,这个共同时间趋势会被空间滞后项捕捉,导致 ρ 虚高。另一个原因是权重矩阵对角线不为 0,让每个地区把自己的 y 也算了一遍邻居,ρ 直接爆表。
解决:在模型中加入时间固定效应,Stata 的 fe 选项里再补时间虚拟变量,R 的 pgmm 把effect 设成 twoways。检查权重矩阵对角线数值,写成diag(W)看一眼,全部应为 0。如果调完还是接近 1,检查 y 是否带明显单位根,必要时取对数或差分。
5.4 现象:动态项系数与静态模型差异巨大
同一种数据,静态 SDM 的 ρ=0.6 且显著,加入 y_{t-1} 后 ρ 降到 0.2,τ=0.7 显著。很多人会怀疑是自己做错了,其实这是正常且合理的结果。
原因是静态模型把时间惯性塞进了空间自回归项。区域 gdp、污染、创新能力都有极强的持续性,静态模型无法区分“因为去年就是这个水平”和“因为邻居今年影响了本地”。加入时间滞后项后,ρ 回落是剥离了时间成分后的真实同期空间溢出。如果 τ 不显著,那才说明没有时间惯性,静态模型也说得过去。
解决:不要删掉静态结果,论文里同时报告静态和动态,用动态结果显示 τ 和 η 的显著性来说明动态模型更合适。再配合 Arellano-Bond AR(2) 检验的 p 值,如果 AR(2) 不显著,说明动态模型的工具变量条件基本成立,这是审稿人最爱看的东西。
5.5 现象:间接效应符号和回归系数符号相反
空间杜宾模型最反直觉的一点,就是回归表格里的 θ 和间接效应符号可能完全相反。比如 W*x 的系数 θ=-0.3 且显著,画出来的间接效应却是正的。很多人因此怀疑效应分解程序出错。
原因在计算逻辑:间接效应不是 θ 本身,而是整个空间乘子矩阵的非对角元素。间接效应同时受到 β、θ、ρ 的影响,如果 β 是正的且 ρ 是正的,本地 x 提升会通过反身反馈放大邻居的 y,最终溢出方向由 β+θW 的组合积分决定,而不是单看 θ。
解决:所有论文结论都从 estat impacts 或 R 的效应分解结果出,不直接引用 θ 做解释。如果间接效应符号和业务直觉冲突,用 2.3 里的空间权重矩阵换一种方式验证,并说明结果在哪种矩阵下成立。把 θ 单独拿出来写结论,是空间计量审稿里非常典型的低级错误。
6. 让动态面板空间杜宾模型进论文:效应分解表格与两个可视化收尾
6.1 效应分解表怎么写才能过审稿人那关
论文里的核心结果表,我一般会列成三块:直接效应、间接效应、总效应,每块再拆短期和长期。行放核心解释变量,列放效应类型,括号里放 bootstrap 置信区间或标准误。注意不要只给星号和 z 值,至少给出 95% 置信区间,审稿人特别喜欢看区间是否跨零。
表格里的数字要跟回归系数对上,但不要直接把 θ 或 β 抄进去。长期效应要特别小心,动态模型的长期乘子不是短期效应的简单相加,而是要通过 (1-τ) 和空间乘子共同调整。你要是存疑,就做一次 bootstrap 计算长期效应,确保每次抽样都走同一个估计流程,避免手算和程序不一致。
6.2 用空间溢出散点图验证方向,别让表格数字说了算
效应分解是一个黑匣子,审稿人未必信,所以我会加一张空间溢出散点图:横轴是某个核心解释变量 x,纵轴是它的空间滞后 W*x,点大小对应空间权重,再叠一条回归线。如果散点图斜率为正,说明该变量的空间分布本身就有正溢出,模型分解出正的间接效应才不会显得突兀。
R 里的代码很简单:
library(ggplot2) df$Wx <- lag.listw(listw, df$x1) ggplot(df, aes(x1, Wx)) + geom_point(aes(size = weight), alpha = 0.6) + geom_smooth(method = "lm", se = FALSE)这张图的价值在于稳定性验证:换一种权重矩阵,如果 Wx 和 x1 的关系仍然同方向,后面的空间模型结论就有支撑;如果图形斜率和模型间接效应相反,你要先回去检查是不是权重矩阵尺度出了偏差。做稳健性时我会再删掉个体规模最大的区域重新估计,防止单点驱动 ρ。这个习惯是从一次翻车里学来的:当时一个直辖市样本同时是高权重和异常值,删掉之后 ρ 从 0.7 掉到 0.3,整个结论差点被推翻。现在我对每个空间模型结果都默认至少跑三种权重矩阵、删一个最大截面、做一次 bootstrap,三个结果方向一致才敢写进正文。希望帮到你。
本文还有配套的精品资源,点击获取