简介:这份资源围绕Kriging空间插值方法展开,面向GIS、地质勘探及空间数据分析领域的学习者与开发者,帮助其理解并实现从半方差函数建模到等值线图绘制的完整流程。压缩包共84个文件,以h头文件与cpp源文件为核心,辅以obj编译产物、txt测试数据及ico、cur等界面资源,整体约1.77MB,属于典型的VC6工程结构,便于直接编译调试。资源内含Kriging插值、矩阵运算、等值线绘制与三维图形显示等模块,并附带测试数据文件,可对照验证插值结果的连续性与光滑性。目前已有1214人学习下载,适合希望掌握空间插值原理、研究等值线生成算法或进行二次开发的中高级读者参考借鉴。
1. Kriging 画等值线图:从散点到一张能看的图,中间隔着多少坑
手里攥着几十个采样点,领导要一张等值线图,这事儿听起来简单,做起来能折腾一下午。Kriging 插值加等值线绘制,是地信、气象、环境监测、地质勘探这些领域绕不开的组合拳。它的核心价值在于:Kriging 不仅能把离散点变成连续曲面,还能给出估计方差,让你知道哪里插得准、哪里是瞎猜。等值线图则是把连续曲面变成人能读懂的边界和梯度。适合谁?适合手头有散点数据、需要出正式图件、又不想在 ArcGIS 里点一上午按钮的人。Python 的 pykrige + matplotlib 组合,能把这条链路压到几十行代码,但参数设错,出来的图就是一团玄学。
2. Kriging 插值的理论底子:为什么它比反距离加权更值得折腾
2.1 从变异函数到权重矩阵,Kriging 到底在算什么
Kriging 插值的数学内核是最优线性无偏估计。通俗点说:它不像反距离加权那样只按距离远近分配权重,而是先看数据本身的空间结构。这个结构用变异函数(variogram)来描述——两点的属性值差异随距离增大而增大的规律。如果变异函数显示数据在 500 米内相关性很强,Kriging 就会给这个范围内的已知点更高权重。
具体计算分两步。第一步,用已知点对拟合变异函数模型,常见的有球状模型、指数模型、高斯模型。第二步,对每个待插值点,解一个线性方程组,求出权重系数,同时得到该点的估计方差。这个方差是 Kriging 独有的,反距离加权给不了。
提示:变异函数拟合是 Kriging 最主观的环节。模型选错,后面的图全废。球状模型适合大多数地质数据,指数模型适合相关性衰减较慢的场景。
2.2 三种 Kriging 变体,什么场景选哪个
普通克里金(Ordinary Kriging)假设数据没有全局趋势,均值未知但局部平稳。这是最常用的,适合大多数环境监测数据。简单克里金(Simple Kriging)假设均值已知且恒定,实际中很少用,因为没人能拍脑袋定均值。泛克里金(Universal Kriging)则假设数据存在全局趋势,比如气温随海拔升高而降低,这时候就需要把趋势项剥离后再插值。
选型逻辑很简单:先画散点图,看数据有没有明显的方向性趋势。没有就用普通克里金,有就用泛克里金。别一上来就上泛克里金,趋势项设错比不设更糟。
2.3 用 pykrige 跑通第一个 Ordinary Kriging 插值
安装依赖:
pip install pykrige matplotlib numpy最小可运行代码:
import numpy as np from pykrige.ok import OrdinaryKriging import matplotlib.pyplot as plt # 模拟 30 个采样点:x, y 坐标和属性值 z np.random.seed(42) x = np.random.uniform(0, 100, 30) y = np.random.uniform(0, 100, 30) z = 50 + 0.3 * x + 0.2 * y + np.random.normal(0, 5, 30) # 初始化 Ordinary Kriging 对象 OK = OrdinaryKriging( x, y, z, variogram_model='spherical', # 变异函数模型 verbose=False, enable_plotting=False ) # 定义插值网格 grid_x = np.arange(0, 100, 2) grid_y = np.arange(0, 100, 2) # 执行插值,返回估计值和方差 z_pred, z_var = OK.execute('grid', grid_x, grid_y) print(f"插值结果形状: {z_pred.shape}") print(f"估计方差范围: {z_var.min():.2f} ~ {z_var.max():.2f}")这段代码做了三件事:构造 OrdinaryKriging 对象时自动拟合变异函数;定义 2 单位步长的网格;执行插值并返回预测值和方差。variogram_model参数可选'linear'、'power'、'gaussian'、'exponential'。enable_plotting=True会弹出变异函数拟合图,调试时有用,出图时关掉。
3. 从插值网格到等值线图:matplotlib 出图的五个关键参数
3.1 用 contourf 填充等值线,levels 怎么定
拿到z_pred后,直接上contourf:
fig, ax = plt.subplots(figsize=(10, 8)) # 填充等值线图 cf = ax.contourf(grid_x, grid_y, z_pred, levels=15, cmap='RdYlBu_r') # 叠加等值线 cs = ax.contour(grid_x, grid_y, z_pred, levels=15, colors='black', linewidths=0.5) # 添加等值线标签 ax.clabel(cs, inline=True, fontsize=8, fmt='%.1f') # 绘制原始采样点 ax.scatter(x, y, c='black', s=20, marker='x', label='采样点') # 添加颜色条 plt.colorbar(cf, ax=ax, label='属性值', shrink=0.8) ax.set_xlabel('X 坐标 (m)') ax.set_ylabel('Y 坐标 (m)') ax.set_title('Kriging 插值等值线图') ax.legend(loc='upper right') plt.tight_layout() plt.savefig('kriging_contour.png', dpi=300) plt.show()levels=15表示把数据范围分成 15 个色阶。太少(比如 5)会丢失细节,太多(比如 50)颜色差异肉眼难辨。我一般用 12 到 20 之间。cmap='RdYlBu_r'是红黄蓝反转色带,适合表示高低值,但注意:红绿色盲人群不友好,正式出版建议用'viridis'或'plasma'。
3.2 网格分辨率与插值速度的权衡
grid_x = np.arange(0, 100, 2)意味着 50×50 的网格,共 2500 个插值点。如果改成步长 0.5,就是 200×200 网格,4 万个点。Kriging 的计算复杂度是 O(n³),n 是已知点数量,但每个待插值点都要解一次方程组。4 万个点会让脚本跑几分钟甚至更久。
实际经验:出图用 1 到 2 的步长足够,A4 纸 300dpi 下看不出锯齿。如果要做交互式地图,步长可以放到 5,先看趋势。真要高分辨率,换用OK.execute('masked', ...)或者分块计算。
注意:
execute的'grid'模式返回完整网格,'masked'模式会把超出数据范围的区域掩掉,适合边界不规则的研究区。
3.3 把估计方差也画出来,判断哪里是瞎猜
Kriging 的方差图比预测值图更有信息量:
fig, axes = plt.subplots(1, 2, figsize=(16, 6)) # 左图:预测值 cf1 = axes[0].contourf(grid_x, grid_y, z_pred, levels=15, cmap='RdYlBu_r') axes[0].scatter(x, y, c='black', s=15, marker='x') axes[0].set_title('Kriging 预测值') plt.colorbar(cf1, ax=axes[0]) # 右图:估计方差 cf2 = axes[1].contourf(grid_x, grid_y, z_var, levels=15, cmap='Reds') axes[1].scatter(x, y, c='black', s=15, marker='x') axes[1].set_title('Kriging 估计方差') plt.colorbar(cf2, ax=axes[1]) plt.tight_layout() plt.savefig('kriging_with_variance.png', dpi=300)方差大的区域(深红色)说明采样点稀疏,插值结果不可信。如果方差图在某个角落突然飙高,要么补采样点,要么在出图时把那个区域裁掉。这是 Kriging 比反距离加权值钱的地方——它告诉你哪里别信。
4. 避坑与排查:Kriging 画等值线最常见的五个翻车现场
4.1 变异函数拟合失败,报错 "ValueError: zero-size array"
现象:运行OrdinaryKriging初始化时直接抛异常,提示数组为空或变异函数计算失败。
原因:采样点坐标完全重复,或者所有属性值相同。变异函数需要计算点对距离和半方差,如果所有点重合,距离矩阵全是零,拟合无从谈起。
解决:先检查数据。用np.unique看坐标去重后的数量。如果确实有重复点,合并取平均。如果属性值全相同,那插值本身就没意义,直接画个常数平面。
4.2 等值线图出现同心圆或条纹状伪影
现象:插值结果出现明显的同心圆环,或者沿某个方向的条纹,和实际物理规律不符。
原因:变异函数模型选错。比如数据实际是高斯型衰减,你用了球状模型,导致远距离点权重异常。或者nugget(块金值)设得太小,把测量误差当成了真实变异。
解决:打开enable_plotting=True,看拟合曲线和实验变异函数的散点是否贴合。如果散点在高距离处上翘,说明有趋势,改用泛克里金。如果散点在低距离处就很高,说明块金效应强,手动设nugget参数。
4.3 插值结果超出物理合理范围
现象:预测值出现负数,但你的数据是浓度、降水量这类不可能为负的变量。
原因:Kriging 是无偏估计,但不保证值域约束。普通克里金假设数据服从正态分布,如果原始数据偏态严重,插值结果就会越界。
解决:先对数据做对数变换,插值后再指数还原。pykrige 支持OrdinaryKriging的transform='log'参数。或者改用指示克里金(Indicator Kriging),但 pykrige 不直接支持,需要自己分位数分类后插值。
4.4 等值线标签重叠或缺失
现象:clabel出来的数字挤成一团,或者某些等值线没有标签。
原因:levels太多,等值线间距太小。或者inline=True把标签嵌在线上,但线太短放不下。
解决:减少levels数量,或者手动指定levels列表,比如levels=[10, 20, 30, 40, 50]。clabel的fmt参数控制小数位数,fontsize调小一点。如果还不行,用manual参数手动点选标签位置。
4.5 出图速度慢到无法接受
现象:网格步长调到 0.1,脚本跑了半小时还没出图。
原因:Kriging 每个待插值点都要解一个 n×n 的方程组,n 是已知点数量。如果已知点有 500 个,网格有 10 万个点,计算量是 500³ × 100000,天文数字。
解决:三个方向。第一,降低网格分辨率,出图用 1 到 2 的步长。第二,用OK.execute('masked', ...)只计算研究区内的点。第三,换用pykrige.uk.UniversalKriging的backend='C'参数,底层用 C 加速,能快 5 到 10 倍。
5. 进阶技巧:用交叉验证判断 Kriging 到底插得准不准
出完图不是终点。你怎么知道这张图可信?靠留一交叉验证。思路很简单:每次拿掉一个已知点,用剩下的点插值出这个位置的值,然后和真实值比较。所有点轮一遍,算均方根误差。
from sklearn.model_selection import LeaveOneOut from sklearn.metrics import mean_squared_error import numpy as np loo = LeaveOneOut() errors = [] for train_idx, test_idx in loo.split(x): # 用训练集拟合 Kriging OK_cv = OrdinaryKriging( x[train_idx], y[train_idx], z[train_idx], variogram_model='spherical', verbose=False, enable_plotting=False ) # 预测被留出的那个点 z_pred_cv, _ = OK_cv.execute( 'points', x[test_idx], y[test_idx] ) errors.append(z[test_idx] - z_pred_cv) errors = np.array(errors).flatten() rmse = np.sqrt(mean_squared_error(z, z + errors)) print(f"交叉验证 RMSE: {rmse:.2f}") print(f"平均误差: {errors.mean():.2f}")execute('points', ...)模式只计算指定坐标点,适合交叉验证。RMSE 越小越好,但要注意:如果 RMSE 比原始数据的标准差还大,说明 Kriging 没学到任何空间结构,不如直接用均值。
我一般会把这个 RMSE 和反距离加权的 RMSE 对比。如果 Kriging 没比反距离加权好多少,说明数据空间自相关性弱,别硬上 Kriging。另一个习惯:交叉验证完,把误差最大的五个点标在地图上,看看它们是不是集中在某个区域。如果是,那个区域可能需要补采样。
提示:交叉验证的 RMSE 受变异函数模型影响很大。换模型后 RMSE 变化超过 20%,说明模型选择比参数调优更重要。
最后说个血泪教训:别在出图前就急着调levels和cmap。先把变异函数拟合图看明白,再把交叉验证跑一遍,最后才动可视化参数。顺序反了,图再好看也是错的。希望帮到你。
本文还有配套的精品资源,点击获取