Pandas:使用 groupby 对时间序列重新采样
Pandas: resample timeseries with groupby
给定以下 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() 的各种组合,但没有成功。我该怎么做?
在我原来的 post 中,我建议使用 pd.TimeGrouper
。
现在,使用 pd.Grouper
而不是 pd.TimeGrouper
。语法基本相同,但 TimeGrouper
支持 pd.Grouper
.
此外,pd.TimeGrouper
只能按 DatetimeIndex 分组,pd.Grouper
可以按日期时间 columns 分组,您可以通过 key
parameter .
您可以使用 pd.Grouper
按小时对 DatetimeIndex 数据帧进行分组:
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
使用unstack
将Location
索引级别移动到列级别:
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
多列分组依据
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
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
这可以在不使用 resample
或 Grouper
的情况下完成,如下所示:
df.groupby([df.index.floor("1H"), "Location"]).count()
如果要保留所有列
df = (df.groupby("Location")
.resample("H", on="date")
.last()
.reset_index(drop=True))
给定以下 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() 的各种组合,但没有成功。我该怎么做?
在我原来的 post 中,我建议使用 pd.TimeGrouper
。
现在,使用 pd.Grouper
而不是 pd.TimeGrouper
。语法基本相同,但 TimeGrouper
pd.Grouper
.
此外,pd.TimeGrouper
只能按 DatetimeIndex 分组,pd.Grouper
可以按日期时间 columns 分组,您可以通过 key
parameter .
您可以使用 pd.Grouper
按小时对 DatetimeIndex 数据帧进行分组:
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
使用unstack
将Location
索引级别移动到列级别:
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
多列分组依据
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
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
这可以在不使用 resample
或 Grouper
的情况下完成,如下所示:
df.groupby([df.index.floor("1H"), "Location"]).count()
如果要保留所有列
df = (df.groupby("Location")
.resample("H", on="date")
.last()
.reset_index(drop=True))