假设你有这个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
我不能用大熊猫得到结果。我能想到的唯一解决方案是在数据帧中逐行迭代,但我真的想避免这样做。有一种优雅的方式吗?
答案 0 :(得分: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中将其用作区间的下限。
然后,一旦您将存储桶列表作为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
现在就像使用 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。