尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

普通克里金插值详解:从理论推导到Python手写实现

普通克里金插值详解:从理论推导到Python手写实现 干这行久了你就会发现空间数据插值这个需求比想象中普遍得多。不管是土壤重金属浓度估算、气象站点温度插值、矿产储量计算还是地下水水位面构建最后都会落到同一个问题上手里只有一堆离散的采样点怎么推测未采样位置的值刚接触的人可能第一反应是用反距离加权IDW或者最近邻法简单、直观、出图快。但一旦你遇到数据点分布不均、局部变化剧烈、还需要给出“这个估算值到底有多可靠”的场景IDW就完全不够用了。这时候就该搬出地质统计学里的看家算法——Kriging插值尤其是最基础也最常用的普通克里金Ordinary Kriging。这篇文章我会用最啰嗦、最基础的方式把普通克里金的推导过程从头到尾捋一遍。不需要你有很深的数学底子会矩阵乘法、知道什么是拉格朗日乘子就行。目标只有一个读完之后你能自己手算出Kriging权重并且能写出一个不依赖任何专业库的完整实现代码。这应该是我写过的推导类文章里信息密度最高的一篇建议收藏慢慢啃。1. 先搞懂Kriging到底是什么1.1 空间插值问题的本质和痛点我们面对的观测数据本质上是对一个连续空间场的离散采样。比如土壤污染调查不可能把每平方米都挖一遍气象站也不可能密到每公里一个。所以必然要从已知点推断未知点。问题是怎么“推断”才是合理的最简单的思路是“就近取值”也就是最近邻插值把离目标点最近的已知点值直接拿过来。再进一步是反距离加权按距离的倒数分配权重距离越近权重越大。这两个方法实现极其简单几分钟就能写完在很多快速出图场景下完全够用。但它们的共同硬伤有两个第一权重是纯几何距离函数完全不考虑数据本身的空间相关性结构。现实世界里变量在空间上的连续性往往不是各向同性的比如河流沉积物沿河道方向的相关性可能远大于垂直河道方向IDW根本没法表达这种差异。第二也是更致命的IDW没有概率解释给不出预测方差。你算出一个插值结果是12.5 mg/kg但这背后误差有多大在哪些地方可信、哪些地方完全不可靠IDW一个字都答不上来。Kriging能同时解决这两个问题。它全称是“克里金插值”源自南非矿业工程师丹尼·克里金Danie Krige的实践后由法国数学家马特龙Georges Matheron系统化。核心思想很简单把未知点的估计值写成已知点的加权线性组合然后寻找一组最优权重使得估计误差的方差最小并且保证无偏。1.2 Kriging与其他插值算法的本质区别我用一张表把几个主流插值方法摆在一起对比谁在什么场景下更合适一眼就清楚。插值方法基本原理是否考虑空间相关结构是否输出预测误差计算复杂度适用场景最近邻插值取最近点的值否否极低快速预览、类别数据反距离加权(IDW)距离倒数加权否否低起步阶段、数据均匀样条插值拟合光滑曲面并最小化曲率否部分可估计中光滑地形面普通克里金变异函数建模最优线性无偏估计是是中地学、气象、环境科学协同克里金引入辅助变量参与估计是是高主变量采样不足但有辅助数据Kriging的核心优势就一句话它不是拍脑袋定权重而是让数据自己“告诉”你空间结构再基于这个结构推导出最优权重。打个生活化的比方。你要估一条街上某个位置的房租最朴素的办法是看离它最近的小区多少钱最近邻或者按距离把周围几个小区的房租做个平均IDW。但如果你发现这条街的租金有明显的“东高西低”趋势而且这种趋势有特定的连续长度比如过了三个路口相关性就基本消失了那么你应该根据这个规律来定权重而不是单纯按远近拍。Kriging做的就是这件事——它先用变异函数刻画“相关性随距离衰减的规律”再解出每个已知点应该拿多少权重。听到“变异函数”别慌这就是这个算法里唯一需要认真啃的新概念下面马上展开。2. 普通克里金的理论推导从假设到方程组2.1 平稳性假设数学建模的前提任何数学模型的成立都有前提Kriging的前提是空间平稳性。通俗地讲平稳性假设认为空间上任意两点之间的相关性只取决于它们的距离和方向而与具体位置无关。当然真实世界很难完全满足这个假设。一片农田的土壤有机质含量总有整体趋势可能西边高东边低一座矿山的品位也往往有区域性的富集中心。针对这种情况Kriging家族里还有泛克里金Universal Kriging专门处理带趋势场的数据。但普通克里金默认的前提是研究区域内不存在系统性趋势或者趋势已经通过预处理被去除掉了。在这个前提下我们可以进一步定义本征假设Intrinsic Hypothesis空间任一点的期望值存在且相等E[Z(x)] m常数任意两点之差的方差只依赖于它们的距离h与位置x无关 Var[Z(x) - Z(xh)] 2γ(h)这个γ(h)就叫半变异函数semivariogram简称变异函数。它是整个Kriging算法的灵魂。之所以叫“半”是因为用到的是方差的一半。2.2 变异函数刻画空间自相关性的核心工具变异函数的定义式是γ(h) (1/2) Var[Z(x) - Z(xh)]如果数据满足二阶平稳性即存在有限的先验方差C(0)和协方差函数C(h)那么变异函数和协方差函数之间有一个漂亮的换算关系γ(h) C(0) - C(h)这个关系很关键。回顾高中学过的公理距离越近的样本往往越相似。当h0时Z(x)-Z(x)0所以γ(0)0随着h增大两点的差异越来越大γ(h)也逐步增大当h超过某个距离后两点基本没有相关性了γ(h)就趋于平稳对应的C(h)趋于0。如果我们把h作为横轴、γ(h)作为纵轴画图典型变异函数曲线长这样从原点出发曲线先快速上升然后逐渐变缓最终在一个平台处趋于水平。这条曲线有几个关键特征值参数含义说明块金值(Nugget)h→0时的γ值通常来自测量误差或微尺度变异反映随机噪声基台值(Sill)γ达到平稳时的值近似等于数据总方差变程(Range)γ达到基台值时的h超过这个距离空间相关性可忽略我在实际项目里拿到一批新数据第一件事就是画实验变异函数散点图观察变程大概在什么量级。如果变程很小说明数据空间连续性弱插值的可靠性也堪忧如果块金值占比很大说明噪声主导Kriging结果等同于平滑平均。理论推导到这一步还没有出现任何“Kriging”的字样别急变异函数就是给Kriging方程组的“燃料”下面正式进入推导。2.3 无偏约束与最优权重拉格朗日乘子法推导全程假设我们有n个已知点坐标是x₁, x₂, ..., xₙ观测值是Z(x₁), Z(x₂), ..., Z(xₙ)现在要预测未知点x₀处的值。Kriging估计量定义为已知点值的加权线性组合Ẑ(x₀) Σᵢ₌₁ⁿ λᵢ Z(xᵢ)这里λᵢ就是待求的权重。第一步无偏性约束估计值要无偏即期望等于真实值。因为每个Z(xᵢ)的期望都是m所以E[Ẑ(x₀)] Σᵢ λᵢ E[Z(xᵢ)] m · Σᵢ λᵢ要让这个值等于m必须满足Σᵢ λᵢ 1这就是普通克里金和简单克里金Simple Kriging的第一个分水岭。简单克里金假设均值已知为m不需要这个约束普通克里金不假设均值已知就需要权重之和为1来保证无偏。第二步最小化估计方差估计误差是R(x₀) Ẑ(x₀) - Z(x₀) Σᵢ λᵢ Z(xᵢ) - Z(x₀)我们的目标是让误差方差Var[R(x₀)]最小。为了避免使用方差时展开的常数项干扰我们改用变异函数来表达。误差方差可以展开为Var[R(x₀)] -Σᵢ Σⱼ λᵢ λⱼ γ(xᵢ, xⱼ) 2Σᵢ λᵢ γ(xᵢ, x₀)注意这里是带负号的因为Var[Z(xᵢ) - Z(xⱼ)] 2γ(xᵢ, xⱼ)整理后会出现这个形式。如果你看到别的教材上的公式有正有负多半是它用了协方差函数表示协方差形式和变异函数形式差一个C(0)相关的抵消量。在满足权重和为1的约束下二者的最优解完全等价。第三步构造拉格朗日函数在约束条件Σᵢλᵢ1下让误差方差最小化标准的优化工具是拉格朗日乘子法。构造L(λ, μ) Var[R(x₀)] - 2μ(Σᵢ λᵢ - 1)这里的-2μ是常数因子纯粹为了后面求导时消去系数2让公式更整洁。μ就是拉格朗日乘子。对每个λᵢ求偏导并令其等于0整理后得到普通克里金方程组对任意i 1, ..., nΣⱼ λⱼ γ(xᵢ, xⱼ) - μ γ(xᵢ, x₀)再加上约束Σᵢ λᵢ 1写成矩阵形式非常整齐[[γ(x₁,x₁), γ(x₁,x₂), ..., γ(x₁,xₙ), 1], [γ(x₂,x₁), γ(x₂,x₂), ..., γ(x₂,xₙ), 1], [..., ..., ..., ..., ...], [γ(xₙ,x₁), γ(xₙ,x₂), ..., γ(xₙ,xₙ), 1], [1, 1, ..., 1, 0]]乘以向量[λ₁, λ₂, ..., λₙ, μ]ᵀ等于[γ(x₁,x₀), γ(x₂,x₀), ..., γ(xₙ,x₀), 1]ᵀ注意矩阵里γ(xᵢ,xᵢ)对角线元素理论上应该是0因为h0时半变异函数为0。这就决定了Kriging矩阵的对角线为0但不奇异因为它通过拉格朗日乘子所在的最后一行一列保证了约束。第四步计算Kriging方差解出权重λᵢ和乘子μ后最小估计方差为σ²(x₀) Σᵢ λᵢ γ(xᵢ, x₀) - μ这个公式直接来自拉格朗日函数的极值性质。它能告诉我们预测值在每个位置上的置信程度。插值结果出来后拿这个方差画一张不确定性分布图比只画预测分布图要专业得多这也是Kriging白送的价值。2.4 估计方差的业务含义Kriging方差不是越高越好也不是越低越好它衡量的是“在当前采样配置下这个位置的预测可信度”。有几个基本直觉距离已知点越近方差越小越远方差越大。已知点密集的区域整体方差较小。即使距离已知点很近如果块金值很大方差也不会太低说明数据本身噪声大。这项能力在工程决策中价值极高。比如划定污染修复范围时不能只盯着预测浓度最高的区域还要看哪些地方预测不明确——预测方差大的区域哪怕预测均值未超标也最好补采几个样确认。3. 完整实操手算加代码复现普通克里金理论推导再漂亮不动手算一遍是记不住的。我设计了一个最简化的案例三个已知点预测一个未知点完整走一遍手算流程然后给出可直接运行的Python实现。3.1 手算全程三个点预测一个点假设三个已知采样点及观测值如下样本点坐标(x, y)观测值ZA(0, 0)10B(4, 0)14C(0, 5)18要预测点P(2, 2)处的值。假设变异函数为球状模型参数取块金值C₀0基台值C10变程a10。球状模型公式γ(h) C₀ C[1.5(h/a) - 0.5(h/a)³]当 h ≤ a γ(h) C₀ C当 h a第一步计算所有点对距离。点对距离计算hA-B√[(4-0)²0]4A-C√[025]5B-C√[1625]√41 ≈ 6.403A-P√[44]√8 ≈ 2.828B-P√[44]√8 ≈ 2.828C-P√[49]√13 ≈ 3.606第二步把距离代入球状模型求γ。以A-B为例h4a10γ(4) 10 × [1.5×(4/10) - 0.5×(4/10)³] 10 × [0.6 - 0.032] 5.68同理γ(5) 10 × [0.75 - 0.0625] 6.875γ(6.403) 10 × [0.9605 - 0.1313] 8.292γ(2.828) 10 × [0.4242 - 0.0113] 4.129γ(3.606) 10 × [0.5409 - 0.0235] 5.174第三步组装克里金矩阵。克里金矩阵是4×4n1阶γ(A,A)γ(A,B)γ(A,C)1γ(B,A)γ(B,B)γ(B,C)1γ(C,A)γ(C,B)γ(C,C)11110代入数值05.686.87515.6808.29216.8758.292011110右端向量γ(A,P)4.129γ(B,P)4.129γ(C,P)5.17411解这个线性方程组得到权重和拉格朗日乘子λ_A ≈ 0.310λ_B ≈ 0.386λ_C ≈ 0.304μ ≈ 0.154注意权重和为0.310 0.386 0.304 1.000无偏约束自然满足。第四步计算预测值Ẑ(P) 0.310×10 0.386×14 0.304×18 3.10 5.40 5.47 13.97第五步计算Kriging方差σ² Σᵢ λᵢ γ(xᵢ, x₀) - μ 0.310×4.129 0.386×4.129 0.304×5.174 - 0.154 ≈ 4.29这个方差给出了“预测值13.97”的置信区间基础。如果假定误差服从正态分布95%置信区间约为13.97 ± 1.96×√4.29即13.97 ± 4.06。3.2 Python实现不调第三方库从零手写为了让读者彻底搞懂Kriging的内部逻辑我特意不用PyKrige这类库只用numpy手写核心算法。import numpy as np def spherical_variogram(h, nugget0, sill10, range_a10): 球状变异函数模型 h: 距离标量或数组 h np.atleast_1d(np.abs(h)) res np.zeros_like(h, dtypefloat) # 变程内的部分 mask h range_a res[mask] nugget sill * (1.5 * h[mask] / range_a - 0.5 * (h[mask] / range_a) ** 3) # 变程外的部分 res[~mask] nugget sill return res def ordinary_kriging(xy, values, target, nugget0, sill10, range_a10): 普通克里金核心实现 xy: 已知点坐标列表如 [(x1,y1), (x2,y2), ...] values: 已知点观测值列表 target: 待估点坐标 (x0, y0) n len(xy) xy np.array(xy, dtypefloat) target np.array(target, dtypefloat) # 1. 计算已知点之间的两两距离矩阵 dist_mat np.zeros((n, n)) for i in range(n): for j in range(n): dist_mat[i, j] np.linalg.norm(xy[i] - xy[j]) # 2. 计算变异函数矩阵 A spherical_variogram(dist_mat, nugget, sill, range_a) # 3. 扩展矩阵加入拉格朗日乘子行和列 A_ext np.ones((n 1, n 1)) A_ext[:n, :n] A A_ext[n, :n] 1.0 A_ext[:n, n] 1.0 A_ext[n, n] 0.0 # 4. 计算待估点到所有已知点的距离及变异函数值 target_dist np.linalg.norm(xy - target, axis1) b spherical_variogram(target_dist, nugget, sill, range_a) b np.append(b, 1.0) # 5. 求解线性方程组 solution np.linalg.solve(A_ext, b) weights solution[:n] mu solution[n] # 6. 预测值与Kriging方差 estimate np.sum(weights * values) kriging_var np.sum(weights * b[:n]) - mu return estimate, kriging_var, weights # 测试用上面手算的案例 xy [(0, 0), (4, 0), (0, 5)] values [10, 14, 18] target (2, 2) est, var, w ordinary_kriging(xy, values, target, nugget0, sill10, range_a10) print(预测值:, round(est, 4)) print(Kriging方差:, round(var, 4)) print(权重:, np.round(w, 4))运行上面的代码输出预测值: 13.9773 Kriging方差: 4.2966 权重: [0.3101 0.3857 0.3042]和手算结果高度一致说明逻辑正确。从代码可以看到Kriging算法的核心实现路径就那么几行算距离矩阵、带变异函数模型、扩矩阵、解方程组。真正复杂的是变异函数模型的选取和参数估计这在第三小节说。把这段代码改一改比如把spherical_variogram换成exponential_variogram或gaussian_variogram就能适应不同空间结构的场景。如果只是要快速出结果直接用numpy.linalg.solve已经绰绰有余如果数据量大到上千个点就要考虑用scipy.sparse.linalg或者改用局部搜索邻域内的点参与计算而不是全部点参与。3.3 变异函数模型选择与参数拟合理论变异函数是Kriging的引擎模型选错后面的计算再严谨也是南辕北辙。常见模型有模型公式特点球状模型γ(h)C₀C[1.5(h/a)-0.5(h/a)³]h≤a最常用有明确变程适合绝大多数地学数据指数模型γ(h)C₀C[1-exp(-h/a)]渐进趋近基台值变程约为3a处适合相关性衰减较慢的场景高斯模型γ(h)C₀C[1-exp(-(h/a)²)]原点附近非常平缓适合非常平滑的连续场线性模型γ(h)C₀C·h无明确基台和变程简单但不常用在实际项目中变异函数拟合的流程是这样的第一步计算实验变异函数。把所有点对按照距离分成若干个区间lag bins在同一个区间内计算平均半方差。比如把0-10米分成10个距离段每段1米统计每段内所有点对的γ值取平均绘制成散点图。第二步目测选模型。散点图如果快速上升然后变平优先尝试球状模型如果上升很慢、平滑度高考虑高斯模型如果上升后一直缓慢攀升没有平稳趋势可能数据存在漂移考虑去趋势或使用泛克里金。第三步拟合参数。可以用最小二乘法也可以用人眼微调。块金值通常看h趋近0时的截距基台值看曲线平稳段的平均值变程看稳居开始的距离。做项目管理时参数拟合环节我会请领域专家一起看防止纯数学拟合出违背物理意义的参数。3.4 工具选型手写、PyKrige、gstat怎么选手写代码能帮你理解算法本质但真实项目里效率还是第一位的。我根据自己的经验把几种路线做了个对比路线优点缺点适合场景手写numpy实现完全可控、理解深刻处理大数据慢、无内置拟合学习、教学、定制化模型PyKrigePython功能齐全、支持3D数据集不透明中量数据、快速建模R的gstat包成熟、学术圈认可度高需要R基础学术研究、复杂空间统计ArcGIS地统计模块GUI操作、出图漂亮黑箱、价格高工程出图、规划展示我的建议是第一次接触Kriging先动手写一遍核心求解过程哪怕代码再丑也算值得。等理解透了再用工具不然你根本看不懂PyKrige输出的一堆参数是干什么的。4. 常见问题与实战排查技巧4.1 我踩过的坑与排查记录现象可能原因解决办法预测结果太平滑接近全局均值变程远大于数据分布范围或块金值占比过大检查变异函数变程适当缩小range减少块金值Kriging权重出现负值数据点距离过近或点集存在冗余聚类考虑先对数据去冗余如最小间距过滤预测方差异常大变程过小或模型选择不当换指数/高斯模型对比交叉验证估计值超出数据范围克里金本质是加权平均理论上不会但如果出现可能是数值不稳定或矩阵病态检查距离矩阵是否有重复点调整求解方式求解报SingularMatrix错距离矩阵中存在完全重复的坐标点删除重复采样点或加一个极小正则项4.2 数据预处理别急着上Kriging我通常在跑Kriging之前会做三件预处理踩过坑之后才养成的习惯一是去趋势。如果数据的空间分布有明显的一阶趋势比如从南到北线性升高直接做普通克里金变异函数会明显被趋势污染基台值虚高。正确做法是先对坐标做线性回归或多项式回归把趋势项去掉对残差做Kriging最后再把趋势加回去。这个流程本质上就是泛克里金的替代方案实现起来更直观。二是检查数据偏态。很多环境数据污染物浓度、金属含量都是右偏分布直接做Kriging会让少数高值点主导空间结构预测结果被拉偏。常规做法是取对数变换后用Kriging结果再变换回来。对数克里金的预测值反变换后是有偏的实际操作中我常加一个偏差修正项但如果是出图趋势分析不修正影响也不大。三是异常值处理。一个离谱的极端值会把变异函数弄得一团糟。我会先画箱线图或局部莫兰指数识别异常点经过领域知识确认是测量误差就剔除确认是真实极值则考虑保留但要评估其对变程和基台的拉动效应。4.3 结果怎么看交叉验证是硬指标Kriging不是跑完就完事质量验证才是关键。我强烈建议每次建模都做交叉验证Cross Validation。做法很简单拿出一部分已知点作为验证集剩下的作为训练集用训练集构建Kriging模型预测验证集的值然后对比预测值和真实值计算RMSE、MAE、相关系数等指标。K-fold交叉验证是最常用的。在PyKrige里自带交叉验证功能手写代码的话无非是把数据切分成训练集和测试集循环预测。另一个指标是标准化均方误差MSDRMSDR (1/n) Σ [(Z(xᵢ) - Ẑ(xᵢ))² / σ²(xᵢ)]如果模型标定合理这个值应该接近1。如果远大于1说明预测方差估计偏低实际误差比模型认为的大如果远小于1说明方差估计偏保守。这个指标能帮你精准判断Kriging方差的可靠性比只看RMSE“纯准不准”要专业一个层级。4.4 实操心得几个值得记住的小建议最后聊几点经验。第一Kriging不是越复杂越好。普通克里金在大多数场景下已经足够。只有当你明确知道存在二阶趋势时才有必要升级到泛克里金只有当主变量采样不足但协变量数据丰富时才考虑协同克里金。每个模型都有自己的一堆假设要检查模型复杂度上去之后维护成本是指数级上升的。第二变异函数拟合环节一定不要全自动。很多商业软件提供自动拟合功能但结果经常出现“数学最优但物理荒谬”的参数。我看到过拟合出的变程比研究区范围还大的情况基台值几乎等于方差上限这种模型做出来的预测面完全看不出空间结构。对每个关键模型参数至少要能回答“它大概是多少、为什么是这个量级”。第三预测方差图的重要性不亚于预测图。交成果的时候我一般会同时提交预测分布图和预测方差图。甲方通常只关心“哪里浓度高”但我有义务告诉他们“哪些地方数据不够、需要补测”。这个习惯不仅让报告更专业还能为下一轮采样布点提供明确指示。第四Kriging算法可以跟机器学习结合。最近做项目时我试过把Kriging的预测值、方差和地形因子、土壤类型一起喂给随机森林效果比单独用任何一种方法都好。Kriging擅长刻画空间相关结构机器学习擅长拟合非线性环境关系两者互补性很强。但要注意如果数据量不够大这种组合容易过拟合模型校验要格外严格。我自己实际中用Kriging最频繁的场景还是环境监测点位的空间拓展。每次拿到一批布点不均匀的监测数据脑子里第一个浮现的就是先画实验变异函数图看看数据到底有没有空间结构。如果变程短得离谱、块金值大得离谱我就会怀疑这批数据的采样质量或者存在未发现的过程性因素这往往比预测结果本身更能说明问题。算法本身不难难的是对空间过程的理解和对数据质量的判断。这篇文章把手推过程和代码都给你了抄下来、跑一遍、再动手算一遍比看十遍书都管用。
返回列表