如何使用 Python/Pandas 从日期字段按月分组

Posted

技术标签:

【中文标题】如何使用 Python/Pandas 从日期字段按月分组【英文标题】:How can I group by month from a date field using Python and Pandas? 【发布时间】:2017-12-08 01:39:21 【问题描述】:

我有一个数据框 df,如下所示:

| date      | Revenue |
|-----------|---------|
| 6/2/2017  | 100     |
| 5/23/2017 | 200     |
| 5/20/2017 | 300     |
| 6/22/2017 | 400     |
| 6/21/2017 | 500     |

我需要将以上数据按月分组,得到输出为:

| date | SUM(Revenue) |
|------|--------------|
| May  | 500          |
| June | 1000         |

我试过这段代码,但没有用:

df.groupby(month('date')).agg('Revenue': 'sum')

我只想使用 Pandas 或 Numpy,不想使用其他库

【问题讨论】:

df.groupby(pd.Grouper(key='Date',freq='M')).agg('Revenue':'sum'),这里假设日期列的数据类型是日期时间 【参考方案1】:

试试这个:

In [6]: df['date'] = pd.to_datetime(df['date'])

In [7]: df
Out[7]: 
        date  Revenue
0 2017-06-02      100
1 2017-05-23      200
2 2017-05-20      300
3 2017-06-22      400
4 2017-06-21      500



In [59]: df.groupby(df['date'].dt.strftime('%B'))['Revenue'].sum().sort_values()
Out[59]: 
date
May      500
June    1000

【讨论】:

赞成,因为这是正确格式化date 列的唯一答案 仅供参考,这为您提供了一个日期字符串列,它既不高效也不有用(作为真正的重采样/时间分组) @shivsn:这可以按日期升序排序吗(May-500,然后是 June -1000)? 你所说的df是什么意思。如何导入df?? @Ragulan28 df 是 DateFrame 的名称。例如 df = pd.read_csv('file.csv')【参考方案2】:

使用熊猫Grouper尝试分组:

df = pd.DataFrame('date':['6/2/2017','5/23/2017','5/20/2017','6/22/2017','6/21/2017'],'Revenue':[100,200,300,400,500])
df.date = pd.to_datetime(df.date)
dg = df.groupby(pd.Grouper(key='date', freq='1M')).sum() # groupby each 1 month
dg.index = dg.index.strftime('%B')

     Revenue
 May    500
June    1000

【讨论】:

这似乎是性能和一般可用性之间的最佳组合 这是最有用的,因为月份是按顺序聚合的。这应该是最佳答案。 如果您的日期跨年,这将不起作用。然后,不再是每个月只有一行(比如上面的 5 月和 6 月),而是每年有多个 5 月和 6 月。【参考方案3】:

对于多行的 DataFrame,使用strftime 会占用更多时间。如果日期列已经有datetime64[ns]的dtype(可以使用pd.to_datetime()进行转换,或者在csv导入时指定parse_dates等),可以直接访问groupby标签的datetime属性(方法三)。加速是巨大的。

import numpy as np
import pandas as pd

T = pd.date_range(pd.Timestamp(0), pd.Timestamp.now()).to_frame(index=False)
T = pd.concat([T for i in range(1,10)])
T['revenue'] = pd.Series(np.random.randint(1000, size=T.shape[0]))
T.columns.values[0] = 'date'

print(T.shape) #(159336, 2)
print(T.dtypes) #date: datetime64[ns], revenue: int32

方法一:strftime

%timeit -n 10 -r 7 T.groupby(T['date'].dt.strftime('%B'))['revenue'].sum()

每个循环 1.47 秒 ± 10.1 毫秒(7 次运行的平均值 ± 标准偏差,每次 10 个循环)

方法二:石斑鱼

%timeit -n 10 -r 7 T.groupby(pd.Grouper(key='date', freq='1M')).sum()
#NOTE Manually map months as integer 01..12 to strings

每个循环 56.9 毫秒 ± 2.88 毫秒(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

方法3:日期时间属性

%timeit -n 10 -r 7 T.groupby(T['date'].dt.month)['revenue'].sum()
#NOTE Manually map months as integer 01..12 to strings

每个循环 34 毫秒 ± 3.34 毫秒(7 次运行的平均值 ± 标准偏差,每次 10 次循环)

【讨论】:

请注意,如果您有超过 1 年的数据,则方法 1 和 3 会对其进行聚合,而方法 2 则不会。此外,方法 1 的结果按字母顺序排序。 如何按升序排列输出?因为它现在是数组而不是 df【参考方案4】:

这样会更好。

试试这个:

#explicitly convert to date
df['Date'] = pd.to_datetime(df['Date'])
# set your date column as index 
df.set_index('Date',inplace=True) 

# For monthly use 'M', If needed for other freq you can change.
df[revenue].resample('M').sum()

此代码给出的结果与@shivsn 在第一篇文章中的回答相同。

但问题是我们可以在上面提到的代码中做更多的操作。 推荐使用这个:

>>> df['Date'] = pd.to_datetime(df['Date'])
>>> df.set_index('Date',inplace=True)
>>> df['withdrawal'].resample('M').sum().sort_values()
Date
2019-10-31     28710.00
2019-04-30     31437.00
2019-07-31     39728.00
2019-11-30     40121.00
2019-05-31     46495.00
2020-02-29     57751.10
2019-12-31     72469.13
2020-01-31     76115.78
2019-06-30     76947.00
2019-09-30     79847.04
2020-03-31     97920.18
2019-08-31    205279.45
Name: withdrawal, dtype: float64

@shivsn 代码的作用相同。

>>> df.groupby(df['Date'].dt.strftime('%B'))['withdrawal'].sum().sort_values()
Date
October       28710.00
April         31437.00
July          39728.00
November      40121.00
May           46495.00
February      57751.10
December      72469.13
January       76115.78
June          76947.00
September     79847.04
March         97920.18
August       205279.45
Name: withdrawal, dtype: float64

【讨论】:

groupby 工作正常时,为什么必须将日期设置为DataFrame 索引?如果重复相同的日期会发生什么?我还将日期格式视为第一步,即投票率最高的答案,因为从问题中不清楚该列是否会正确格式化。 要么是重复的,要么是唯一的,它将汇总所有这些值。它的作用与 groupby 相同。除了 groupby 选项之外,通过将日期列设置为索引,您可以执行更多基本操作。谢谢。【参考方案5】:

试试这个:

    将日期列更改为日期时间格式。

    --->df['Date'] = pd.to_datetime(df['Date'])

    在数据框中插入新行,月份为->[May, 'June']

    --->df['months'] = df['date'].apply(lambda x:x.strftime('%B'))

    ---> 这里 x 是取自数据框中日期列的日期。

    现在汇总月份列上的汇总数据并对收入求和。

    --->response_data_frame = df.groupby('months')['Revenue'].sum()

    ---->print(response_data_frame)

输出-:

| month | Revenue |

|-------|---------|

| May   | 500     |

| June  | 1000    |

【讨论】:

【参考方案6】:
df['Month'] = pd.DatetimeIndex(df['date']).month_name()

使用这个你应该得到

date Revenue Month
6/2/2017 100 June
5/23/2017 200 May
5/20/2017 300 May
6/22/2017 400 June
6/21/2017 500 June

【讨论】:

以上是关于如何使用 Python/Pandas 从日期字段按月分组的主要内容,如果未能解决你的问题,请参考以下文章

如何使用sql从日期字段按月分组

如何根据当前日期使用 python Pandas 从 Excel 工作表加载特定工作簿

Python Pandas:按日期分组,并按时间戳访问每个组

Python pandas根据日期范围按升序过滤数据

我如何编写一个 python/pandas 循环来将 sql 查询中的日期增加一天

从空格分隔的 .dat 文件中获取日期时间 - python/pandas [重复]