【问题标题】:Pandas groupby aggregation to truncate earliest date instead of oldest datePandas groupby 聚合以截断最早日期而不是最旧日期
【发布时间】: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 这不会解决问题,因为日期不会像我想要的输出那样。但如果我误解你,请纠正我。

标签: python pandas aggregate pandas-groupby


【解决方案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 明白了。
猜你喜欢
  • 1970-01-01
  • 2018-06-29
  • 2014-09-21
  • 2013-06-06
  • 2021-12-15
  • 1970-01-01
  • 2021-07-17
  • 2016-07-16
  • 2020-09-28
相关资源
最近更新 更多