如何在Python DataFrame的时间段内生成插值数值?
问题
现有一组包含周期序列(周期0、1、2……)的DataFrame数据,需要在相邻周期之间生成新的数值行,计算逻辑为:取相邻周期的value差值,按设定的分段数量均分,生成对应time_order和value的记录。
示例数据如下:
import pandas as pd data = [{'metric': '3f00d0b5', 'time':52.66, 'time_order': 0, 'variable': 'var1', 'value': 0.035}, {'metric': '3f00d0b5', 'time':422.4, 'time_order': 1, 'variable': 'var1', 'value': 0.512}, {'metric': '3f00d0b5', 'time':620.1, 'time_order': 2, 'variable': 'var1', 'value': 0.0}, {'metric': '3f00d0b5', 'time':52.66, 'time_order': 0, 'variable': 'var2', 'value': 0.007}, {'metric': '3f00d0b5', 'time':422.4, 'time_order': 1, 'variable': 'var2', 'value': 0.012}, {'metric': '3f00d0b5', 'time':620.1, 'time_order': 2, 'variable': 'var2', 'value': 0.214}, {'metric': '83e7fdd1', 'time':25.42, 'time_order': 0, 'variable': 'var1', 'value': 0.0}, {'metric': '83e7fdd1', 'time':322.45, 'time_order': 1, 'variable': 'var1', 'value': 0.241}, {'metric': '83e7fdd1', 'time':678.12, 'time_order': 2, 'variable': 'var1', 'value': 0.005}, {'metric': '83e7fdd1', 'time':25.42, 'time_order': 0, 'variable': 'var2', 'value': 0.02}, {'metric': '83e7fdd1', 'time':322.45, 'time_order': 1, 'variable': 'var2', 'value': 0.007}, {'metric': '83e7fdd1', 'time':678.12, 'time_order': 2, 'variable': 'var2', 'value': 0.0} ] df = pd.DataFrame.from_dict(data)
期望结果示例(以metric=3f00d0b5, variable=var1的相邻周期0和1为例):
{'metric': '3f00d0b5', 'time':52.66, 'time_order': 0, 'variable': 'var1', 'value': 0.035}, {'metric': '3f00d0b5', 'time':52.66, 'time_order': 0.1, 'variable': 'var1', 'value': 0.083}, ... {'metric': '3f00d0b5', 'time':52.66, 'time_order': 0.9, 'variable': 'var1', 'value': 0.4643}, {'metric': '3f00d0b5', 'time':422.4, 'time_order': 1, 'variable': 'var1', 'value': 0.512},
需要简洁的Pythonic实现方式。
简洁实现方案
可以利用Pandas的分组、线性插值功能实现,核心思路是按metric和variable分组,对每组内的相邻周期数据生成均分的中间值,以下两种方式都能满足需求:
方式一:直观分段生成
适合需要自定义插值逻辑的场景,代码清晰易懂:
n = 10 # 相邻周期间分成10份,生成9个中间行 # 按维度分组并确保每组内按周期排序 groups = df.sort_values(['metric', 'variable', 'time_order']).groupby(['metric', 'variable']) def interpolate_group(group): expanded = [] orders = group['time_order'].values values = group['value'].values times = group['time'].values metric = group['metric'].iloc[0] var = group['variable'].iloc[0] for i in range(len(orders)-1): # 生成当前周期到下一个周期的均分序列(不含终点,避免重复) order_steps = pd.linspace(orders[i], orders[i+1], num=n, endpoint=False) val_steps = pd.linspace(values[i], values[i+1], num=n, endpoint=False) # 构造当前段的行数据 segment = pd.DataFrame({ 'metric': metric, 'time': times[i], 'time_order': order_steps, 'variable': var, 'value': val_steps }) expanded.append(segment) # 添加分组的最后一行原始数据 expanded.append(group.iloc[[-1]]) return pd.concat(expanded, ignore_index=True) # 应用分组逻辑并合并结果 result_df = groups.apply(interpolate_group).reset_index(drop=True)
方式二:利用Pandas内置插值
仅需线性插值时,代码更紧凑:
n = 10 groups = df.sort_values(['metric', 'variable', 'time_order']).groupby(['metric', 'variable']) def interpolate_group_compact(group): # 生成所有需要的time_order序列 original_orders = group['time_order'].values new_orders = [] for i in range(len(original_orders)-1): new_orders.extend(pd.linspace(original_orders[i], original_orders[i+1], num=n, endpoint=False)) new_orders.append(original_orders[-1]) # 重新索引并插值 new_group = group.set_index('time_order').reindex(new_orders) new_group['value'] = new_group['value'].interpolate(method='linear') # 其他非数值字段用前向填充补全 new_group[['metric', 'variable', 'time']] = new_group[['metric', 'variable', 'time']].ffill() return new_group.reset_index() result_df_compact = groups.apply(interpolate_group_compact).reset_index(drop=True)
验证结果
执行以下代码查看指定维度的结果:
print(result_df[(result_df['metric'] == '3f00d0b5') & (result_df['variable'] == 'var1')].head(11))
输出会包含周期0的起始行、9个中间行和周期1的起始行,与预期一致。
内容的提问来源于stack exchange,提问作者Leonardo Ferreira
相关产品推荐
相关产品推荐

