跳转至

Pandas 根据日期进行分组

问题背景:有一个分钟级别索引的数据框,需要根据日期进行分组聚合计算。

  1. 简单的 .groupby('datetime') 无法实现按日期分组。
  2. .groupby(pd.Grouper(level='datetime', freq='D')) 会为原始数据中不存在的日期填充空值(例如,在股票数据中,周末、节假日等非交易日会被填充为空值)。
    • 如果分组后调用的是 .mean(),则会出现这个问题。
    • 如果分组后调用的是 .transform('mean'),则不存在这个问题。

本文记录了可以正确根据日期进行分组的方法。

image-20231008235016433

示例数据

Python
import pandas as pd
import numpy as np

# 创建一个示例数据集
data = pd.DataFrame(
    index=np.concatenate(
        (
            pd.date_range(
                start="2023-01-01 00:00:00", end="2023-01-01 23:59:59", freq="12H"
            ),
            pd.date_range(
                start="2023-01-03 00:00:00", end="2023-01-03 23:59:59", freq="12H"
            ),
        ),
        axis=None,
    ),
    data={
        "value": [1, 2, 3, 4],
    },
)
data.index.name = "datetime"
print(data)
Text Only
                     value
datetime                  
2023-01-01 00:00:00      1
2023-01-01 12:00:00      2
2023-01-03 00:00:00      3
2023-01-03 12:00:00      4

简单的 .groupby('datetime') 无法实现按日期分组

.groupby('datetime') 只是根据原始分钟级别进行分组,并没有实现按日期分组的效果。

Python
data.groupby('datetime').mean()
Text Only
                     value
datetime                  
2023-01-01 00:00:00    1.0
2023-01-01 12:00:00    2.0
2023-01-03 00:00:00    3.0
2023-01-03 12:00:00    4.0

.groupby(pd.Grouper(level='datetime', freq='D')) 会为原始数据中不存在的日期填充空值

2023-01-02 本来是没有数据的,但分组之后被填充为了空值。

Python
data.groupby(pd.Grouper(level='datetime', freq='D')).mean()
Text Only
            value
datetime         
2023-01-01    1.5
2023-01-02    NaN
2023-01-03    3.5

.transform() 不会出现填充空值的问题

如果分组后调用的是 .transform('mean'),则不存在这个问题。

Python
data.groupby(pd.Grouper(level='datetime', freq='D')).transform('mean')
Text Only
                     value
datetime                  
2023-01-01 00:00:00    1.5
2023-01-01 12:00:00    1.5
2023-01-03 00:00:00    3.5
2023-01-03 12:00:00    3.5

使用 .date.floor('D') 提取日期

.date

Python
data.groupby(data.index.date).mean()
Text Only
            value
2023-01-01    1.5
2023-01-03    3.5

.floor('D')

参考:StackOverflow: In pandas, group by date from DatetimeIndex

D 代表日频。更多数据频率的字符串可以参考 offset-aliases

Python
data.groupby(data.index.floor('D')).mean()
Text Only
            value
datetime         
2023-01-01    1.5
2023-01-03    3.5

.date.floor('D') 的区别

注意到,上述两种方法得到的结果略微有不同:

  • .date 得到的结果中,索引是没有名称的。
  • .floor('D') 得到的结果中,索引的名称仍然是 datetime

.date.floor('D') 的运行速度

StackOverflow: In pandas, group by date from DatetimeIndex 回答的评论说 .floor('D') 更快,但我自己实验后发现有时 .date 更快,有时两者耗时十分接近。

评论