Pandas 按时间和 ID 进行分组,并进行聚合

3

我正在尝试计算下半年支付的金额总和减去上半年的金额总和。

数据可能如下所示:

   ID   date    payment
    1   1/1/2020    10
    1   1/2/2020    11
    1   1/3/2020    10
    1   1/4/2020    10
    1   1/5/2020    11
    1   1/6/2020    10
    1   1/7/2020    10
    1   1/8/2020    11
    1   1/9/2020    10
    1   1/10/2020   32
    1   1/11/2020   10
    1   1/12/2020   12
    2   1/1/2020    10
    2   1/2/2020    10
    2   1/3/2020    41
    2   1/4/2020    10
    2   1/5/2020    53
    2   1/6/2020    10
    2   1/7/2020    10
    2   1/8/2020    44
    2   1/9/2020    10
    2   1/10/2020   2
    2   1/11/2020   9
    2   1/12/2020   5

我将数据框的日期转换为 Pandas 的日期时间。

df.date = df.date.astype(str).str.slice(0, 10)
df.date = pd.to_datetime(pay.date)

print(df.date.min(),df.date.max()) 
output: 2020-01-01 00:00:00 2020-12-01 00:00:00

然后我创建了时间点,并分别为上半年和下半年创建了不同的数据框

observation_date = '2020-12-31'
observation_date = datetime.strptime(observation_date, '%Y-%m-%d')
observation_date = observation_date.date()
observation_date = pd.Timestamp(observation_date)
print(observation_date)         

mo6_ago = observation_date - relativedelta(months=6) 
mo6_ago = pd.Timestamp(mo6_ago)
print(mo6_ago)

mo6_ago_plus1 = observation_date - relativedelta(months=6) + relativedelta(days=1)
mo6_ago_plus1 = pd.Timestamp(mo6_ago_plus1)
print(mo6_ago_plus1)

mo12_ago = observation_date - relativedelta(months=12) + relativedelta(days=1)
mo12_ago = pd.Timestamp(mo12_ago)
print(mo12_ago)

output:
2020-12-31 00:00:00
2020-06-30 00:00:00
2020-07-01 00:00:00
2020-01-01 00:00:00

mask = (df['date'] >= mo12_ago) & (df['date'] <= mo6_ago)
first_half = df.loc[mask]
first_half = first_half[['ID','date','payment']]
print(first_half.date.min(),first_half.date.max())

output: 2020-01-01 00:00:00 2020-06-01 00:00:00

mask = (df['date'] >= mo6_ago_plus1) & (df['date'] <= observation_date)
sec_half = df.loc[mask]
sec_half = sec_half[['ID','date','payment']]
print(sec_half.date.min(),sec_half.date.max())

output: 2020-07-01 00:00:00 2020-12-01 00:00:00

然后我将上半年和下半年分组并进行求和,然后将它们合并成一个数据框,如下所示:

sum_first_half = first_half.groupby(['ID'])['payment'].sum().reset_index()
sum_first_half = sum_first_half.rename(columns = {'payment':'payment_first_half'})

sum_sec_half = sec_half.groupby(['ID'])['payment'].sum().reset_index()
sum_sec_half = sum_sec_half.rename(columns = {'payment':'payment_sec_half'})

df_new = pd.merge(sum_first_half, sum_sec_half, how='outer', on='ID')

最后,我用以下方式减去了这两列

df_new['sec_minus_first'] = df_new['payment_sec_half'] -df_new['payment_first_half']

ID  payment_first_half  payment_sec_half    sec_minus_first
1         62                    85               23
2        134                    80              -54

有没有更快、更节省内存的方法来完成这个任务?

1个回答

2

使用datetime模块:

from datetime import datetime as dt

将日期列转换为日期时间格式:

df["date"] = pd.to_datetime(df["date"])

按您选择的日期拆分,按ID分组,对每一半求和,然后相减:

df.loc[df['date'] >= dt(2020, 7, 1)].groupby("ID").sum() - df.loc[df['date'] < dt(2020, 7, 1)].groupby("ID").sum()

谢谢!我可以问一下 dt(2020, 7, 1) 是否是表示年份的前半部分和后半部分的切割点,因此它表示的是2020年7月1日吗? - IceAsher Chew
是的,它正在创建一个日期时间,年份为2020年,月份为7月,日期为1日。请参阅链接文档。 - noah
非常感谢你的帮助!我简直无法相信解决方案是如此简短。 - IceAsher Chew
我应该点击这篇文章上的勾选按钮,对吗?抱歉,我很新手。 - IceAsher Chew
如果您发现任何答案有帮助,可以给它点赞(点击问题左侧的向上箭头使其变为橙色)。如果它是最好解决您问题的答案,您应该接受它(绿色勾号)。到目前为止,您已经接受了答案。我无法看到您是否点赞或其他人是否点赞。 - noah
完成了!再次感谢您! - IceAsher Chew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接