如何按日期对pandas DataFrame中非唯一列的条目进行分组?

106

一个 Pandas DataFrame 包含一个名为 "date" 的列,其中包含非唯一的 datetime 值。 我可以使用以下代码对该数据框中的行进行分组:

data.groupby(data['date'])
然而,这将根据 datetime 值拆分数据。我想按 "date" 列中存储的年份对这些数据进行分组。此页面 显示了如何按年份分组的案例,其中时间戳用作索引,但在我的情况下并非如此。
我该如何实现这种分组?

对于那些在2017年及以后来到这里的人,有几种新的方法可以按特定时间段进行分组。请参见下面的答案 - Ted Petrou
6个回答

136

我正在使用pandas 0.16.2版本。这个版本在我的大型数据集上有更好的性能:

data.groupby(data.date.dt.year)

使用dt选项并尝试使用weekofyeardayofweek等参数变得更加容易。


同意,这似乎是访问系列日期属性的熊猫方式。 - dancow

80

ecatmur的解决方案可以正常工作。然而,在大型数据集上,以下方法会有更好的性能:

data.groupby(data['date'].map(lambda x: x.year))

9
为什么使用 map 而不是 apply? - Gus
1
据我所知,与仅使用apply相比,在应用任意函数时,map通常具有一些良好的效率特性。 - Coolio2654

44

可能通过一个示例数据集更容易解释。

创建示例数据

假设我们有一个时间戳的单列 date 和另一个我们想要聚合的列 a

df = pd.DataFrame({'date':pd.DatetimeIndex(['2012-1-1', '2012-6-1', '2015-1-1', '2015-2-1', '2015-3-1']),
                   'a':[9,5,1,2,3]}, columns=['date', 'a'])

df

        date  a
0 2012-01-01  9
1 2012-06-01  5
2 2015-01-01  1
3 2015-02-01  2
4 2015-03-01  3

有多种方法可以按年份进行分组:

  • 使用year属性的dt访问器
  • date放在索引中,并使用匿名函数访问年份
  • 使用resample方法
  • 转换为pandas时期

.dt访问器和year属性

如果您有一列(而不是索引)的pandas时间戳,则可以使用dt访问器访问更多额外的属性和方法。例如:

df['date'].dt.year

0    2012
1    2012
2    2015
3    2015
4    2015
Name: date, dtype: int64

我们可以使用这个方法来形成我们的分组,并在特定列上计算一些聚合结果:

df.groupby(df['date'].dt.year)['a'].agg(['sum', 'mean', 'max'])

      sum  mean  max
date                
2012   14     7    9
2015    6     2    3

将日期作为索引,并使用匿名函数访问年份

如果您将日期列设置为索引,则它将成为一个DateTimeIndex,具有与普通列相同的属性和方法,dt访问器可提供。

df1 = df.set_index('date')
df1.index.year

Int64Index([2012, 2012, 2015, 2015, 2015], dtype='int64', name='date')

有趣的是,在使用groupby方法时,你可以传递一个函数作为参数。这个函数会隐式地接受DataFrame的索引。因此,我们可以通过以下方式获得与上面相同的结果:

df1.groupby(lambda x: x.year)['a'].agg(['sum', 'mean', 'max'])

      sum  mean  max
2012   14     7    9
2015    6     2    3

使用 resample 方法

如果你的日期列不在索引中,你需要使用 on 参数指定该列。同时,你需要将偏移别名作为字符串来指定。

df.resample('AS', on='date')['a'].agg(['sum', 'mean', 'max'])

             sum  mean  max
date                       
2012-01-01  14.0   7.0  9.0
2013-01-01   NaN   NaN  NaN
2014-01-01   NaN   NaN  NaN
2015-01-01   6.0   2.0  3.0
你也可以将日期列转换为 pandas 的 Period 对象。我们必须将偏移量别名作为字符串传递以确定 Period 的长度。
df['date'].dt.to_period('A')

0   2012
1   2012
2   2015
3   2015
4   2015
Name: date, dtype: object
我们可以将这个作为一个组来使用。
df.groupby(df['date'].dt.to_period('Y'))['a'].agg(['sum', 'mean', 'max'])


      sum  mean  max
2012   14     7    9
2015    6     2    3

1
在你最后一个方法中使用了 to_period('A'),那个 ('A') 是什么意思? - shiv_90
2
@Shiv_90 'A' 是一个时间序列偏移别名:https://pandas.pydata.org/pandas-docs/stable/timeseries.html#offset-aliases - ptim
如果需要单独保存“日期”列,你会推荐哪种方法?例如,如果我运行简单的 .dt.year 方法并将其保存到新的数据框中,日期会保存为索引,如果需要绘制数据时,这可能会导致问题,因为“日期”列实际上并不存在,只提供了 .agg() 中的三列。 - shiv_90

15
这应该可以运行:
data.groupby(lambda x: data['date'][x].year)

1
这也可以工作。

data.groupby(data['date'].dt.year)


应该可以工作,但执行时输出的是对象在内存中的位置,而没有真正的输出。当我执行时,得到的是 <pandas.core.groupby.DataFrameGroupBy object at 0x10d7f6438> - shiv_90

0

使用:

data.groupby(['col1', data.date.dt.year]).agg({'col2': 'agg_func'}).reset_index()

如果您想按照日期时间列和另一个不同类型的列(col1)分组


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接