本文目录导读:

我来详细介绍如何使用Scipy进行插值计算,包括几种常用的插值方法。
基础准备
import numpy as np from scipy import interpolate import matplotlib.pyplot as plt # 设置中文显示 plt.rcParams['font.sans-serif'] = ['SimHei'] plt.rcParams['axes.unicode_minus'] = False
一维插值方法
1 线性插值 (interp1d)
# 创建样本数据
x = np.linspace(0, 10, 11) # 11个点
y = np.sin(x)
# 创建插值函数
f_linear = interpolate.interp1d(x, y, kind='linear')
f_cubic = interpolate.interp1d(x, y, kind='cubic')
f_quadratic = interpolate.interp1d(x, y, kind='quadratic')
# 生成插值点
x_new = np.linspace(0, 10, 101)
# 计算插值
y_linear = f_linear(x_new)
y_cubic = f_cubic(x_new)
y_quadratic = f_quadratic(x_new)
# 可视化
plt.figure(figsize=(12, 8))
plt.plot(x, y, 'o', label='原始数据点', markersize=8)
plt.plot(x_new, y_linear, '-', label='线性插值')
plt.plot(x_new, y_cubic, '--', label='三次样条插值')
plt.plot(x_new, y_quadratic, ':', label='二次插值')
plt.plot(x_new, np.sin(x_new), 'k-', label='真实函数', alpha=0.5)
plt.legend()
plt.xlabel('x')
plt.ylabel('y')'不同插值方法比较')
plt.grid(True)
plt.show()
2 样条插值
# 使用样条插值 x = np.linspace(0, 10, 10) y = np.sin(x) # 创建样条插值对象 spline = interpolate.UnivariateSpline(x, y) spline_smooth = interpolate.UnivariateSpline(x, y, s=0.5) # 带平滑参数 # 生成插值点 x_new = np.linspace(0, 10, 100) y_spline = spline(x_new) y_spline_smooth = spline_smooth(x_new) plt.figure(figsize=(10, 6)) plt.plot(x, y, 'o', label='原始数据', markersize=8) plt.plot(x_new, y_spline, '-', label='样条插值') plt.plot(x_new, y_spline_smooth, '--', label='平滑样条(s=0.5)') plt.plot(x_new, np.sin(x_new), 'k:', label='真实函数') plt.legend()'样条插值示例') plt.grid(True) plt.show()
多维插值
1 二维插值 (griddata)
from scipy.interpolate import griddata
# 创建二维散点数据
np.random.seed(42)
points = np.random.rand(100, 2) * 10 # 100个随机点
values = np.sin(points[:, 0]) * np.cos(points[:, 1]) # 函数值
# 创建网格
xi = np.linspace(0, 10, 50)
yi = np.linspace(0, 10, 50)
xi, yi = np.meshgrid(xi, yi)
# 不同插值方法
methods = ['linear', 'cubic', 'nearest']
fig, axes = plt.subplots(1, 4, figsize=(16, 4))
# 原始数据点
axes[0].scatter(points[:, 0], points[:, 1], c=values, cmap='viridis', s=50)
axes[0].set_title('原始散点数据')
# 各种插值方法
for i, method in enumerate(methods, 1):
zi = griddata(points, values, (xi, yi), method=method)
im = axes[i].imshow(zi, extent=[0, 10, 0, 10], origin='lower',
cmap='viridis', aspect='auto')
axes[i].set_title(f'{method}插值')
plt.colorbar(im, ax=axes[i])
plt.tight_layout()
plt.show()
2 二维样条插值 (RectBivariateSpline)
# 创建规则的二维网格数据
x = np.linspace(0, 10, 20)
y = np.linspace(0, 10, 20)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y)
# 创建二维样条插值
spline_2d = interpolate.RectBivariateSpline(x, y, Z)
# 生成精细网格
x_new = np.linspace(0, 10, 100)
y_new = np.linspace(0, 10, 100)
Z_new = spline_2d(x_new, y_new)
# 可视化
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
im1 = ax1.imshow(Z, extent=[0, 10, 0, 10], origin='lower', cmap='coolwarm', aspect='auto')
ax1.set_title('原始数据(20x20)')
plt.colorbar(im1, ax=ax1)
im2 = ax2.imshow(Z_new, extent=[0, 10, 0, 10], origin='lower', cmap='coolwarm', aspect='auto')
ax2.set_title('插值后(100x100)')
plt.colorbar(im2, ax=ax2)
plt.tight_layout()
plt.show()
实际应用案例
1 温度数据插值
# 模拟气象站温度数据
hours = np.array([0, 3, 6, 9, 12, 15, 18, 21]) # 测量时间
temperatures = np.array([15, 12, 10, 18, 25, 28, 22, 17]) # 温度(°C)
# 创建连续时间点
hours_dense = np.linspace(0, 24, 241) # 每10分钟一个点
# 不同插值方法比较
methods = {
'线性': 'linear',
'二次': 'quadratic',
'三次': 'cubic'
}
plt.figure(figsize=(12, 6))
for label, method in methods.items():
f = interpolate.interp1d(hours, temperatures, kind=method)
temp_dense = f(hours_dense)
plt.plot(hours_dense, temp_dense, label=label, linewidth=2)
plt.plot(hours, temperatures, 'ro', label='观测数据', markersize=10)
plt.xlabel('时间 (小时)')
plt.ylabel('温度 (°C)')'气温变化插值')
plt.legend()
plt.grid(True)
plt.xticks(range(0, 25, 3))
plt.show()
2 缺失数据填充
# 模拟带有缺失值的时间序列
time = np.arange(0, 10, 0.5)
data = np.sin(time)
data[5:8] = np.nan # 人为制造缺失值
# 分离有效数据和缺失位置
valid_idx = ~np.isnan(data)
time_valid = time[valid_idx]
data_valid = data[valid_idx]
# 对缺失值进行插值
f = interpolate.interp1d(time_valid, data_valid, kind='cubic')
time_missing = time[~valid_idx]
data_filled = f(time_missing)
# 可视化
plt.figure(figsize=(12, 5))
plt.plot(time, np.sin(time), 'g-', label='真实值', alpha=0.5)
plt.plot(time[valid_idx], data_valid, 'bo', label='有效数据', markersize=8)
plt.plot(time_missing, data_filled, 'r^', label='插值填充', markersize=8)
plt.xlabel('时间')
plt.ylabel('数值')'缺失数据插值填充')
plt.legend()
plt.grid(True)
plt.show()
高级插值方法
1 径向基函数插值 (RBF)
from scipy.interpolate import RBFInterpolator
# 创建不规则散点数据
np.random.seed(42)
x = np.random.rand(50) * 10
y = np.random.rand(50) * 10
values = np.sin(x) * np.cos(y) + np.random.randn(50) * 0.1
# 创建RBF插值
rbf = RBFInterpolator(np.column_stack([x, y]), values, kernel='multiquadric')
# 创建网格进行评估
x_grid, y_grid = np.meshgrid(np.linspace(0, 10, 100), np.linspace(0, 10, 100))
z_grid = rbf(np.column_stack([x_grid.ravel(), y_grid.ravel()]))
z_grid = z_grid.reshape(x_grid.shape)
# 可视化
plt.figure(figsize=(10, 8))
plt.contourf(x_grid, y_grid, z_grid, levels=20, cmap='viridis')
plt.colorbar(label='插值值')
plt.scatter(x, y, c=values, s=100, edgecolor='white', linewidth=1, cmap='viridis')
plt.xlabel('X')
plt.ylabel('Y')'径向基函数插值')
plt.show()
性能比较
import time
# 生成测试数据
n_points = [10, 50, 100, 500, 1000]
methods = {'linear': 'linear', 'cubic': 'cubic', 'quadratic': 'quadratic'}
performance = {method: [] for method in methods}
for n in n_points:
x = np.linspace(0, 10, n)
y = np.sin(x)
x_new = np.linspace(0, 10, 1000)
for name, kind in methods.items():
start = time.time()
f = interpolate.interp1d(x, y, kind=kind)
y_new = f(x_new)
end = time.time()
performance[name].append(end - start)
# 绘制性能比较图
plt.figure(figsize=(10, 6))
for method, times in performance.items():
plt.plot(n_points, times, 'o-', label=method, linewidth=2)
plt.xlabel('数据点数量')
plt.ylabel('计算时间 (秒)')'插值方法性能比较')
plt.legend()
plt.grid(True)
plt.xscale('log')
plt.yscale('log')
plt.show()
Scipy提供了丰富的插值工具:
- 一维插值:使用
interp1d,支持多种插值方法 - 样条插值:
UnivariateSpline提供更灵活的平滑控制 - 多维插值:
griddata处理不规则数据,RectBivariateSpline处理规则网格 - 高级方法:RBF插值适合不规则散点数据
选择插值方法时需要考虑:
- 数据特点(规则/不规则)
- 精度要求
- 计算效率
- 是否需要平滑
这样就能应对大多数插值应用场景了!