熊猫数据框按日期时间月份分组


90

考虑一个csv文件:

string,date,number
a string,2/5/11 9:16am,1.0
a string,3/5/11 10:44pm,2.0
a string,4/22/11 12:07pm,3.0
a string,4/22/11 12:10pm,4.0
a string,4/29/11 11:59am,1.0
a string,5/2/11 1:41pm,2.0
a string,5/2/11 2:02pm,3.0
a string,5/2/11 2:56pm,4.0
a string,5/2/11 3:00pm,5.0
a string,5/2/14 3:02pm,6.0
a string,5/2/14 3:18pm,7.0

我可以阅读一下,然后将date列重新格式化为datetime格式:

b=pd.read_csv('b.dat')
b['date']=pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')

我一直在尝试按月对数据进行分组。似乎应该有一种明显的方式来访问月份并以此进行分组。但是我似乎做不到。有人知道吗?

我目前正在尝试按日期重新建立索引:

b.index=b['date']

我可以这样访问月份:

b.index.month

但是我似乎找不到按月汇总的函数。

Answers:


174

设法做到这一点:

b = pd.read_csv('b.dat')
b.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')
b.groupby(by=[b.index.month, b.index.year])

要么

b.groupby(pd.Grouper(freq='M'))  # update for v0.21+

52
我认为,更多的Pandonic方式是使用resample(当它提供所需的功能时)或使用TimeGrouperdf.groupby(pd.TimeGrouper(freq='M'))
Karl

10
以获得结果DataFrame的总和或平均值,df.groupby(pd.TimeGrouper(freq='M')).sum()df.groupby(pd.TimeGrouper(freq='M')).mean()
Alexandre

9
pd.TimeGrouper已不推荐使用,而是使用pd.Grouper,该方法稍微灵活一些,但仍带有freqlevel参数。
BallpointBen

第一种方法似乎无效。它给出了错误,“系列对象对于通过创建的系列没有属性”月” to_datetime
ely

1
@ely答案隐式依赖于原始问题中的各行,这些问题b是从CSV中读取后获得索引的。b.index = pd.to_datetime(b['date'],format='%m/%d/%y %I:%M%p')在行后添加b = pd.read_csv('b.dat')。[我现在也已经编辑了答案。]

72

(更新:2018)

请注意,它pd.Timegrouper已贬值,将被删除。改用:

 df.groupby(pd.Grouper(freq='M'))

2
找到石斑鱼文档这里(和频率规格freq=...这里。一些例子是freq=Dfreq=B工作日freq=W甚至freq=Q季度

1
我发现使用'key'避免重新索引df很有用,如下所示:df.groupby(pd.Grouper(key ='your_date_column',freq ='M'))
爱德华

10

一种避免MultiIndex的解决方案是创建一个新的datetime列设置日=1。然后按此列分组。下面的琐碎示例。

df = pd.DataFrame({'Date': pd.to_datetime(['2017-10-05', '2017-10-20']),
                   'Values': [5, 10]})

# normalize day to beginning of month
df['YearMonth'] = df['Date'] - pd.offsets.MonthBegin(1)

# two alternative methods
df['YearMonth'] = df['Date'] - pd.to_timedelta(df['Date'].dt.day-1, unit='D')
df['YearMonth'] = df['Date'].map(lambda dt: dt.replace(day=1))

g = df.groupby('YearMonth')

res = g['Values'].sum()

# YearMonth
# 2017-10-01    15
# Name: Values, dtype: int64

与之不同pd.Grouper,此解决方案的微妙好处是,将grouper索引标准化为每个月的开始而不是每个月的结束,因此您可以通过get_group以下方式轻松提取组:

some_group = g.get_group('2017-10-01')

计算十月的最后一天比较麻烦。pd.Grouper从v0.23开始,确实支持convention参数,但这仅适用于PeriodIndex石斑鱼。


8

@jpp的替代解决方案,但输出一个YearMonth字符串:

df['YearMonth'] = pd.to_datetime(df['Date']).apply(lambda x: '{year}-{month}'.format(year=x.year, month=x.month))

res = df.groupby('YearMonth')['Values'].sum()
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.