Pandas groupby 聚合以截断最早日期而不是最旧日期
Posted
技术标签:
【中文标题】Pandas groupby 聚合以截断最早日期而不是最旧日期【英文标题】:Pandas groupby aggregation to truncate earliest date instead of oldest date 【发布时间】:2018-08-23 04:47:45 【问题描述】:我正在尝试从日期范围的末尾而不是从开头进行聚合。尽管我认为将 closed='right'
添加到 grouper 可以解决问题,但事实并非如此。请让我知道如何实现底部显示的所需输出,谢谢。
import pandas as pd
df = pd.DataFrame(columns=['date','number'])
df['date'] = pd.date_range('1/1/2000', periods=8, freq='T')
df['number'] = pd.Series(range(8))
df
date number
0 2000-01-01 00:00:00 0
1 2000-01-01 00:01:00 1
2 2000-01-01 00:02:00 2
3 2000-01-01 00:03:00 3
4 2000-01-01 00:04:00 4
5 2000-01-01 00:05:00 5
6 2000-01-01 00:06:00 6
7 2000-01-01 00:07:00 7
通过 groupby 和日期的聚合,我得到以下信息。由于我有 8 个日期并且我按 3 个周期进行分组,因此它必须选择是截断最早的日期组还是最旧的日期组,并且它选择最旧的日期组(最旧的日期组的计数为 2):
df.groupby(pd.Grouper(key='date', freq='3T')).agg('count')
date number
2000-01-01 00:00:00 3
2000-01-01 00:03:00 3
2000-01-01 00:06:00 2
我想要的输出是截断 最早 日期组:
date number
2000-01-01 00:00:00 2
2000-01-01 00:02:00 3
2000-01-01 00:05:00 3
请让我知道如何实现这一点,我希望只有一个可以设置的参数被我忽略了。请注意,这类似于this 问题,但我的问题是针对日期截断的。
编辑:为了重新构建问题(感谢 Alexdor),pandas 中的默认行为是按 [0, 3)、[3, 6)、[6, 9) 周期分箱,但我想按 ( -1, 2], (2, 5], (5, 8]
【问题讨论】:
@jpp 这不会解决问题,因为日期不会像我想要的输出那样。但如果我误解你,请纠正我。 【参考方案1】:似乎 grouper 函数从您传递给它的系列中最早的时间开始构建垃圾箱。我看不出有什么方法可以让它从最新开始构建垃圾箱,但从头开始构建垃圾箱相当容易。
freq = '3min'
minTime = df.date.min()
maxTime = df.date.max()
deltaT = pd.Timedelta(freq)
minTime -= deltaT - (maxTime - minTime) % deltaT # adjust min time to start of first bin
r = pd.date_range(start=minTime, end=maxTime, freq=freq)
df.groupby(pd.cut(df["date"], r)).agg('count')
给予
date date number
(1999-12-31 23:58:00, 2000-01-01 00:01:00] 2 2
(2000-01-01 00:01:00, 2000-01-01 00:04:00] 3 3
(2000-01-01 00:04:00, 2000-01-01 00:07:00] 3 3
【讨论】:
输出中的第二个日期列是什么? 我的格式不是很好。第一个日期是索引,第二个是df的日期列中的计数 作为以后任何人的参考,您可以将上面的“间隔”日期索引转换为正常日期,如下所示:df.index = pd.to_datetime(pd.Series(df.index).apply(lambda x: x.right.date()))
。如果您想保留时间戳部分,请忽略 .date()
【参考方案2】:
这是一个技巧,让您可以按恒定的组大小进行分组,自下而上计数。
from itertools import chain
def grouper(x, k=3):
n = len(df.index)
return list(chain.from_iterable([[0]*int(n//k)] + [[i]*k for i in range(1, int(n/k)+1)]))
df['grouper'] = grouper(df, 3)
res = df.groupby('grouper', as_index=False)\
.agg('date': 'first', 'number': 'count')\
.drop('grouper', 1)
# date number
# 0 2000-01-01 00:00:00 2
# 1 2000-01-01 00:02:00 3
# 2 2000-01-01 00:05:00 3
【讨论】:
问题很明显。他希望日期落入 (-2, 1]、(1, 4] 和 (4, 7] 的箱中,而不是 [0, 3)、[3, 6)、[6, 9] 的默认行为)。您所做的只是对列进行排序以适合示例输出 @jpp 我的疑虑是您的“解决方案”没有任何意义——您将最后一组中的计数分配给第一组。如果示例不是对称的(每个间隔的计数不相等),则此方法不起作用。我可以将示例更改为更复杂,但我宁愿不这样做。编辑:alexdor 明白了。以上是关于Pandas groupby 聚合以截断最早日期而不是最旧日期的主要内容,如果未能解决你的问题,请参考以下文章
pandas groupby 可以聚合成一个列表,而不是 sum、mean 等吗?
为 pandas groupby 中的不同特征分配不同的聚合函数