熊猫:用groupby重新采样时间序列

时间:2015-08-14 14:04:02

标签: python pandas group-by time-series

鉴于以下pandas DataFrame:

In [115]: times = pd.to_datetime(pd.Series(['2014-08-25 21:00:00','2014-08-25 21:04:00',
                                            '2014-08-25 22:07:00','2014-08-25 22:09:00']))
          locations = ['HK', 'LDN', 'LDN', 'LDN']
          event = ['foo', 'bar', 'baz', 'qux']
          df = pd.DataFrame({'Location': locations,
                             'Event': event}, index=times)
          df
Out[115]:
                               Event Location
          2014-08-25 21:00:00  foo   HK
          2014-08-25 21:04:00  bar   LDN
          2014-08-25 22:07:00  baz   LDN
          2014-08-25 22:09:00  qux   LDN

我想重新对数据进行重新采样,按位数按小时聚合,同时按位置分组以生成如下所示的数据框:

Out[115]:
                               HK    LDN
          2014-08-25 21:00:00  1     1
          2014-08-25 22:00:00  0     2

我尝试了resample()和groupby()的各种组合,但没有运气。我该怎么做呢?

4 个答案:

答案 0 :(得分:37)

在我的原帖中,我建议使用pd.TimeGrouper。 现在,使用pd.Grouper代替pd.TimeGrouper。语法基本相同,但TimeGrouper is now deprecated支持pd.Grouper

此外,虽然pd.TimeGrouper只能按DatetimeIndex进行分组,但pd.Grouper可以按日期时间分组,您可以通过key parameter指定。

您可以使用pd.Grouper按小时对DatetimeIndex的DataFrame进行分组:

grouper = df.groupby([pd.Grouper(freq='1H'), 'Location'])

使用count计算每组中的事件数量:

grouper['Event'].count()
#                      Location
# 2014-08-25 21:00:00  HK          1
#                      LDN         1
# 2014-08-25 22:00:00  LDN         2
# Name: Event, dtype: int64

使用unstackLocation索引级别移至列级别:

grouper['Event'].count().unstack()
# Out[49]: 
# Location             HK  LDN
# 2014-08-25 21:00:00   1    1
# 2014-08-25 22:00:00 NaN    2

然后使用fillna将NaN更改为零。

全部放在一起,

grouper = df.groupby([pd.Grouper(freq='1H'), 'Location'])
result = grouper['Event'].count().unstack('Location').fillna(0)

产量

Location             HK  LDN
2014-08-25 21:00:00   1    1
2014-08-25 22:00:00   0    2

答案 1 :(得分:27)

Pandas 0.21回答:TimeGrouper is getting deprecated

这样做有两种选择。他们实际上可以根据您的数据给出不同的结果。第一个选项按位置分组,按位置分组按小时分组。第二个选项按位置和小时同时分组。

选项1 :使用groupby + resample

grouped = df.groupby('Location').resample('H')['Event'].count()

选项2 :将位置和DatetimeIndex与groupby(pd.Grouper)

组合在一起
grouped = df.groupby(['Location', pd.Grouper(freq='H')])['Event'].count()

它们都会产生以下结果:

Location                     
HK        2014-08-25 21:00:00    1
LDN       2014-08-25 21:00:00    1
          2014-08-25 22:00:00    2
Name: Event, dtype: int64

然后重塑:

grouped.unstack('Location', fill_value=0)

将输出

Location             HK  LDN
2014-08-25 21:00:00   1    1
2014-08-25 22:00:00   0    2

答案 2 :(得分:7)

多列组按

untubu与他的答案一致,但我想补充一下,如果你有第三列,你可以做些什么,比如Cost,并想像上面那样聚合它。通过结合unutbu的答案和this one,我发现了如何做到这一点,并认为我将为未来的用户分享。

使用Cost列创建一个DataFrame:

In[1]:
import pandas as pd
import numpy as np
times = pd.to_datetime([
    "2014-08-25 21:00:00", "2014-08-25 21:04:00",
    "2014-08-25 22:07:00", "2014-08-25 22:09:00"
])
df = pd.DataFrame({
    "Location": ["HK", "LDN", "LDN", "LDN"],
    "Event":    ["foo", "bar", "baz", "qux"],
    "Cost":     [20, 24, 34, 52]
}, index = times)
df

Out[1]:
                     Location  Event  Cost
2014-08-25 21:00:00        HK    foo    20
2014-08-25 21:04:00       LDN    bar    24
2014-08-25 22:07:00       LDN    baz    34
2014-08-25 22:09:00       LDN    qux    52

现在,我们使用agg功能进行分组,以指定每个列的聚合方法,例如:计数,平均值,总和等。

In[2]:
grp = df.groupby([pd.Grouper(freq = "1H"), "Location"]) \
      .agg({"Event": np.size, "Cost": np.mean})
grp

Out[2]:
                               Event  Cost
                     Location
2014-08-25 21:00:00  HK            1    20
                     LDN           1    24
2014-08-25 22:00:00  LDN           2    43

然后最后unstack的填充NaN带有零,并显示为int因为它很好。

In[3]: 
grp.unstack().fillna(0).astype(int)

Out[3]:
                    Event     Cost
Location               HK LDN   HK LDN
2014-08-25 21:00:00     1   1   20  24
2014-08-25 22:00:00     0   2    0  43

答案 3 :(得分:0)

可以不使用resampleGrouper来完成此操作,如下所示:

df.groupby([df.index.floor("1H"), "Location"]).count()