Pandas:使用groupby重新采样时间序列

2ekbmq32  于 2023-06-20  发布在  其他
关注(0)|答案(6)|浏览(109)

给定下面的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

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

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

我尝试过reample()和groupby()的各种组合,但都没有成功。我该怎么办?

dfuffjeb

dfuffjeb1#

在我最初的帖子中,我建议使用pd.TimeGrouper。现在,使用pd.Grouper代替pd.TimeGrouper。语法基本相同,但TimeGrouperis now deprecated更倾向于pd.Grouper
此外,虽然pd.TimeGrouper只能按DatetimeIndex分组,但pd.Grouper可以按datetime columns 分组,您可以通过key参数指定。
您可以使用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
soat7uwm

soat7uwm2#

Pandas0.21回答:TimeGrouper is getting deprecated

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

    • 选项1**:使用groupby + resample
grouped = df.groupby('Location').resample('H')['Event'].count()
    • 选项二**:将位置和日期时间索引与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
iyfjxgzm

iyfjxgzm3#

多列分组依据

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
5uzkadbs

5uzkadbs4#

如果要保留所有列

df = (df.groupby("Location")
      .resample("H", on="date")
      .last()
      .reset_index(drop=True))
ngynwnxp

ngynwnxp5#

这可以在不使用resampleGrouper的情况下完成,如下所示:
df.groupby([df.index.floor("1H"), "Location"]).count()

pokxtpni

pokxtpni6#

pd.resample>>> pd.groupby()似乎快了很多倍

df = 

PJMW_MW
Datetime    
2002-04-01 01:00:00     4374.0
2002-04-01 02:00:00     4306.0
2002-04-01 03:00:00     4322.0
2002-04-01 04:00:00     4359.0
2002-04-01 05:00:00     4436.0
...     ...
2017-12-31 19:00:00     8205.0
2017-12-31 20:00:00     8053.0
2017-12-31 21:00:00     8012.0
2017-12-31 22:00:00     7864.0
2017-12-31 23:00:00     7710.0

138066 rows × 1 columns

%timeit df.resample(rule='24H', kind='interval').mean()
3.45 ms ± 41.9 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

%timeit df.groupby(df.index.strftime('%Y-%m-%d')).mean()
169 ms ± 1.09 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)

相关问题