Python:将不同列的值分组为时间桶

时间:2017-12-05 10:52:21

标签: python pandas grouping binning

假设你有这个DataFrame:

Name    Item    Date    value1  value2
Marc    bike    21-Dec-17   7   1000
Marc    bike    05-Jan-18   9   2000
Marc    bike    27-Jul-18   4   500
John    house   14-Dec-17   4   500
John    house   02-Feb-18   6   500
John    house   07-Feb-18   8   1000
John    house   16-Feb-18   2   1000
John    house   05-Dec-21   7   1000
John    house   27-Aug-25   8   500
John    car     17-Apr-18   4   500

我想将value1和value2分为每个名称 - 项目组合的月度桶(每隔3个星期三,接下来的48个月)。

所以每个组合有49个时间段,每个月的值为1和value2之和:Marc / bike,John / house,John / car,......

John / house的解决方案如下:

Name    Item    TimeBucket  value1  value2
John    house   20-Dec-17   4   500
John    house   17-Jan-18   0   0
John    house   21-Feb-18   16  2500
John    house   21-Mar-18   0   0
John    house   18-Apr-18   0   0
John    house   …           0   0
John    house   17-Nov-21   0   0
John    house   15-Dec-21   7   1000
John    house   rest        8   500

我不能用大熊猫得到结果。我能想到的唯一解决方案是在数据帧中逐行迭代,但我真的想避免这样做。有一种优雅的方式吗?

1 个答案:

答案 0 :(得分:1)

问题实际上归结为三个步骤:

1。如何找到每个月的第三个星期三?

这可能不是最优雅的解决方案,但您可以通过屏蔽过滤掉{/ 1>}每个月的第三个星期三,其中包含时间范围内的每一天。

DatetimeIndex

将结果列表转换为# generate a DatetimeIndex for all days in the relevant time frame from datetime import datetime start = datetime(2017, 12, 1) end = datetime(2022, 1, 31) days = pd.date_range(start, end, freq='D') # filter out only the third wednesday of each month import itertools third_wednesdays = [] for year, month in itertools.product(range(2017, 2023), range(1,13)): mask = (days.weekday == 2) & \ (days.year == year) & \ (days.month == month) if len(days[mask]) > 0: third_wednesdays.append(days[mask][2]) bucket_lower_bounds = pd.DatetimeIndex(third_wednesdays) ,以便在步骤2中将其用作区间的下限。

2。如何分享DataFrame的值?

然后,一旦您将存储桶列表作为DatetimeIndex,您就可以使用panda's cut function将每个日期分配到存储桶。将日期列转换为整数,然后将它们传递到DatetimeIndex,然后将结果转换回日期:

cut

系列time_buckets = pd.to_datetime( pd.cut( x = pd.to_numeric(df['Date']), bins = pd.to_numeric(bucket_lower_bounds), labels = bucket_lower_bounds[:-1] ) ) 将原始数据框的每个索引值分配给存储桶的下限。我们现在可以简单地将它添加到原始数据框中:

time_buckets

结果应该看起来像这样(不是df['TimeBucket'] = time_buckets 代表“休息”桶):

NaT

3。如何聚合分箱的DataFrame?

现在就像使用 Name Item Date value1 value2 TimeBucket 0 Marc bike 2017-12-21 7 1000 2017-12-20 1 Marc bike 2018-01-05 9 2000 2017-12-20 2 Marc bike 2018-07-27 4 500 2018-07-18 3 John house 2017-12-14 4 500 NaT 4 John house 2018-02-02 6 500 2018-01-17 5 John house 2018-02-07 8 1000 2018-01-17 6 John house 2018-02-16 2 1000 2018-01-17 7 John house 2021-12-05 7 1000 2021-11-17 8 John house 2025-08-27 8 500 NaT 9 John car 2018-04-17 4 500 2018-03-21 获取名称,项目和存储桶的每个组合的总和一样简单:

groupby

结果:

df.groupby(['Name','Item','TimeBucket']).sum()

不幸的是,NaT values are excluded from groupby。如果您还需要对这些进行求和,也许最简单的方法是确保您的存储桶列表在输入范围内的每个日期都至少有一个存储桶。

编辑:第2步需要pandas版本> = 0.18.1。