PyKrige泛克里金插值如何设置高程为外部漂移项
问题原因
你遇到的报错和插值结果异常来自三个核心问题:
- 初始化
UniversalKriging时指定了functional漂移类型,但未定义传入的func函数,触发了参数校验逻辑报出点漂移相关错误 - 要将高程作为协变量做漂移,应该使用内置的
external_drift漂移类型,不需要自定义泛函 - 现有代码的数据流完全没有纳入高程字段,既没有给训练阶段传入采样点高程,也没有给插值阶段传入网格点高程,漂移项缺少必要输入
修正方案
1. 补全全链路高程数据传递
从数据读取、数据扩展到网格生成的全流程,都需要把高程字段和经纬度、观测值做一一对应绑定,不能只传经纬度和O18观测值。
2. 准备插值网格的高程数据
外部漂移的硬性要求是:所有待插值的网格点必须有对应的高程值。你需要使用和研究区匹配的DEM高程产品,采样到你生成的经纬度网格上,得到和网格x/y维度完全一致的高程数组。如果暂时没有合适的DEM,也可以先对采样点高程做初步插值得到网格高程,正式计算建议使用实测DEM以保证精度。
你已知的-0.2‰/100m的高程梯度是经验值,不需要手动写入代码,泛克里金算法会自动拟合漂移项的最优系数,和经验值做对照即可。
3. 修正克里金初始化和执行参数
把漂移类型改为external_drift,初始化时传入和采样点一一对应的高程数组,执行网格插值时传入和网格一一对应的高程数组即可。
修正后的核心代码
把你原有代码中对应函数替换为以下版本即可:
import numpy as np from pykrige.uk import UniversalKriging import matplotlib.pyplot as plt from mpl_toolkits.basemap import Basemap import pandas as pd def load_data(): # 替换为你的本地csv路径 df = pd.read_csv(r"your_local_file_path.csv") return df def get_data(df): return { "lons": df['Longitude'].values, "lats": df['Latitude'].values, "values": df['O18'].values, "alts": df['Altitude'].values } def extend_data(data): # 如果你的研究区不跨180度经线,可直接删掉这个函数,不需要做经度扩展 return { "lons": np.concatenate([data["lons"]-360, data["lons"], data["lons"]+360]), "lats": np.concatenate([data["lats"]]*3), "values": np.concatenate([data["values"]]*3), "alts": np.concatenate([data["alts"]]*3) } def generate_grid(data, basemap, delta=1): grid = { 'lon': np.arange(-180, 180, delta), 'lat': np.arange(np.amin(data["lats"]), np.amax(data["lats"]), delta) } grid["x"], grid["y"] = np.meshgrid(grid["lon"], grid["lat"]) grid["x"], grid["y"] = basemap(grid["x"], grid["y"]) # === 这里必须替换成你自己的DEM采样结果 === # 要求数组shape和grid["x"]完全一致,高程单位为米,无缺测值 grid["alt"] = sample_your_dem_to_grid(grid["lon"], grid["lat"]) return grid def interpolate(data, grid): uk = UniversalKriging( x = data["lons"], y = data["lats"], z = data["values"], variogram_model='exponential', verbose=True, drift_terms=["external_drift"], external_drift = data["alts"] ) return uk.execute("grid", grid["lon"], grid["lat"], external_drift_grid=grid["alt"]) def prepare_map_plot(): figure, axes = plt.subplots(figsize=(10,10)) basemap = Basemap(projection='robin', lon_0=0, lat_0=0, resolution='h',area_thresh=1000,ax=axes) return figure, axes, basemap def plot_mesh_data(interpolation, grid, basemap): colormesh = basemap.contourf(grid["x"], grid["y"], interpolation,32, cmap='RdBu_r') color_bar = basemap.colorbar(colormesh,location='bottom',pad="10%") if __name__ == "__main__": df = load_data() base_data = get_data(df) figure, axes, basemap = prepare_map_plot() grid = generate_grid(base_data, basemap, delta=1) # 原代码delta=90分辨率过粗,调整为1度 extended_data = extend_data(base_data) interpolation, interpolation_error = interpolate(extended_data, grid) plot_mesh_data(interpolation, grid,basemap) plt.show()
注意事项
- 所有高程数据单位必须统一,建议全部使用米为单位
- 传入的采样点高程长度必须和经纬度、观测值长度完全一致;网格高程的维度必须和插值网格完全匹配,否则会报维度不匹配错误
- 原代码设置的90度网格分辨率过粗,远低于常规同位素采样点的分布密度,建议根据实际采样点间距调整delta值,一般取采样点平均间距的1/2~1/3即可
- 如果研究区不跨180度国际日期变更线,直接删掉经度扩展的
extend_data逻辑即可,重复拼接的全球数据会干扰变异函数拟合,降低插值精度
内容的提问来源于stack exchange,提问作者Weiss
相关产品推荐
相关产品推荐

