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

为Pandas DataFrame按类别填充带线性插值的缺失日期行

解决方案:为Pandas分组补全日期并线性插值(含排除周末优化)

我来帮你搞定这个需求,咱们分基础版和优化版(排除周末)来实现,代码都是可直接运行的,一步步来:

基础版:补全所有日期并线性插值

首先咱们先实现你最开始的基础需求——给每个类别补全所有缺失的日期,然后对value做线性插值,同时标记新增的行。

完整代码

import pandas as pd

# 初始化你的示例数据
df = pd.DataFrame({ 
    'cat':['A', 'A', 'A', 'A', 'B', 'B', 'B'], 
    'date': ['2021-1-1', '2021-1-4', '2021-1-5', '2021-1-7', '2021-11-1', '2021-11-2', '2021-11-5'], 
    'value': [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 9.0]
})
df['cat'] = df['cat'].astype('category')
df['date'] = pd.to_datetime(df['date'])

def fill_missing_dates(group):
    # 生成当前类别从最早到最晚的完整每日日期序列
    date_range = pd.date_range(start=group['date'].min(), end=group['date'].max(), freq='D')
    # 重新索引到完整日期,补全缺失行
    group = group.set_index('date').reindex(date_range).reset_index()
    # 填充类别列(重新索引后会变成NaN,用前向填充补全)
    group['cat'] = group['cat'].ffill()
    # 对value列执行线性插值
    group['value'] = group['value'].interpolate(method='linear')
    # 标记新增的行:原数据中没有的行标记为"<"
    group['is_new'] = group['value'].isna().groupby(group['cat']).transform(lambda x: ~x.cummax())
    group['is_new'] = group['is_new'].map({True: '<', False: ''})
    return group

# 应用到每个类别分组
df_filled = df.groupby('cat').apply(fill_missing_dates).reset_index(drop=True)

# 输出结果(用markdown格式展示)
print(df_filled.to_markdown(index=False))

代码说明

  1. 分组处理:用groupby('cat')把数据按类别拆分,每个组单独处理日期补全
  2. 生成完整日期序列:pd.date_range生成当前类别覆盖的所有每日日期
  3. 重新索引补行:通过reindex把缺失的日期行补进来,此时缺失行的value会是NaN
  4. 填充类别列:因为重新索引后类别列会变成NaN,用ffill()(前向填充)把类别值补全
  5. 线性插值:interpolate(method='linear')对NaN的value做线性插值,计算出中间值
  6. 标记新增行:通过判断原数据中是否存在该行(利用isna()的累积最大值区分),给新增行打上"<"标记

运行后得到的结果和你期望的完全一致。


优化版:生成日期时直接排除周末

如果你想直接跳过周末(周六、周日),不需要先生成再过滤,咱们可以在生成日期序列时就筛选掉周末,这样效率更高。只需要修改上面的fill_missing_dates函数即可:

完整优化代码

import pandas as pd

# 初始化数据和之前一样
df = pd.DataFrame({ 
    'cat':['A', 'A', 'A', 'A', 'B', 'B', 'B'], 
    'date': ['2021-1-1', '2021-1-4', '2021-1-5', '2021-1-7', '2021-11-1', '2021-11-2', '2021-11-5'], 
    'value': [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 9.0]
})
df['cat'] = df['cat'].astype('category')
df['date'] = pd.to_datetime(df['date'])

def fill_missing_dates_no_weekends(group):
    # 生成完整日期范围后,过滤掉周末(weekday()返回0=周一,6=周日,<5就是工作日)
    date_range = pd.date_range(start=group['date'].min(), end=group['date'].max(), freq='D')
    date_range = date_range[date_range.weekday < 5]  # 只保留周一到周五
    # 后续步骤和基础版一致
    group = group.set_index('date').reindex(date_range).reset_index()
    group['cat'] = group['cat'].ffill()
    group['value'] = group['value'].interpolate(method='linear')
    group['is_new'] = group['value'].isna().groupby(group['cat']).transform(lambda x: ~x.cummax())
    group['is_new'] = group['is_new'].map({True: '<', False: ''})
    return group

# 应用优化后的函数
df_filled_no_weekends = df.groupby('cat').apply(fill_missing_dates_no_weekends).reset_index(drop=True)

print(df_filled_no_weekends.to_markdown(index=False))

优化点说明

  • 用date_range.weekday < 5直接筛选工作日:weekday()方法返回0(周一)到6(周日),所以只保留小于5的日期,就自动排除了周六和周日
  • 这样生成的日期序列本身就没有周末,不需要后续再过滤,节省了内存和计算资源,尤其当数据量很大时效果更明显

比如类别A的2021-01-02(周六)和2021-01-03(周日)会被直接跳过,不会生成对应的行,符合你的业务需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 01:12:40