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

如何让Pandas按固定整点/半点分组30分钟时间间隔?

问题:Pandas按固定30分钟间隔(00/30分)统计事件次数时分组偏移的解决方法

我写了一段Pandas代码,想要按每小时00分和30分的固定30分钟间隔统计事件发生次数,但第二组结果始终对齐到03分和33分。怀疑分组是按首行时间对齐,第一组结果正确只是巧合,求问如何让分组器强制对齐到00分和30分?

# load and prepare data
df_long_forecast = pd.read_csv('df_long_forecast - reduced.csv')
df_long_forecast['after_12_max_datetime'] = pd.to_datetime(
    df_long_forecast['after_12_max_datetime']
)
df_long_forecast['after_12_max_time'] = (
    df_long_forecast['after_12_max_datetime']
    - df_long_forecast['after_12_max_datetime'].dt.normalize()
)  # timedelta64[ns]

# count the number of maxes happening after 12am (absolute and percentage)
hist_max = df_long_forecast.groupby(
    pd.Grouper(key='after_12_max_time', freq='30T', offset='0T', origin='epoch')
)['Date'].count()
display(hist_max)

# count the number of maxes after 12 that result in a profit trade
# (cannot be MORE than the previous ones)
df_long_forecast_profit = df_long_forecast[
    df_long_forecast['after_12_max_>_9_to_12_high'] > 0
]
profit_long = df_long_forecast_profit.groupby(
    pd.Grouper(key='after_12_max_time', freq='30T', offset='0T', origin='epoch')
)['Date'].count()
display(profit_long)

hist_max输出:

after_12_max_time
0 days 12:00:00    24
0 days 12:30:00     5
0 days 13:00:00     7
0 days 13:30:00     5
0 days 14:00:00     5
0 days 14:30:00     4
0 days 15:00:00     4
0 days 15:30:00     1
0 days 16:00:00     5
0 days 16:30:00     7
0 days 17:00:00     1
0 days 17:30:00     6
0 days 18:00:00     1
0 days 18:30:00     1
0 days 19:00:00     1
0 days 19:30:00     6
0 days 20:00:00     3
0 days 20:30:00     0
0 days 21:00:00     6
0 days 21:30:00    19
0 days 22:00:00     8
Freq: 30T, Name: Date, dtype: int64

profit_long输出:

after_12_max_time
0 days 12:03:00     8
0 days 12:33:00     4
0 days 13:03:00     5
0 days 13:33:00     4
0 days 14:03:00     5
0 days 14:33:00     4
0 days 15:03:00     3
0 days 15:33:00     2
0 days 16:03:00     5
0 days 16:33:00     6
0 days 17:03:00     2
0 days 17:33:00     5
0 days 18:03:00     1
0 days 18:33:00     2
0 days 19:03:00     0
0 days 19:33:00     5
0 days 20:03:00     3
0 days 20:33:00     0
0 days 21:03:00     6
0 days 21:33:00    21
0 days 22:03:00     3
Freq: 30T, Name: Date, dtype: int64

问题原因

问题出在你使用origin='epoch'且分组对象是timedelta类型数据。对timedelta使用pd.Grouper时,origin='epoch'会让分组从1970-01-01 00:00:00对应的timedelta起点开始,过滤后的子数据集(比如df_long_forecast_profit)的首个时间会触发分组偏移,导致间隔错位。

解决方法

方法1:直接基于datetime列分组(推荐)

利用datetime的分组逻辑,配合origin='start_day'强制以当天00:00为起点对齐30分钟间隔,最后可保留时间部分匹配原输出格式:

# 统计所有事件
hist_max = df_long_forecast.groupby(
    pd.Grouper(key='after_12_max_datetime', freq='30T', origin='start_day')
)['Date'].count()
# 仅保留时间部分作为索引(可选)
hist_max.index = hist_max.index.time
display(hist_max)

# 统计盈利事件
df_long_forecast_profit = df_long_forecast[df_long_forecast['after_12_max_>_9_to_12_high'] > 0]
profit_long = df_long_forecast_profit.groupby(
    pd.Grouper(key='after_12_max_datetime', freq='30T', origin='start_day')
)['Date'].count()
profit_long.index = profit_long.index.time
display(profit_long)

方法2:手动对齐timedelta

如果必须使用timedelta列,可通过秒数计算手动对齐到30分钟间隔:

def align_30min(td):
    total_seconds = td.total_seconds()
    # 1800秒=30分钟,取整后转回timedelta
    aligned_seconds = round(total_seconds / 1800) * 1800
    return pd.to_timedelta(aligned_seconds, unit='s')

# 应用对齐函数到全量数据
df_long_forecast['aligned_time'] = df_long_forecast['after_12_max_time'].apply(align_30min)
hist_max = df_long_forecast.groupby('aligned_time')['Date'].count()
display(hist_max)

# 应用到盈利数据
df_long_forecast_profit['aligned_time'] = df_long_forecast_profit['after_12_max_time'].apply(align_30min)
profit_long = df_long_forecast_profit.groupby('aligned_time')['Date'].count()
display(profit_long)

关键说明

  • origin='start_day'会让分组从当天00:00开始,确保30分钟间隔严格对齐到00分和30分,不受数据中最早时间的影响。
  • 直接使用datetime列分组比timedelta更可靠,Pandas对datetime的分组逻辑更成熟,能更好地处理固定间隔对齐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 08:03:25