含Datetime类型X值的二维双线性插值实现及绘图示例请求
双线性插值处理含Datetime坐标的DataFrame并绘图示例
我明白你的痛点——scipy.interpolate.interp2d不支持直接传入Datetime类型的坐标,而且原始数据是长格式的,需要整理成插值函数要求的结构。下面是针对你的DataFrame的完整解决方案,包含代码和可视化:
第一步:修正并生成原始数据
先把你提供的代码补全修正(比如import语句分开,确保数据生成逻辑正确):
import pandas as pd import numpy as np from scipy.interpolate import interp2d import matplotlib.pyplot as plt from matplotlib.dates import DateFormatter # 生成原始时间序列(5分钟间隔,共13个点) time = pd.date_range('2018-05-14 00:00:00','2018-05-14 01:00:00',freq='5T') # 生成y轴里程值(10个点) mile = np.linspace(0,100,10) # 构造长格式数据 x = list(time)*len(mile) y = np.repeat(mile,len(time)) # 生成z值:每个mile组对应不同均值的正态分布 z = [] for i in range(0,10,1): z.extend(np.random.normal(loc=i*5, scale=5, size=len(time))) origin_data = pd.DataFrame({'x':x, 'y':y ,'z':z})
第二步:将Datetime转换为数值类型
把Datetime类型的x转换成相对于起始时间的分钟数(比Unix时间戳更直观),这样就能满足interp2d的数值输入要求:
# 提取原始数据的起始时间 start_time = origin_data['x'].min() # 将Datetime转为分钟数:(x - start_time).dt.total_seconds()/60 origin_data['x_num'] = (origin_data['x'] - start_time).dt.total_seconds() / 60 # 提取唯一的x_num和y值(interp2d需要一维的x、y输入) x_unique = origin_data['x_num'].unique() y_unique = origin_data['y'].unique() # 将长格式数据转为二维矩阵(z_matrix的行对应y_unique,列对应x_unique) z_matrix = origin_data.pivot(index='y', columns='x_num', values='z').values
第三步:准备目标插值点并执行插值
生成你需要的目标x(1分钟间隔)和y(固定值91),同样转换为数值类型,然后进行双线性插值:
# 生成目标时间序列(1分钟间隔) target_x = pd.date_range('2018-05-14 00:00:00','2018-05-14 01:00:00',freq='1T') # 转为分钟数 target_x_num = (target_x - start_time).dt.total_seconds() / 60 # 目标y值 target_y = np.array([91]) # 创建插值函数,指定kind='linear'实现双线性插值 interp_func = interp2d(x_unique, y_unique, z_matrix, kind='linear') # 计算插值结果 target_z = interp_func(target_x_num, target_y) # 将插值结果整理成DataFrame方便查看 result_df = pd.DataFrame({ 'x': target_x, 'y': target_y.repeat(len(target_x)), 'z': target_z.flatten() }) print("插值结果前5行:") print(result_df.head())
第四步:可视化原始数据与插值结果
用matplotlib绘制原始点的散点图,再叠加插值后的曲线,直观对比:
fig, ax1 = plt.subplots(figsize=(10,6)) # 绘制原始数据散点图 scatter = ax1.scatter(origin_data['x'], origin_data['y'], c=origin_data['z'], cmap='viridis', alpha=0.6, label='原始数据点') # 设置x轴日期格式 ax1.xaxis.set_major_formatter(DateFormatter('%H:%M')) ax1.set_xlabel('时间') ax1.set_ylabel('里程') ax1.set_title('原始数据与插值结果对比') # 绘制插值结果曲线(y=91处的z值随时间变化) ax2 = ax1.twinx() ax2.plot(target_x, result_df['z'], color='red', linewidth=2, label='y=91处插值结果') ax2.set_ylabel('z值') # 添加图例 fig.legend(loc='upper right', bbox_to_anchor=(1.15, 1)) # 添加颜色条 plt.colorbar(scatter, ax=ax1, label='原始z值') plt.tight_layout() plt.show()
关键说明
- Datetime转数值:这里用相对分钟数,既保留了时间的连续性,又避免了Unix时间戳的大数问题,插值结果更稳定。
- 数据格式转换:
pivot方法把长格式的DataFrame转成二维矩阵,完美匹配interp2d对z输入的要求(z必须是二维数组,对应x和y的网格)。 - 双线性插值:通过
kind='linear'指定双线性插值,这是interp2d的默认选项,明确指定能确保插值效果符合预期。
内容的提问来源于stack exchange,提问作者YQ.Wang
相关产品推荐
相关产品推荐

