做空间计量的朋友应该都经历过这个场景:模型跑通了,显著性也出来了,审稿人一句“空间权重矩阵怎么构建的?为什么选这种矩阵?”直接把你问住。更常见的情况是,你从某个网盘下了一份邻接矩阵,兴冲冲拿去和面板数据匹配,结果发现里面是旧行政区划代码,一merge就丢掉十几个城市,想死的心都有。
我花了不少精力整理了一份覆盖285个地级市、时间跨度2003-2023年、包含8类空间权重矩阵的数据集。这篇文章不卖数据,而是把这套矩阵背后的构建思路、计算原理、实际操作和踩坑记录完整写出来。无论你是做区域经济、产业集聚、绿色发展还是城市创新,空间权重矩阵这一步绕不开,搞明白了能省掉大量重复劳动,也能让论文在方法部分经得起审稿人追问。
1. 为什么花力气整理矩阵:空间计量的第一步就藏着大坑
1.1 矩阵不是工具变量,它是模型假设本身
空间计量和普通面板回归最大的区别,在于它用空间权重矩阵把样本之间的“相互影响”显式地写进了模型。这个矩阵不只是建模时的一个插件,它本身就是模型的核心假设。同样是285个城市的碳排放数据,用邻接矩阵跑出来的莫兰指数,和用经济距离矩阵跑出来的结果,可能方向都不一样。审稿人一定会追问:为什么用这个权重?不同权重有没有做稳健性检验?
很多人正是在这一步栽了跟头。我见过不少同学,在某个网站下了一个看似完整的矩阵,不检查样本顺序,直接合并到面板数据里,等到输出结果才发现莫兰指数是负数、空间滞后项不显著,但根本不知道问题出在矩阵上。还有更隐蔽的:矩阵里用城市名做索引,而城市名称在2003到2023年间有很多次调整,比如早期的襄樊后来更名为襄阳,思茅更名为普洱,用名字做关联键,跨年合并很容易静默丢失样本。矩阵数据本身没有对错,但如果不理解它背后的构造逻辑,拿到手也只是个“黑盒”。
1.2 8个矩阵分别是什么,怎么选
这套数据里包含的8类矩阵,背后对应8种不同的空间相互作用假设。没有一个矩阵能通吃所有场景,关键是你得匹配自己的研究问题。我把整套矩阵的构成和适用场景整理如下:
| 矩阵名称 | 构建逻辑 | 典型适用场景 |
|---|---|---|
| 0-1邻接矩阵(Rook) | 两城市共享行政边界记为1,否则为0 | 区域污染邻近效应、行政边界溢出、创新协同 |
| 0-1邻接矩阵(Queen) | 边界或顶点相接都记为1 | 对邻接定义做稳健性检验,考虑对角相邻 |
| 地理距离倒数矩阵 | 权重=1/d,d为球面距离 | 连续距离衰减、要素流动、知识溢出的基准设定 |
| 地理距离平方倒数矩阵 | 权重=1/d² | 距离衰减更陡峭的通信流、技术扩散场景 |
| 经济距离矩阵 | 基于两地GDP差额的倒数 | 经济发展水平相近地区之间的互动 |
| 经济地理嵌套矩阵 | 地理邻接关系乘以经济权重 | 同时考虑地理邻近和经济关联的综合溢出 |
| 引力模型矩阵 | (GDP_i×GDP_j)/d² | 贸易流、人口流动、城市间经济辐射 |
| 产业结构相似矩阵 | 产业结构向量余弦相似度 | 产业同构、地区竞争与合作关系 |
这个组合基本覆盖了我这些年看文献时遇到的空间权重需求。我的建议是:主模型用一个基础矩阵,比如邻接矩阵或地理距离倒数矩阵;稳健性检验再换两到三个不同逻辑的矩阵,这样既能说明结果不依赖于特定权重设定,又不会因为矩阵太多把自己绕晕。以下是各类矩阵的适用场景补充:
- 邻接矩阵最常用,也最容易解释,但它默认只有接壤的城市才存在空间溢出,忽略非接壤但经济联系紧密的城市。
- 距离矩阵把“地理学第一定律”直接量化,即距离越近影响越大,但距离衰减速度的选择(1/d还是1/d²)会影响结果。
- 经济距离和嵌套矩阵适合研究跨区域经济联系,但构造时对GDP处理要求高,不能直接用名义GDP。
- 产业结构相似矩阵是我个人很喜欢的稳健性检验矩阵,它捕捉的是城市间“竞争—互补”关系,在做产业政策、协同发展类题目时特别好用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 构建原理:8个矩阵背后的计算逻辑
2.1 邻接矩阵:Rook和Queen到底差在哪
邻接矩阵的构建逻辑不复杂:两个城市是否共享边界,共享记为1,否则为0。但这里头有个细节很多人没注意——Rook邻接和Queen邻接的差异。Rook方式只把共享边界的城市记为相邻,类似于国际象棋里车(Rook)的走法,只能横竖;Queen方式还把共享顶点的城市也算相邻,相当于皇后(Queen)的走法,还能斜着走。
这两种方式在东部平原城市密集区差异不大,但放到西部和边疆地区就明显了。因为地级市面积大,边界接壤情况复杂,用Rook算出来的邻居数量明显少于Queen,部分面积大的地级市在Rook规则下几乎没有邻居。更麻烦的是,邻接矩阵对“形状”敏感,同一个城市在不同年份的行政区划调整后,邻居集合可能发生变化。所以我在整理时特意把Rook和Queen两种版本都保留了,这样你在做稳健性检验时可以直接替换,不用自己再跑一遍拓扑计算。
2.2 地理距离矩阵:从经纬度到球面距离的完整过程
地理距离矩阵的核心是计算两个城市中心点之间的球面距离。这里不能直接拿来平面直角坐标系里的欧氏距离,因为地球是球面,纬度不同,同一经度差对应的实际距离完全不同。我使用的是Haversine公式,给定两点的经纬度,大圆距离的计算方式如下:
d = 2R · arcsin(√(sin²((lat₂−lat₁)/2) + cos(lat₁)·cos(lat₂)·sin²((lon₂−lon₁)/2)))
其中R取地球平均半径6371公里。这个公式在短距离和中距离上都保持较高精度,足够用于城市间距离计算。实际操作中有一个极其容易踩的坑:经纬度单位。从地图API或地理数据库中拿到的大多是十进制度数,但三角函数要求弧度制,必须先统一转换。我见过有人忘了这一条,算出来的距离结果直接差了一个数量级。
城市中心点的选取也有讲究。常用的有市政府驻地坐标、主城区几何中心、或者用人口加权重心。我最终选择了市政府驻地坐标,理由很简单:可复现性强,别人拿着你的数据可以核对。如果选人口加权重心,会牵扯到每个城市历年人口分布数据,数据源一旦换年份,结果就对不上了。
2.3 经济距离矩阵和嵌套矩阵:为什么不能只靠地理距离
邻接矩阵和地理距离矩阵只考虑空间物理位置,没有涉及经济系统的结构差异。但真实世界里的空间溢出,往往不是单纯由地理距离决定的。两个城市地理距离很远,但都是千万级GDP的经济强市,它们之间的技术合作、资本流动可能远远高于地理相邻但产业同质化严重的一对小城市。这就需要有经济维度的权重。
经济距离矩阵我采用的做法是:先计算2003-2023年各城市实际GDP均值,再取任意两城市GDP均值之差的绝对值,取倒数作为权重。经济水平越接近,权重越大。这个假设符合很多实证研究中的逻辑——经济结构和发展阶段相似的城市之间,更容易发生竞争效应、示范效应和资源共享。
经济地理嵌套矩阵则更复杂一些,它的构造思路是把地理邻接关系当成“骨架”,把经济权重当成“血肉”填进去。基本流程是:先构建0-1邻接矩阵,得到地理结构的0/1框架;再对每个城市i,计算其相邻城市j的GDP占比,把这个占比权重乘以邻接关系,得到嵌套矩阵。这个矩阵在解释上更丰满:既承认只有地理相邻才有直接溢出,又区分了相邻城市中哪些经济联系更强、权重更高。
2.4 矩阵标准化:行标准化是默认操作,但不是万能钥匙
矩阵构建出来之后,还有一个经常被忽略的环节:标准化。绝大多数空间计量模型默认使用行标准化,也就是把矩阵每一行的所有元素除以该行之和,使每行权重之和等于1。这样做的好处是模型参数可以解释为“来自其他样本的加权平均影响”,在莫兰指数计算、空间滞后变量构造上都很自然。
但行标准化并非没有代价。它会让小城市、邻居少的城市的权重被人为放大,而大城市、邻居多的城市反而被压缩。举个例子:一个西部地级市只有2个地理邻居,一个东部地级市有8个地理邻居,行标准化后,西部的每个邻居权重是1/2,东部的每个邻居权重只有1/8。这显然会对估计结果产生微妙影响。所以在整理时,我每一类矩阵都同时提供了原始版本和行标准化版本,具体用哪个,取决于你的研究场景和稳健性设置要求。
3. 实操记录:从原始数据到可用的矩阵
3.1 确定城市集合:为什么是285个
2003年到2023年,中国的行政区划并非一成不变。这几年里有城市更名、有撤地设市、也有地级市被整体撤并。我选择的标准非常明确:在2003-2023年这21年里,能持续匹配到完整面板数据的地级市,最终确定为285个。这个数量比当前最新的地级行政区数量略少,原因就是个别城市在窗口期内发生了撤销合并,无法保留完整的面板序列。
我用的处理规则是这样的:先以2003年行政区划代码为基准版本,逐年核对后续年份的代码变化,建立一张“历史代码映射表”。城市更名的,比如襄樊变更为襄阳,保留同一代码不变,但名称更新;城市代码发生变化的,则要查清是更名还是合并还是行政级别调整,再决定是否保留在面板中。如果某个城市在窗口期后半段被并入其他城市,那么把它整个样本删除,不强行拼接。
这个规则在论文方法部分必须写清楚。审稿人如果发现你的样本是285个城市,而不是通常说的293个左右,他会期望你给出筛选依据。说明哪些城市因为撤销合并被排除,比让读者自己去猜要妥当得多。
3.2 坐标匹配与距离矩阵的实现
我把经纬度获取和距离矩阵生成分成两步。第一步,通过地理编码接口批量获取285个市政府驻地的经纬度坐标,得到一张包含城市代码、城市名称、经度、纬度的基础表。第二步,用R语言里的geosphere包计算两两距离,核心代码如下:
r复制# coords 是数据框,包含 city_code, lon, lat
library(geosphere)
coord_matrix <- as.matrix(coords[, c("lon", "lat")])
dist_mat <- distm(coord_matrix, fun = distHaversine) / 1000 # 单位转换为公里
diag(dist_mat) <- 0
# 生成地理距离倒数矩阵
dist_inv <- 1 / dist_mat
dist_inv[is.infinite(dist_inv)] <- 0
# 生成地理距离平方倒数矩阵
dist_inv2 <- 1 / (dist_mat^2)
dist_inv2[is.infinite(dist_inv2)] <- 0
这里有一个关键细节:distm函数返回的单位是米,直接除以1000转成公里,不会影响后续取倒数的操作,但能在描述性统计部分让距离数值更直观。另一个细节是,距离矩阵的对角线元素是0,取倒数之后会出现无穷大,必须手动替换为0。
距离计算完成后,我做了三项常规检查:矩阵是否对称、是否存在NA或无穷大、城市顺序是否与主面板完全一致。这三个检查是最基础的,但不做很容易翻车。我建议无论用什么语言实现,都至少跑一遍矩阵对称性验证,用max(abs(W - t(W)))查看是不是0,不是0就说明计算过程有Bug。
3.3 GDP数据的对齐与经济矩阵构造
经济距离矩阵和嵌套矩阵必须依赖GDP数据。这里最大的坑是:构建跨年度矩阵时,GDP应该用当年价还是不变价。如果直接用当年价,年份之间的价格因素会混进来,导致经济权重在不同年份之间不可比。我的处理是以2003年为基期,用各城市所在省份的GDP平减指数对名义GDP做缩减,得到实际GDP序列,然后取样本期内的均值作为构建经济矩阵的基础。
为什么不直接用某一年的实际GDP?因为单一年份容易受短期波动影响,均值更稳定,同时面板模型里多个年份都用同一个空间权重矩阵时,理论上要求矩阵是外生的,用整个样本期的均值可以缓解内生性争议。还有一点,GDP缺失值必须在构建矩阵前处理完。某城市个别年份GDP缺失,我会用前后两年线性插值补齐;如果连续多年缺失,则考虑从样本中剔除该城市。
经济距离矩阵的构建逻辑是:任意两城市之间,实际GDP均值差额的绝对值越大,经济距离越大,权重越小,所以取倒数。经济地理嵌套矩阵则更精细,先确定地理邻居,再以GDP占比作为权重。假设城市i有K个地理邻居,则城市j的嵌套权重 = GDP_j / (GDP邻居1 + GDP邻居2 + ... + GDP邻居K)。这种做法的好处是权重之和在每行保持为1,天然做了行标准化,而且包含了地理邻近和经济结构双重信息。
3.4 矩阵文件如何导入实证模型
数据整理得再漂亮,最终还是要落到模型里跑。我用Stata的频率较高,这里说一下Stata导入外部空间矩阵的两种方式。
第一种,如果装的是Spatial Autoregressive Models模块,可以直接用spmatrix命令。需要先把矩阵文件保存为标准的矩阵格式,比如用Excel保存的csv文件,然后通过spmatrix import命令导入:
stata复制spmatrix import W_adj using "0-1邻接矩阵_Rook.csv", sheet(1) row(1) column(1)
spmatrix summarize W_adj
第二种方式是使用外部命令spmat,不过从Stata 15之后官方spmatrix已经很成熟了,我更推荐直接用官方命令,兼容性更好,而且支持多种矩阵形式的校验。导入之后一定要做一步操作:查看spmatrix summarize的输出,确认矩阵的维度是285×285、对角线为0、行标准化版本每行和为1。如果这些检查有一项不对,模型估计结果再好也不能信。
R语言用户更简单,spdep包里的mat2listw函数可以直接把矩阵对象转换成空间权重列表,然后代入lagsarlm、errorsarlm等模型估计函数。这部分我不过多展开,因为Stata和R的细节差异比较大,但底层逻辑一致:先确保矩阵格式与模型需要一致。
4. 常见问题排查:这些坑我替你踩过了
4.1 邻接矩阵里的“孤立点”怎么处理
用Rook邻接矩阵时,最尴尬的问题是有些城市一个邻居都没有,典型的是海岛城市和部分边界城市。对应行全部是0,行标准化时0/0直接变成NaN,模型估计直接报错。遇到这种情况,我先看地图确认这个城市是否真的不与其他地级市接壤,如果确实没有陆地边界相邻,最简单的办法是换成Queen邻接矩阵,让对角相邻也算邻居。绝大多数情况下,Queen能解决Rook的孤立问题。如果Queen也无法解决,那就升级到距离矩阵,用地理距离倒数权重替代邻接关系。这也印证了为什么要一次准备多套矩阵,而不是只依赖一种。
4.2 城市更名和代码变化导致merge丢样本
2003到2023年间,涉及城市名称调整的案例不少。更重要的是,有些城市不是因为更名,而是因为行政区划调整导致代码发生变化,甚至整个城市被撤销合并。如果拿城市名做匹配键,轻则匹配失败数量为0,重则同一个城市在不同年份被识别成两个样本,面板直接失衡。
我的经验是三条:第一,统一以行政区划代码作为唯一主键,城市名称仅为辅助信息;第二,建立一份历史代码映射表,逐年核对,而不是一次性合并整个面板;第三,合并之后立刻统计每年样本量,如果某年城市数量忽然减少,优先怀疑代码匹配问题。这些步骤花的时间不多,但能避免后续模型结果全盘作废。
4.3 莫兰指数出现负数或NaN,排查顺序是什么
莫兰指数算出来是负数,不一定代表数据有错误。负莫兰指数表示空间离散,即高值周围是低值,这在某些经济变量里是有实际含义的。但如果莫兰指数出现NaN、或者绝对值大于1(正常情况下莫兰指数一般在[-1,1]区间),那就要查矩阵问题了。我的排查顺序是:
- 先检查矩阵对角线是否全为0。
- 再检查矩阵是否符合标准化要求,比如行标准化版每行之和是否接近1。
- 然后检查面板数据和矩阵的行列顺序是否完全一致。很多情况下,数据排序一变,矩阵没有跟着调整,结果就乱了。
- 最后检查是否有空值。矩阵里一个NA,都会导致全局莫兰指数直接NaN。
这里特别强调“顺序一致性”。我在早期的项目里犯过这个错:面板数据用城市代码排序,矩阵却按行政区划代码排序,两者城市列表一样,但顺序不同,匹配后矩阵行列错位,计算结果全错。后来我在生成矩阵之前就把城市列表固定下来,所有面板数据和矩阵文件都按这个固定顺序输出,才彻底解决这个问题。
4.4 嵌套矩阵的构造顺序:先乘权重还是先标准化
经济地理嵌套矩阵有一个隐蔽的坑:乘权重的顺序和标准化顺序会显著影响最终矩阵元素。我的经验是,先确定地理邻接骨架,再嵌入经济权重,最后整体行标准化。先算GDP权重比例再和对角拼接,看起来差别细微,但会导致非邻居城市之间出现虚假的正权重,这在逻辑上是错误的。换个角度想,嵌套矩阵的含义是“在地理相邻的前提下,经济联系更强的邻居获得更高权重”,如果颠倒顺序,矩阵就可能对地理不相邻但经济相似的城市也分配权重,这与研究假设冲突。构造完后,还要手动验证矩阵是否非对称(标准化后非对称是正常的,但逻辑要自洽),以及每行权重分布是否符合“邻居多的城市权重更分散、邻居少的城市权重更集中”的预期。
4.5 一个额外的提醒:矩阵的年限匹配
很多空间面板论文里使用单一的非时变权重矩阵,这个做法本身可以,但要交代清楚矩阵对应的是哪个时间段的经济数据。如果研究区间是2003-2023年,却用2003年的GDP构造经济权重,那么后20年的经济联系结构就被固定在了23年前的状态,审稿人可能质疑这个假设。我的建议是:经济矩阵分别提供基于全期均值版本和基于基期版本,在稳健性检验里进行对比。至少你要知道,你用的矩阵是基于哪一段时间的GDP,不能含糊。
5. 一句话总结我自己的使用习惯
矩阵数据整理这件事,属于“不做不知道,做了才知道有多少细节”的脏活累活。我自己用这套矩阵跑项目时,形成了一个固定套路:先用Rook邻接矩阵做主回归,再用经济地理嵌套矩阵做核心稳健性检验,最后用距离平方倒数矩阵做补充。三个矩阵逻辑差异明显,覆盖了地理邻近、经济关联和距离衰减三种空间相互作用机制,这样的组合在审稿环节几乎不会被质疑“权重选择具有偶然性”。
最后再分享一个实操小技巧:所有矩阵在生成后,都保留一份原始版、一份行标准化版,文件名里标注清楚版本和生成日期。这看似多余,但在论文返修、更换模型设定时非常有用。空间权重矩阵不是一次性工具,它会在你的论文里反复出现,把数据版本管好,能给自己省下大量返工时间。
