第一次接触Kriging插值是在处理气象站温度数据时遇到的难题。当时手头只有30个气象站的离散观测数据,却需要生成整个省份的温度分布图。试过线性插值、反距离加权这些传统方法,效果总是不尽人意。直到同事推荐了Kriging方法,才真正体会到什么叫"专业工具干专业活"。
Kriging(克里金)插值是一种基于统计学的空间预测方法,由南非地质学家丹尼·克里金(Danie Krige)在1950年代提出。与普通插值方法不同,它不仅考虑样本点之间的距离关系,还会分析数据的空间自相关性。这就好比经验丰富的老农预测收成,不仅看相邻田地的产量,还会考虑土壤、气候等因素的空间关联性。
在Matlab中实现Kriging插值,最常用的就是DACE(Design and Analysis of Computer Experiments)工具箱。这个工具箱特别适合处理带有地理坐标的二维数据,比如:
我特别喜欢它的一点是,不仅能给出预测值,还能提供预测误差的分布图。这对评估插值结果的可靠性特别重要——就像天气预报不仅告诉你温度,还会说明准确概率。
DACE工具箱的安装比想象中简单得多。官方下载地址是http://www.omicron.dk/dace.html(注意:建议使用正版Matlab和工具箱)。下载zip压缩包后,我习惯把它解压到MATLAB安装目录/toolbox文件夹下。比如我的路径是:
code复制C:\Program Files\MATLAB\R2023a\toolbox\dace
然后在Matlab命令行窗口输入:
matlab复制addpath(genpath('C:\Program Files\MATLAB\R2023a\toolbox\dace'))
savepath
这样就永久添加到了Matlab路径中。为了避免每次重启都要重新添加路径,记得使用savepath命令保存设置。
提示:如果遇到权限问题,可以先把工具箱复制到文档文件夹再添加路径。我在Windows 11上就遇到过管理员权限导致的路径保存失败。
安装完成后,可以用以下命令测试是否成功:
matlab复制which dacefit
如果返回路径信息,说明安装正确。我第一次使用时犯了个低级错误——把工具箱文件夹命名成了中文,结果Matlab死活找不到函数。所以建议保持原英文文件夹名"dace"。
假设我们有20个气象站的坐标和温度数据,存储在一个Excel文件中。先用Matlab导入数据:
matlab复制data = readtable('weather_stations.xlsx');
S = [data.Longitude, data.Latitude]; % 坐标矩阵
Y = data.Temperature; % 观测值
数据清洗是重中之重。我通常会先做异常值检测:
matlab复制figure
geoscatter(S(:,2), S(:,1), 50, Y, 'filled')
colorbar
title('气象站温度分布')
通过地图可视化,能快速发现位置或数值异常的数据点。有次就发现某个站点的经度输错了,导致点落在了非洲(实际应该在亚洲)。
DACE工具箱的核心函数是dacefit和predictor。一个完整的插值流程如下:
matlab复制% 设置Kriging参数
theta = [5 5]; % 初始相关参数
lob = [0.1 0.1]; % 参数下限
upb = [20 20]; % 参数上限
% 模型拟合
[dmodel, perf] = dacefit(S, Y, @regpoly0, @corrgauss, theta, lob, upb);
% 生成预测网格
lon_grid = linspace(min(S(:,1)), max(S(:,1)), 100);
lat_grid = linspace(min(S(:,2)), max(S(:,2)), 100);
[LON, LAT] = meshgrid(lon_grid, lat_grid);
X_pred = [LON(:), LAT(:)];
% 执行预测
[YX_pred, MSE] = predictor(X_pred, dmodel);
这里有几个关键点:
@regpoly0表示使用零阶多项式回归(常数趋势)@corrgauss是高斯相关函数,适合平滑变化的数据把预测结果转回网格格式并绘图:
matlab复制YX_grid = reshape(YX_pred, size(LON));
MSE_grid = reshape(MSE, size(LON));
figure
subplot(1,2,1)
contourf(LON, LAT, YX_grid, 20, 'LineColor', 'none')
hold on
plot(S(:,1), S(:,2), 'ko', 'MarkerFaceColor', 'w')
title('温度预测分布')
colorbar
subplot(1,2,2)
contourf(LON, LAT, MSE_grid, 20, 'LineColor', 'none')
title('预测误差分布')
colorbar
左图显示温度的空间分布,右图是预测标准差。误差大的区域通常出现在数据稀疏处,这很符合直觉——缺少观测点的区域预测不确定性自然更高。
DACE工具箱提供了多种相关函数,常用的有:
@corrgauss:高斯型,适合平滑连续变化@correxp:指数型,适合有突变的数据@corrlin:线性型,计算量小但精度较低选择相关函数就像选相机镜头——没有绝对的好坏,只有适合与否。我通常的做法是:
matlab复制functions = {@corrgauss, @correxp, @corrlin};
perfs = zeros(size(functions));
for i = 1:length(functions)
[~, perfs(i)] = dacefit(S, Y, @regpoly0, functions{i}, theta, lob, upb);
end
比较不同函数的RMSE(perf.rmse),选择误差最小的。但要注意避免过拟合——有时更简单的模型反而更稳健。
theta参数对结果影响巨大。我的调参经验是:
matlab复制theta_range = logspace(-1, 2, 20);
rmse = zeros(size(theta_range));
for i = 1:length(theta_range)
[~, perf] = dacefit(S, Y, @regpoly0, @corrgauss, [theta_range(i) theta_range(i)]);
rmse(i) = perf.rmse;
end
[~, idx] = min(rmse);
optimal_theta = theta_range(idx);
matlab复制theta_fine = linspace(0.8*optimal_theta, 1.2*optimal_theta, 10);
% 重复上述调参过程
有次处理山区降水数据,发现最优theta在经度和纬度方向差异很大。这时就需要分别设置:
matlab复制theta = [3.2 1.8]; % 经度方向3.2,纬度方向1.8
除了@regpoly0,DACE还支持:
@regpoly1:一阶多项式(线性趋势)@regpoly2:二阶多项式(二次趋势)选择原则:
matlab复制trends = {@regpoly0, @regpoly1, @regpoly2};
for i = 1:length(trends)
[dmodel, perf] = dacefit(S, Y, trends{i}, @corrgauss, theta);
fprintf('%s: RMSE=%.3f\n', func2str(trends{i}), perf.rmse);
end
但要注意,高阶趋势项需要更多样本点支持。有次只有15个数据点却用了@regpoly2,结果预测曲面出现了严重振荡。
地理数据常常采样不均匀——城市密集、荒野稀疏。这时普通Kriging可能产生偏差。我的解决方案是:
matlab复制[~, density] = knnsearch(S, S, 'K', 5);
density = mean(density(:,2:end), 2);
dacefit中使用加权回归:matlab复制weights = 1./density; % 稀疏区域权重高
[dmodel, perf] = dacefit(S, Y, @regpoly0, @corrgauss, theta, lob, upb, weights);
当数据点超过5000时,计算量会剧增。可以采用以下优化:
matlab复制function Y_pred = local_kriging(S, Y, X_pred, radius)
Y_pred = zeros(size(X_pred,1),1);
for i = 1:size(X_pred,1)
dist = sqrt(sum((S - X_pred(i,:)).^2, 2));
idx = dist < radius;
[dmodel, ~] = dacefit(S(idx,:), Y(idx), @regpoly0, @corrgauss, theta);
Y_pred(i) = predictor(X_pred(i,:), dmodel);
end
end
matlab复制tree = KDTreeSearcher(S);
idx = rangesearch(tree, X_pred, radius);
要评估模型泛化能力,我常用留一法交叉验证:
matlab复制Y_pred = zeros(size(Y));
for i = 1:length(Y)
S_train = S(setdiff(1:end,i),:);
Y_train = Y(setdiff(1:end,i));
[dmodel, ~] = dacefit(S_train, Y_train, @regpoly0, @corrgauss, theta);
Y_pred(i) = predictor(S(i,:), dmodel);
end
RMSE = sqrt(mean((Y - Y_pred).^2));
R2 = 1 - sum((Y - Y_pred).^2)/sum((Y - mean(Y)).^2);
好的模型应该同时具备低RMSE和高R²。我曾遇到过R²很高但RMSE也大的情况,说明模型存在系统偏差。
当出现"Matrix is close to singular"警告时,通常是因为:
解决方案:
matlab复制% 检查重复点
[~,ia,~] = unique(round(S,4),'rows','stable');
S = S(ia,:); Y = Y(ia);
% 减小theta初始值
theta = [1 1]; lob = [0.01 0.01]; upb = [5 5];
如果预测值出现明显偏差:
我处理过一个案例,温度预测值比观测值普遍高5度。后来发现是趋势项选择不当,改用@regpoly1后问题解决。
对于大规模数据,可以:
'verbose', false关闭迭代显示@corrlin)matlab复制% 快速配置示例
[dmodel, perf] = dacefit(S, Y, @regpoly0, @corrlin, [1 1], [0.1 0.1], [5 5],...
'verbose', false);
如果有Mapping Toolbox,可以生成带坐标系的专业地图:
matlab复制figure
ax = usamap('all');
geoshow(ax, YX_grid, [min(lat_grid), max(lat_grid)],...
[min(lon_grid), max(lon_grid)], 'DisplayType', 'texturemap')
plotm(S(:,2), S(:,1), 'ko', 'MarkerFaceColor', 'w')
title('温度分布图')
colorbar
将结果导出为GIS兼容格式:
matlab复制R = georasterref('RasterSize', size(YX_grid),...
'LatitudeLimits', [min(lat_grid) max(lat_grid)],...
'LongitudeLimits', [min(lon_grid) max(lon_grid)]);
geotiffwrite('temperature.tif', YX_grid, R);
在环境监测网络优化中,可以用Kriging误差指导新增站点位置:
matlab复制% 找出误差最大的区域
[~, idx] = maxk(MSE, 5);
new_sites = X_pred(idx,:);
% 可视化
contourf(LON, LAT, MSE_grid, 'ShowText','on')
hold on
plot(new_sites(:,1), new_sites(:,2), 'rx', 'MarkerSize', 15)