Python案例如何实现数据插值?

wen python案例 2

本文目录导读:

Python案例如何实现数据插值?

  1. 一维插值
  2. 二维插值
  3. 实际应用案例:缺失数据填充
  4. 插值方法选择指南

我来介绍几种在Python中实现数据插值的常用方法。

一维插值

使用 SciPy 的 interp1d

import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
# 原始数据点
x = np.array([0, 1, 2, 3, 4, 5])
y = np.array([0, 2, 1, 4, 3, 6])
# 创建插值函数
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值用于插值
x_new = np.linspace(0, 5, 50)
# 计算插值结果
y_linear = f_linear(x_new)
y_cubic = f_cubic(x_new)
y_quadratic = f_quadratic(x_new)
# 可视化结果
plt.figure(figsize=(10, 6))
plt.plot(x, y, 'o', label='原始数据', markersize=8)
plt.plot(x_new, y_linear, '-', label='线性插值', linewidth=2)
plt.plot(x_new, y_cubic, '--', label='三次样条插值', linewidth=2)
plt.plot(x_new, y_quadratic, ':', label='二次插值', linewidth=2)
plt.legend()
plt.xlabel('x')
plt.ylabel('y')'一维插值示例')
plt.grid(True)
plt.show()

使用 NumPy 的插值函数

import numpy as np
# 原始数据
x = np.array([0, 1, 2, 3, 4, 5])
y = np.array([0, 2, 1, 4, 3, 6])
# 使用 numpy 的 interp 函数(线性插值)
x_new = np.array([0.5, 1.5, 2.5, 3.5, 4.5])
y_new = np.interp(x_new, x, y)
print("原始数据点:")
for i in range(len(x)):
    print(f"({x[i]}, {y[i]})")
print(f"\n插值点:")
for i in range(len(x_new)):
    print(f"x={x_new[i]}, y={y_new[i]:.2f}")

二维插值

使用 griddata 进行散点插值

import numpy as np
from scipy.interpolate import griddata
import matplotlib.pyplot as plt
# 生成原始散点数据
np.random.seed(42)
n_points = 100
x = np.random.uniform(-3, 3, n_points)
y = np.random.uniform(-3, 3, n_points)
# 生成真实函数值
z = np.sin(x) * np.cos(y) + 0.1 * np.random.randn(n_points)
# 创建网格用于插值
xi = np.linspace(-3, 3, 100)
yi = np.linspace(-3, 3, 100)
xi, yi = np.meshgrid(xi, yi)
# 不同的插值方法
zi_linear = griddata((x, y), z, (xi, yi), method='linear')
zi_cubic = griddata((x, y), z, (xi, yi), method='cubic')
zi_nearest = griddata((x, y), z, (xi, yi), method='nearest')
# 可视化结果
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
# 原始散点图
axes[0, 0].scatter(x, y, c=z, cmap='viridis', edgecolor='black', s=50)
axes[0, 0].set_title('原始散点数据')
axes[0, 0].set_xlabel('x')
axes[0, 0].set_ylabel('y')
# 线性插值
im1 = axes[0, 1].contourf(xi, yi, zi_linear, cmap='viridis')
axes[0, 1].set_title('线性插值')
axes[0, 1].set_xlabel('x')
axes[0, 1].set_ylabel('y')
plt.colorbar(im1, ax=axes[0, 1])
# 三次样条插值
im2 = axes[1, 0].contourf(xi, yi, zi_cubic, cmap='viridis')
axes[1, 0].set_title('三次样条插值')
axes[1, 0].set_xlabel('x')
axes[1, 0].set_ylabel('y')
plt.colorbar(im2, ax=axes[1, 0])
# 最近邻插值
im3 = axes[1, 1].contourf(xi, yi, zi_nearest, cmap='viridis')
axes[1, 1].set_title('最近邻插值')
axes[1, 1].set_xlabel('x')
axes[1, 1].set_ylabel('y')
plt.colorbar(im3, ax=axes[1, 1])
plt.tight_layout()
plt.show()

使用 RectBivariateSpline 进行规则网格插值

import numpy as np
from scipy.interpolate import RectBivariateSpline
import matplotlib.pyplot as plt
# 创建规则网格数据
x = np.linspace(-2, 2, 10)
y = np.linspace(-2, 2, 10)
X, Y = np.meshgrid(x, y)
Z = np.sin(X) * np.cos(Y) + 0.1 * np.random.randn(10, 10)
# 创建样条插值函数
spline = RectBivariateSpline(x, y, Z.T, kx=3, ky=3)  # kx, ky是样条阶数
# 创建更密的网格用于插值
x_new = np.linspace(-2, 2, 50)
y_new = np.linspace(-2, 2, 50)
Z_new = spline(x_new, y_new)
# 可视化
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 5))
# 原始数据
im1 = ax1.pcolormesh(X, Y, Z, cmap='viridis')
ax1.set_title('原始规则网格数据')
plt.colorbar(im1, ax=ax1)
# 插值后的数据
X_new, Y_new = np.meshgrid(x_new, y_new)
im2 = ax2.pcolormesh(X_new, Y_new, Z_new, cmap='viridis')
ax2.set_title('三次样条插值')
plt.colorbar(im2, ax=ax2)
plt.tight_layout()
plt.show()

实际应用案例:缺失数据填充

import numpy as np
import pandas as pd
from scipy import interpolate
import matplotlib.pyplot as plt
# 创建包含缺失值的时间序列数据
np.random.seed(42)
dates = pd.date_range('2023-01-01', periods=30, freq='D')
values = np.sin(np.linspace(0, 3*np.pi, 30)) + np.random.normal(0, 0.3, 30)
# 人为加入缺失值
missing_indices = [5, 6, 12, 13, 14, 20, 21]
values[missing_indices] = np.nan
# 提取非缺失值
valid_mask = ~np.isnan(values)
x_valid = np.arange(len(values))[valid_mask]
y_valid = values[valid_mask]
# 使用插值填充缺失值
x_all = np.arange(len(values))
# 线性插值
f_linear = interpolate.interp1d(x_valid, y_valid, kind='linear', 
                                fill_value='extrapolate')
y_filled_linear = f_linear(x_all)
# 三次样条插值
f_cubic = interpolate.interp1d(x_valid, y_valid, kind='cubic', 
                               fill_value='extrapolate')
y_filled_cubic = f_cubic(x_all)
# 可视化结果
plt.figure(figsize=(12, 6))
# 原始数据(包含缺失值)
plt.plot(dates, values, 'o-', label='原始数据(含缺失值)', 
         linewidth=2, markersize=6)
# 填充后的数据
plt.plot(dates, y_filled_linear, 's-', label='线性插值填充', 
         linewidth=2, markersize=4, alpha=0.7)
plt.plot(dates, y_filled_cubic, '^--', label='三次样条插值填充', 
         linewidth=2, markersize=4, alpha=0.7)
# 标记缺失位置
plt.scatter(dates[missing_indices], y_filled_linear[missing_indices], 
           color='red', s=100, label='插值点', zorder=5)
plt.xlabel('日期')
plt.ylabel('值')'时间序列数据缺失值插值填充')
plt.legend()
plt.xticks(rotation=45)
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
# 输出插值结果
print("缺失值插值结果:")
for idx in missing_indices:
    print(f"日期 {dates[idx].strftime('%Y-%m-%d')}: "
          f"线性插值 = {y_filled_linear[idx]:.3f}, "
          f"三次样条插值 = {y_filled_cubic[idx]:.3f}")

插值方法选择指南

插值方法 适用场景 特点
线性插值 数据变化平缓 简单快速,但导数不连续
三次样条 需要平滑曲线 二阶导数连续,结果平滑
最近邻 分类数据 简单,但结果不连续
多项式插值 数据点较少 可能产生振荡(龙格现象)
径向基函数 散乱数据 灵活,适用于高维数据

Python中数据插值的主要工具:

  1. NumPy: np.interp() 用于简单线性插值
  2. SciPy: interp1d(), griddata(), RectBivariateSpline()
  3. Pandas: DataFrame.interpolate() 用于时间序列插值

选择插值方法时需考虑数据特性、精度要求和计算效率。

抱歉,评论功能暂时关闭!