1. 为什么我要系统整理GIS与空间统计的基础知识
做GIS这行十来年,我最大的感受就是:工具换了一茬又一茬,从早期的桌面端软件到现在的云端平台,从单机分析到分布式计算,但底层那套空间思维和统计逻辑几乎没怎么变。很多人上手就能用软件画图、做缓冲区、跑个核密度,可一旦问到“为什么这里要用Moran's I而不是Geary's C”“半变异函数拟合出来的块金效应到底意味着什么”,就卡壳了。这个项目标题叫“GIS及空间统计相关基础整理”,说白了就是我自己给自己建的一套知识索引,把散落在各种文档、论文、项目笔记里的东西归拢到一块儿,方便随时查、随时补。
这套整理能解决什么问题?最直接的就是:当你面对一个空间数据集,知道该从哪儿下手,用什么指标去描述它的空间特征,以及怎么判断结果是不是靠谱。它适合谁?刚入行的GIS分析人员、做城市研究或环境监测的研究生、需要处理位置数据的后端开发,甚至是对地图感兴趣但没系统学过的产品经理,都能从这套框架里找到自己需要的部分。我不会把它写成教科书,而是按实际干活儿的顺序来组织——先搞清楚数据在空间上长什么样,再判断它有没有空间规律,最后才是建模和解释。
2. 空间数据的基础认知与整理思路
2.1 矢量、栅格与属性表:三种视角看同一片地
空间数据说到底就两种基本形态:矢量和栅格。矢量用点、线、面来描述离散对象,比如一个井盖、一条道路、一个行政区;栅格用规则网格上的像元值来表达连续现象,比如高程、温度、植被指数。很多人纠结“我该用哪种”,其实判断标准很简单:你要表达的对象边界是否清晰。边界清晰就用矢量,边界模糊或连续变化就用栅格。但实际项目中经常需要互相转换,比如把栅格分类结果转成矢量面来统计面积,或者把矢量点插值成栅格表面。转换过程中最容易被忽略的是分辨率与精度的匹配——矢量转栅格时,栅格大小决定了你能保留多少细节,转小了数据量爆炸,转大了小图斑直接消失。
属性表是矢量数据的灵魂。一个面要素可以挂几十个字段,记录人口、产值、用地类型。这里有个坑:很多人把属性表当成普通表格来操作,忽略了它与几何对象的绑定关系。一旦你做了融合、拆分或空间连接,属性表的行数和对应关系就会变。我的习惯是,任何会改变几何的操作之前,先备份一份原始属性表,或者至少记录下操作前的要素数量和关键字段的统计值,方便事后核对。
2.2 坐标系与投影:所有空间分析的起点
坐标系这事儿,说多了都是泪。我见过太多项目因为坐标系没统一,导致面积算错、距离偏差、图层对不上。地理坐标系(比如常见的WGS84、CGCS2000)用经纬度表示位置,单位是度;投影坐标系则是把球面展平到平面上,单位是米。做空间统计时,只要涉及距离、面积、密度这些度量,就必须用投影坐标系。判断方法很简单:看你的数据单位,如果是度,那大概率是地理坐标系,直接拿来做缓冲区会得到奇怪的结果。
投影的选择也有讲究。等角投影保持形状不变,适合导航和地形图;等积投影保持面积不变,适合做统计汇总;等距投影保持特定方向的距离不变,适合做缓冲区分析。没有一种投影能同时保住形状、面积和距离,所以得根据分析目标来选。我通常会在项目开始时建一个“投影决策表”,把研究区范围、分析类型、需要的度量精度列出来,然后对照选择。比如做全国范围的人口密度分析,我会用Albers等积投影;做城市尺度的路网距离计算,用UTM或高斯-克吕格投影更合适。
2.3 数据清洗与拓扑检查:别让脏数据毁掉分析
空间数据清洗比普通表格清洗麻烦得多,因为除了属性错误,还有几何错误。常见的几何问题包括:自相交、悬挂节点、重叠面、缝隙、重复点。这些错误在可视化时可能看不出来,但一做空间分析就会出问题。比如两个相邻面之间有微小缝隙,做叠加分析时就会产生大量碎片多边形;线要素有悬挂节点,网络分析就会断掉。
我的清洗流程一般是:先做几何有效性检查,修复自相交和空几何;再做拓扑检查,确保面不重叠、线不悬挂、点不重复;最后做属性一致性检查,比如分类字段的取值是否在预期范围内、数值字段有没有异常值。拓扑检查的容差设置很关键,设太小查不出问题,设太大又会误伤正常要素。经验值是:对于城市尺度的数据,容差设在0.001米到0.01米之间比较合适;对于区域尺度的数据,可以放宽到1米到10米。这个没有绝对标准,得根据数据精度和项目要求来调。
3. 空间统计的核心概念与实操要点
3.1 空间自相关:判断“近朱者赤”是否成立
空间自相关是空间统计里最基础也最重要的概念。它回答的问题是:某个位置的值,是否与它邻近位置的值相关。正相关意味着高值旁边是高值、低值旁边是低值(聚集);负相关意味着高值旁边是低值(离散);零相关就是随机分布。最常用的两个指标是Moran's I和Geary's C。Moran's I的取值范围大致在-1到1之间,大于0表示正相关,小于0表示负相关;Geary's C的取值范围一般在0到2之间,小于1表示正相关,大于1表示负相关。两者本质上是倒数的关系,但Moran's I对全局聚集更敏感,Geary's C对局部差异更敏感。
实操中最关键的是空间权重矩阵的构建。权重矩阵定义了“谁是谁的邻居”。常见的有邻接权重(共享边或共享点算邻居)、距离权重(一定距离内算邻居)、K近邻权重(最近的K个算邻居)。选哪种取决于你的研究假设和数据特征。比如做行政区划的聚集分析,用邻接权重比较自然;做点数据的聚集分析,用距离权重或K近邻更合适。权重矩阵还要考虑是否行标准化,行标准化后每个要素的邻居权重之和为1,能消除邻居数量差异带来的偏差。我一般会同时跑几种权重方案,对比结果是否稳健,如果结论随权重变化而剧烈波动,那就得小心解释了。
3.2 热点分析与局部指标:找到真正的“异常区”
全局自相关只能告诉你整体有没有聚集,但没法指出哪里聚集。这时候就需要局部指标,最常用的是Local Moran's I(也叫LISA)和Getis-Ord Gi*。LISA把每个要素的局部贡献分解出来,能识别出高-高聚集、低-低聚集、高-低异常和低-高异常四种类型。Getis-Ord Gi*则直接给出热点和冷点的z得分和p值,更适合做热点制图。
这里有个实操心得:LISA和Gi的结果有时会不一致,因为它们的零假设和统计量不同。LISA关注的是局部与全局的差异,Gi关注的是局部邻域内的集中程度。我的做法是两者都跑,然后看重叠区域。如果某个区域在两种方法下都显著,那结论就比较可靠;如果只有一种方法显著,就得结合业务知识判断。另外,多重比较问题不能忽视。做局部统计时,每个要素都要做一次检验,假阳性率会累积。常用的校正方法有FDR(错误发现率)和Bonferroni校正。FDR相对宽松,适合探索性分析;Bonferroni严格,适合验证性分析。
3.3 半变异函数与空间插值:从离散点推测连续面
半变异函数是地统计学的核心工具,用来描述空间相关性随距离变化的规律。它的三个关键参数是:块金值、基台值和变程。块金值表示距离趋近于0时的变异,反映了测量误差和微观尺度变异;基台值是变异达到平稳时的水平,等于总方差;变程是达到基台值对应的距离,超过这个距离就认为没有空间相关性了。拟合半变异函数模型时,常用的有球状模型、指数模型和高斯模型。球状模型在变程处达到基台后保持平稳,指数模型渐近达到基台,高斯模型在原点附近非常平滑。选哪个模型要看数据特征,没有绝对优劣。
插值方法的选择更考验经验。反距离加权简单快速,但容易产生“牛眼”效应;克里金插值能给出预测方差,但计算量大且需要拟合变异函数;样条函数适合平滑表面,但不适合有突变的数据。我通常先用反距离加权快速看趋势,再用克里金做精细插值,最后用交叉验证比较误差。交叉验证的指标看均方根误差和平均标准误差,前者越小越好,后者越接近1越好。如果平均标准误差远大于1,说明预测方差被低估了,模型过于自信;远小于1则说明预测方差被高估了。
4. 完整实操流程:从原始数据到空间统计报告
4.1 数据准备与预处理
假设我拿到一份某区域的气象站点数据,包含站点坐标和年均温度,想分析温度的空间分布特征。第一步是检查坐标系。如果站点坐标是经纬度,先投影到合适的投影坐标系。我会根据研究区范围选择投影,比如研究区在中纬度地区,用UTM投影比较合适。投影后计算站点间的距离,确认单位是米。
第二步是数据清洗。检查有没有重复站点、坐标异常点、温度缺失值。重复站点会导致空间权重矩阵出现自环,影响统计结果。坐标异常点可能是录入错误,比如经纬度写反了。温度缺失值如果少量,可以剔除;如果大量,得考虑插补,但插补会引入不确定性,需要在报告中说明。
第三步是探索性分析。画直方图看温度分布是否正态,画散点图看有没有空间趋势。如果温度随纬度有明显梯度,说明存在全局趋势,做克里金插值时需要先去除趋势,否则变异函数会被趋势污染。去除趋势的方法有全局多项式拟合和局部多项式拟合,阶数一般从1阶开始试,看残差是否还有空间结构。
4.2 空间权重矩阵构建与全局自相关计算
数据准备好后,构建空间权重矩阵。对于站点数据,我一般用K近邻权重,K取4到8之间。为什么不用距离权重?因为站点分布不均匀时,距离权重会导致密集区域的站点权重过大。K近邻能保证每个站点都有相同数量的邻居,相对公平。权重矩阵行标准化后,计算全局Moran's I。
计算过程可以用Python的libpysal和esda库。代码大致如下:
import libpysal import esda import numpy as np # 假设coords是站点坐标数组,values是温度数组 w = libpysal.weights.KNN.from_array(coords, k=6) w.transform = 'r' # 行标准化 moran = esda.Moran(values, w) print(f"Moran's I: {moran.I:.4f}") print(f"p-value: {moran.p_sim:.4f}")跑出来如果Moran's I显著为正,说明温度存在空间聚集。这时候可以进一步做局部分析,看看哪些站点是热点或冷点。如果Moran's I不显著,那可能温度在这个尺度上是随机分布的,或者空间权重矩阵没选对,可以换几种权重方案再试。
4.3 局部热点识别与结果可视化
局部分析用Local Moran's I或Getis-Ord Gi*。我习惯用Gi做热点制图,因为它的z得分可以直接映射到颜色深浅,直观易懂。计算Gi的代码:
gi = esda.G_Local(values, w, star=True) print(gi.z_sim) # z得分 print(gi.p_sim) # p值得到z得分后,按显著性水平分类:z大于1.96且p小于0.05为热点,z小于-1.96且p小于0.05为冷点,其余为不显著。可视化时,热点用暖色,冷点用冷色,不显著用灰色。这样一眼就能看出温度的高值聚集区和低值聚集区。
这里有个细节:Gi*的z得分受权重矩阵影响很大。K近邻的K值不同,热点范围会变化。我的做法是跑多个K值(比如4、6、8、10),看热点区域是否稳定。如果某个区域在所有K值下都是热点,那结论就很可靠;如果只在特定K值下出现,就得谨慎解释。
4.4 半变异函数拟合与克里金插值
如果要做连续表面插值,先计算实验半变异函数。用gstat或pykrige都可以。实验半变异函数的计算步骤是:把所有站点两两配对,计算距离和半方差,然后按距离分组求平均。分组数一般取10到20组,保证每组有足够的点对。
from pykrige.ok import OrdinaryKriging import numpy as np # 假设x, y是投影坐标,z是温度 ok = OrdinaryKriging(x, y, z, variogram_model='spherical', verbose=False) z_pred, ss_pred = ok.execute('grid', gridx, gridy)拟合模型后,看变程是否合理。如果变程远大于研究区范围,说明空间相关性在整个研究区都存在,插值结果会比较平滑;如果变程很小,说明空间相关性只在很近的距离内存在,插值结果会保留更多局部细节。块金值如果很大,说明测量误差或微观变异占主导,插值的不确定性会比较高。
交叉验证是必须做的。用留一法,每次剔除一个站点,用其余站点插值预测该站点,然后计算预测误差。均方根误差越小越好,平均标准误差越接近1越好。如果误差太大,可能需要换变异函数模型或调整参数。
5. 常见问题与排查技巧实录
5.1 空间权重矩阵报错:孤岛与自环
构建空间权重矩阵时,最常见的报错是“孤岛”(island)和“自环”(self-loop)。孤岛是指某个要素没有任何邻居,通常出现在研究区边缘或数据稀疏区域。自环是指要素把自己当成邻居,通常是因为坐标重复或距离阈值设置不当。解决方法:对于孤岛,可以手动添加邻居,或者用K近邻强制指定邻居数量;对于自环,检查坐标是否有重复,或者在构建权重时排除自身。
提示:
libpysal的KNN方法会自动排除自身,但如果坐标数组中有重复点,仍然可能出现问题。建议在构建权重前先做去重。
5.2 Moran's I不显著:可能的原因与对策
Moran's I不显著,不一定意味着没有空间规律。可能的原因有:空间权重矩阵不合适、数据存在全局趋势、研究尺度不对、变量本身空间相关性弱。对策:换几种权重方案(邻接、距离、K近邻)对比;去除全局趋势后再计算;改变研究尺度(比如从站点尺度聚合到网格尺度);检查变量是否应该做变换(比如对数变换)。
我遇到过一个案例:某区域房价的Moran's I不显著,但去除城市中心趋势后,残差的Moran's I显著为正。这说明房价的全局趋势掩盖了局部聚集。所以,不显著时不要急着下结论,多试几种处理方式。
5.3 克里金插值出现负值或异常值
克里金插值假设数据服从正态分布,如果原始数据偏态严重,插值结果可能出现负值或超出物理范围的值。解决方法:先做数据变换,比如对数变换、Box-Cox变换,使数据接近正态;或者改用指示克里金,它对数据分布没有严格要求。另外,变异函数模型选择不当也会导致异常值,比如用高斯模型拟合有突变的数据,会在突变处产生过冲。这时候换成球状模型或指数模型可能更好。
5.4 局部统计的多重比较问题
做局部统计时,每个要素都做一次假设检验,假阳性率会累积。比如有1000个要素,显著性水平0.05,即使没有真实聚集,也会有大约50个要素被误判为显著。解决方法:用FDR校正或Bonferroni校正。FDR校正后的p值阈值更宽松,适合探索性分析;Bonferroni更严格,适合验证性分析。在esda库中,Moran_Local的p_sim是模拟p值,已经部分考虑了多重比较,但最好还是手动做FDR校正。
| 问题现象 | 可能原因 | 排查方法 | 解决对策 |
|---|---|---|---|
| 权重矩阵报孤岛 | 要素无邻居 | 检查研究区边缘和数据稀疏区 | 手动添加邻居或改用K近邻 |
| Moran's I不显著 | 权重不当/趋势干扰/尺度不对 | 换权重、去趋势、改尺度 | 多方案对比,结合业务判断 |
| 插值出现负值 | 数据偏态/模型不当 | 检查分布、拟合变异函数 | 数据变换或改用指示克里金 |
| 局部统计假阳性多 | 多重比较 | 计算FDR校正后p值 | 用FDR或Bonferroni校正 |
6. 工具链与代码片段整理
6.1 Python生态:libpysal + esda + pykrige
Python做空间统计的优势是生态完整、可复现性强。libpysal负责空间权重矩阵,esda负责探索性空间数据分析,pykrige负责克里金插值。这三个库基本覆盖了从数据准备到统计建模的全流程。安装用pip install libpysal esda pykrige即可。需要注意的是,libpysal的权重对象可以保存为文件,方便复用。保存和加载的代码:
w.save('weights.gal') w = libpysal.weights.load('weights.gal')6.2 R生态:spdep + gstat + sf
R在空间统计领域历史更久,spdep包提供了丰富的空间自相关和局部指标函数,gstat包是地统计学的标杆,sf包则是现代空间数据处理的基石。如果你习惯R,这套组合非常顺手。spdep的moran.test和localmoran函数用起来很直接,gstat的variogram和krige函数也很成熟。R的优势是统计模型更丰富,比如可以做空间回归、地理加权回归等进阶分析。
6.3 工具选型建议:看场景,不看喜好
选Python还是R,我的建议是:如果项目需要和Web服务、机器学习管道集成,选Python;如果项目偏重统计建模和学术发表,选R。如果团队两种都有人用,那就统一用一种,避免维护两套代码。另外,QGIS和ArcGIS Pro也内置了空间统计工具,适合快速探索和可视化,但批量处理和自动化还是得靠代码。我通常用QGIS做数据检查和初步可视化,用Python做批量计算和可复现分析,两者结合效率最高。
7. 持续整理的方法与个人体会
这套整理我一直在更新,因为空间统计这个领域新方法层出不穷,旧方法也在不断被重新审视。我的整理习惯是:每做一个项目,就把用到的数据预处理步骤、参数选择理由、遇到的坑和解决方案记下来,归到对应的主题下。时间长了,就形成了一套自己的知识库。我用的工具很简单,就是Markdown文件加Git版本控制,每个主题一个文件,代码片段单独存成脚本,用相对路径引用。这样不管换电脑还是换系统,都能快速恢复工作环境。
另外,我强烈建议做空间统计的人养成记录“分析日志”的习惯。每次跑完一个分析,把数据版本、参数设置、软件版本、运行时间、关键结果都记下来。空间统计的结果对参数很敏感,过几个月回头看,如果没有日志,根本想不起来当时为什么选那个变程、为什么用那个权重矩阵。这个习惯看起来麻烦,但关键时刻能救命。
最后分享一个小技巧:做空间自相关分析时,先用随机化方法生成零分布,看看你的观测值在零分布中的位置。esda的Moran对象有sim属性,保存了模拟的Moran's I值。画个直方图,把观测值标上去,比只看p值直观得多。如果观测值落在零分布的尾部,说明聚集显著;如果落在中间,那就别硬解释了。这个方法我每次做探索性分析都会用,能快速判断结果是否值得深入。