You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多时间序列保留原始数据并插值填充NaN值的实现方法

问题描述

需求1:为每个ID确定时间范围

需要为每个ID找出00:00:00之前最早的测量时间和00:00:00之后最晚的测量时间,以此确定各ID数据的最大重叠起止时间。附带示例数据生成代码:

import pandas as pd
import random

# 创建示例数据框
df = pd.DataFrame({'timestamp': pd.date_range(start='2022-01-01', end='2022-01-01 23:59', freq='4H')})
df2 = pd.DataFrame({'timestamp': pd.date_range(start='2022-01-01', end='2022-01-01 23:59', freq='5H')})

df['value']= [random.randrange(10, 19) for n in range(len(df))]
df['ID']= [random.randrange(1, 4) for n in range(len(df))]

df2['value']= [random.randrange(10, 19) for n in range(len(df2))]
df2['ID']= [random.randrange(1, 4) for n in range(len(df2))]

merged_df = df.merge(df2,  how='outer', on =['timestamp'])
merged_df.reset_index(drop=True,inplace=True)
merged_df.sort_values(by=['timestamp'],inplace=True)

print(merged_df)

需求2:多时间序列合并后插值填充

现有多个不同采样间隔的时间序列(例如20分钟、15分钟间隔),合并后需实现:

  • 保留VALUE1列的原始测量值
  • 为无原始记录的时间点插值填充数值

最小示例数据

IDVALUE1TIME
255000:04:00
258000:04:30
2510000:05:00
2510000:05:30
2510000:06:00
184500:04:02
183300:04:22
187500:04:42
185700:05:02
189900:05:22

预期输出

IDVALUE1TIME
255000:04:00
25插值值=例如(50+80)/200:04:02
25插值值00:04:22
258000:04:30
25插值值00:04:42
2510000:05:00
25插值值00:05:02
25插值值00:05:22
2510000:05:30
2510000:06:00
18插值值=例如沿用最近值4500:04:00
184500:04:02
183300:04:22
18某插值值00:04:30
187500:04:42
18某插值值00:04:30
185700:05:02
189900:05:22
18某插值值00:05:00
18某插值值00:05:30
18某插值值00:06:00

编辑补充:两个序列时可通过outer merge保留时间点再插值,但需了解多序列场景下的实现方式。


解决方案

针对需求1:确定每个ID的时间范围

  1. 先确保时间列是datetime类型,再按ID分组计算时间范围:
# 转换时间列为datetime类型
merged_df['timestamp'] = pd.to_datetime(merged_df['timestamp'])

# 提取日期,构造当天0点时间
merged_df['date'] = merged_df['timestamp'].dt.date
merged_df['midnight'] = pd.to_datetime(merged_df['date'])

# 按ID分组,计算0点前最早、0点后最晚时间
def get_time_range(group):
    midnight = group['midnight'].iloc[0]
    before_midnight = group[group['timestamp'] < midnight]['timestamp']
    after_midnight = group[group['timestamp'] >= midnight]['timestamp']
    return pd.Series({
        'earliest_before_midnight': before_midnight.min() if not before_midnight.empty else None,
        'latest_after_midnight': after_midnight.max() if not after_midnight.empty else None
    })

id_time_ranges = merged_df.groupby('ID').apply(get_time_range).reset_index()
print(id_time_ranges)

针对需求2:多时间序列合并后插值填充

多序列场景核心是先构建完整时间轴,再按ID扩展记录,最后保留原始值并插值:

步骤1:合并所有原始数据

统一结构后合并多个时间序列:

# 假设有df1、df2、df3等多个结构为[ID, VALUE1, TIME]的DataFrame
all_dfs = [df1, df2, df3]
combined_df = pd.concat(all_dfs, ignore_index=True)
# 转换时间列为datetime类型
combined_df['TIME'] = pd.to_datetime(combined_df['TIME'], format='%H:%M:%S')

步骤2:构建完整时间轴

提取所有序列的唯一时间点并排序:

all_times = combined_df['TIME'].unique()
all_times.sort()

步骤3:扩展每个ID的时间记录

生成ID与时间点的笛卡尔积,合并原始数据保留真实值:

# 生成ID和时间点的全组合
ids = combined_df['ID'].unique()
id_time_grid = pd.MultiIndex.from_product([ids, all_times], names=['ID', 'TIME']).to_frame(index=False)

# 合并原始数据,缺失值标记为NaN
full_df = id_time_grid.merge(combined_df, on=['ID', 'TIME'], how='left')

步骤4:插值填充缺失值

按ID分组选择插值方式,原始值会被保留:

# 基于时间间隔的线性插值(适合不规则时间间隔)
full_df['VALUE1'] = full_df.sort_values('TIME').groupby('ID')['VALUE1'].transform(
    lambda x: x.interpolate(method='time')
)

# 若需沿用最近前值,替换为:
# full_df['VALUE1'] = full_df.sort_values('TIME').groupby('ID')['VALUE1'].ffill()

# 若需沿用最近后值,替换为:
# full_df['VALUE1'] = full_df.sort_values('TIME').groupby('ID')['VALUE1'].bfill()

步骤5:排序输出

按ID和时间排序得到最终结果:

full_df.sort_values(['ID', 'TIME'], inplace=True)
print(full_df)

说明

  • 该方法支持任意数量的时间序列,只需保证所有序列结构统一(ID、VALUE列、时间列)
  • 插值方式可根据业务需求调整:method='time'适合时间间隔不规则的线性插值,ffill()/bfill()适合沿用最近值的场景
  • 若时间包含日期,只需确保TIME列为完整datetime类型,代码逻辑无需改动

内容的提问来源于stack exchange,提问作者dspractician

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.29 11:23:16