如何基于时间序列连续性拆分Pandas DataFrame为无NaN子集
Pandas 时间序列连续子集拆分方案
针对300万行规模的数据集,以下方案全用Pandas原生向量化操作实现,运行效率足够满足需求,无需额外依赖。
核心思路
我们只需要对两类断裂点做标记,将连续的非断裂行归为同一分组即可完成拆分:
- 断裂点1:任意指定列存在NaN值
- 断裂点2:当前行与上一行的时间索引差不等于固定时间步长(步长可根据你的数据采样规则自定义,比如示例中的1小时)
实现代码
import pandas as pd def split_continuous_subsets(df: pd.DataFrame, target_cols: list, freq: str = "H") -> list[pd.DataFrame]: # 复制原数据避免修改原表 df = df.copy().sort_index() # 条件1:指定列全为非NaN的行标记为True,否则为False no_nan_mask = df[target_cols].notna().all(axis=1) # 条件2:时间连续的行标记为True,否则为False,先计算期望的连续时间差 expected_delta = pd.Timedelta(freq) time_continuous_mask = df.index.to_series().diff() == expected_delta # 生成组ID:只要出现断裂点,组ID就+1 group_id = (~(no_nan_mask & time_continuous_mask)).cumsum() # 过滤掉包含NaN的行,按组ID拆分 subsets = [subset for _, subset in df[no_nan_mask].groupby(group_id)] return subsets
调用示例
用你给出的测试场景验证:
# 构造测试数据 idx = pd.date_range("2021-08-21 11:00:00", periods=7, freq="H", tz="UTC") df = pd.DataFrame( {"x1": [1,2,3,4,5,6,7], "x2": [10,20,30,None,50,60,70]}, index=idx ) df.index.name = "predicted_at" # 调用拆分函数,指定要校验的列x1、x2,时间步长为1小时 subsets = split_continuous_subsets(df, target_cols=["x1", "x2"], freq="H")
返回的subsets列表就包含两个子集:
- 第一个子集对应11:00-13:00的3行无NaN数据
- 第二个子集对应15:00-17:00的3行无NaN数据
自定义调整说明
- 如果你的时间序列不是固定频率,可以把
freq参数替换为你实际的采样间隔,比如freq="15T"代表15分钟采样 - 如果不需要校验时间连续性,只需要按NaN断裂拆分,删除
time_continuous_mask相关判断即可,仅保留no_nan_mask生成组ID
内容的提问来源于stack exchange,提问作者Jostein Sortland
相关产品推荐
相关产品推荐

