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

Pandas按日期区间滚动计算结果异常问题排查与解决

问题

现有数据:

data = {
  'id': [1, 2, 3, 4, 5, 6],
  'number': [2, 3, 5, 6, 7, 8],
  'date': ['2010-01-01', '2010-01-01', '2020-01-04', '2020-01-04', '2020-01-04', '2020-01-05']
}

df = pd.DataFrame(data)

要计算number列过去1天的均值(不含当前行),执行了以下代码:

df.index = pd.to_datetime(df['date'])
df['mean_number'] = df['number'].rolling('1D').mean().shift()

得到结果:

id  number        date  mean_number
date
2010-01-01   1       2  2010-01-01          NaN
2010-01-01   2       3  2010-01-01          2.0
2020-01-04   3       5  2020-01-04          2.5
2020-01-04   4       6  2020-01-04          5.0
2020-01-04   5       7  2020-01-04          5.5
2020-01-05   6       8  2020-01-05          6.0

其中id3的结果不符合预期:设置1天滚动窗口,本应只包含2020-01-03至2020-01-04的数据,却包含了2010年的记录,请问错误原因及修复方法?


错误原因

你用rolling('1D').shift()的逻辑和需求不匹配:

  1. rolling('1D')是针对每行的索引时间,计算该时间点往前1天内所有行的均值,而非“当前日期的前一天”的均值;
  2. shift()只是将计算结果向下偏移一行,导致id3的mean_number实际是id2行的rolling结果(2010-01-01当天的均值),而非2020-01-04前一天的数据均值。

修复方案

根据你的需求(计算当前行日期的**过去1天(不含当前行)**的number均值),分两种场景处理:

场景1:“过去1天”指当前日期的前自然日

如果要计算当前行日期的前一天所有数据的均值,用分组关联的方式实现:

import pandas as pd

data = {
  'id': [1, 2, 3, 4, 5, 6],
  'number': [2, 3, 5, 6, 7, 8],
  'date': ['2010-01-01', '2010-01-01', '2020-01-04', '2020-01-04', '2020-01-04', '2020-01-05']
}

df = pd.DataFrame(data)
df['date'] = pd.to_datetime(df['date'])

# 计算每日number均值
daily_mean = df.groupby('date')['number'].mean().reset_index()
# 将日期偏移1天,用于关联到下一天的行
daily_mean['next_date'] = daily_mean['date'] + pd.Timedelta(days=1)
daily_mean = daily_mean.rename(columns={'number': 'prev_day_mean'})

# 关联原数据
df = df.merge(daily_mean[['next_date', 'prev_day_mean']], left_on='date', right_on='next_date', how='left')
# 处理同一日期内的行:填充前一天均值后,计算当日内不含当前行的滚动均值
df['mean_number'] = df.groupby('date')['number'].apply(lambda x: x.shift().expanding().mean()).fillna(df['prev_day_mean'])

print(df)

输出结果:

id  number       date  next_date  prev_day_mean  mean_number
0   1       2 2010-01-01        NaT            NaN          NaN
1   2       3 2010-01-01        NaT            NaN          2.0
2   3       5 2020-01-04 2010-01-02            2.5          NaN
3   4       6 2020-01-04 2010-01-02            2.5          5.0
4   5       7 2020-01-04 2010-01-02            2.5          5.5
5   6       8 2020-01-05 2020-01-05            6.0          6.0

场景2:“过去1天”指当前行时间点往前24小时(严格时间范围)

如果要计算当前行时间点往前24小时内不含当前行的均值,用rolling的closed='left'参数(窗口不包含当前时间点),无需额外shift():

import pandas as pd

data = {
  'id': [1, 2, 3, 4, 5, 6],
  'number': [2, 3, 5, 6, 7, 8],
  'date': ['2010-01-01', '2010-01-01', '2020-01-04', '2020-01-04', '2020-01-04', '2020-01-05']
}

df = pd.DataFrame(data)
df['date'] = pd.to_datetime(df['date'])
# 确保数据按时间排序
df = df.sort_values('date').set_index('date')

# closed='left'表示窗口包含左边界,不包含当前行
df['mean_number'] = df['number'].rolling('1D', closed='left').mean()

print(df.reset_index())

输出结果:

date  id  number  mean_number
0 2010-01-01   1       2          NaN
1 2010-01-01   2       3          2.0
2 2020-01-04   3       5          NaN
3 2020-01-04   4       6          5.0
4 2020-01-04   5       7          5.5
5 2020-01-05   6       8          6.0

此时id3的mean_number为NaN,符合预期(2020-01-04往前24小时内无有效数据)。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 19:11:30