Python中优化插值数组:最小误差缩减尺寸的标准方法
3D数组插值后优化采样点缩减尺寸的解决方案
问题描述
我在Python中处理一个51×51×181的3D数组,需要做3D插值(可计算任意中间点)。现在要在保持数组元素总数不变的前提下缩减数组尺寸,同时尽可能降低插值误差。示例中的Angles和Shifts不需要等间距,我已经写出了误差函数,但在SciPy里找不到合适的优化器,想问有没有标准解决方案?
示例代码
import numpy as np from scipy.interpolate import RegularGridInterpolator import itertools Data = np.zeros((5, 180)) Angles = np.linspace(0, 360, 10) Shifts = np.linspace(0, 100, 10) Data = np.sin(np.deg2rad(Angles[:, None] + Shifts[None, :])) interp = RegularGridInterpolator((Angles, Shifts), Data, bounds_error=False, fill_value=None) def errorfunc(): Angles = np.linspace(0, 360, 50) Shifts = np.linspace(0, 100, 50) Function_Results = np.sin(np.deg2rad(Angles[:, None] + Shifts[None, :]).flatten()) Data_interp = interp(np.array(list(itertools.product(Angles, Shifts)))) Error = np.sqrt(np.mean(np.square(Function_Results - Data_interp))) return Error
标准解决方案思路
1. 基于优化器的自适应采样调整
这是解决这类非均匀采样优化问题的核心方案,把采样点位置作为优化变量,用你的误差函数作为目标函数,调用通用优化器求解:
- 变量定义:将原等间距采样点(如Angles、Shifts)替换为可调整的变量,需保证各维度点数的乘积等于原数组总元素数(比如原51×51×181=466201,可调整为200×200×117这类接近的组合)。
- 适配SciPy优化器:使用
scipy.optimize.minimize,需要把你的误差函数改成接受变量输入的形式——将采样点展平为一维数组传入函数,内部再整理成有序的采样轴,计算插值误差。 - 约束设置:必须添加边界约束(比如Angles限制在0-360,Shifts限制在0-100),还要添加单调递增约束(保证采样点有序,插值器能正常工作),可通过
constraints参数结合type='ineq'实现。
2. 结合数据特征的预采样优化
如果数据存在明显的高频变化区域(比如某些角度/位移区间数值波动剧烈),可以先做特征分析再优化:
- 计算原数据在各维度的梯度或二阶导数,定位变化剧烈的区域,在这些区域加密采样,平缓区域稀疏采样,能在总点数不变的前提下大幅降低误差。
- 可以先按等间距缩减点数,再用优化器微调采样点位置,兼顾效率和精度。
3. 改用径向基函数(RBF)插值
如果RegularGridInterpolator的规则限制过多,可尝试SciPy的Rbf插值——它天然支持非均匀采样点。优化思路和之前一致:将采样点位置作为变量,最小化插值误差,缺点是计算成本较高,适合中小规模数据。
适配优化器的误差函数示例
import numpy as np from scipy.interpolate import RegularGridInterpolator import itertools from scipy.optimize import minimize # 原数据与初始插值器 Angles_orig = np.linspace(0, 360, 10) Shifts_orig = np.linspace(0, 100, 10) Data = np.sin(np.deg2rad(Angles_orig[:, None] + Shifts_orig[None, :])) interp_orig = RegularGridInterpolator((Angles_orig, Shifts_orig), Data, bounds_error=False, fill_value=None) # 目标:保持总点数100(10×10)不变,调整采样点位置 n_angles = 10 n_shifts = 10 def error_func(x): # x前n_angles个元素为Angles,后n_shifts个为Shifts,强制排序保证有序 angles = np.sort(x[:n_angles]) shifts = np.sort(x[n_angles:]) # 构建新插值器 interp_new = RegularGridInterpolator((angles, shifts), Data, bounds_error=False, fill_value=None) # 计算误差 test_angles = np.linspace(0, 360, 50) test_shifts = np.linspace(0, 100, 50) test_points = np.array(list(itertools.product(test_angles, test_shifts))) true_vals = np.sin(np.deg2rad(test_points[:,0] + test_points[:,1])) interp_vals = interp_new(test_points) return np.sqrt(np.mean(np.square(true_vals - interp_vals))) # 初始猜测:等间距采样点 x0 = np.concatenate([np.linspace(0, 360, n_angles), np.linspace(0, 100, n_shifts)]) # 边界约束 bounds = [(0, 360)]*n_angles + [(0, 100)]*n_shifts # 单调递增约束:保证后一个采样点≥前一个 constraints = [] for i in range(n_angles-1): constraints.append({'type': 'ineq', 'fun': lambda x, i=i: x[i+1] - x[i]}) for i in range(n_shifts-1): constraints.append({'type': 'ineq', 'fun': lambda x, i=i: x[n_angles + i+1] - x[n_angles + i]}) # 执行优化(用SLSQP处理带约束的优化问题) result = minimize(error_func, x0, bounds=bounds, constraints=constraints, method='SLSQP') # 提取优化后的采样点 optimized_angles = np.sort(result.x[:n_angles]) optimized_shifts = np.sort(result.x[n_angles:])
内容的提问来源于stack exchange,提问作者Okapi575
相关产品推荐
相关产品推荐

