Python Pandas 有条件的聚合
Python Pandas aggregation with condition
我需要对我的数据框进行分组,并在不同的列上使用多个聚合函数。而且这个聚合有些是有条件的。
这是一个例子。数据是2个客户的所有订单,我想计算每个客户的一些信息。比如他们的订单数,他们的总消费和平均消费。
import pandas as pd
data = {'order_id' : range(1,9),
'cust_id' : [1]*5 + [2]*3,
'order_amount' : [100,50,70,75,80,105,30,20],
'cust_days_since_reg' : [0,10,25,37,52,0,17,40]}
orders = pd.DataFrame(data)
aggregation = {'order_id' : 'count',
'order_amount' : ['sum', 'mean']}
cust = orders.groupby('cust_id').agg(aggregation).reset_index()
cust.columns = ['_'.join(col) for col in cust.columns.values]
这很好用,给了我:
_
但我必须添加一个带有参数和条件的聚合函数:客户在前 X 个月内花费的金额(X 必须是可自定义的)
因为我在这个聚合中需要一个参数,所以我尝试了:
def spendings_X_month(group, n_months):
return group.loc[group['cust_days_since_reg'] <= n_months*30,
'order_amount'].sum()
aggregation = {'order_id' : 'count',
'order_amount' : ['sum',
'mean',
lambda x: spendings_X_month(x, 1)]}
cust = orders.groupby('cust_id').agg(aggregation).reset_index()
但是最后一行给我错误:KeyError: 'cust_days_since_reg'
。
这一定是一个范围错误,cust_days_since_reg
列在这种情况下一定是不可见的。
我可以单独计算最后一列,然后将生成的数据帧连接到第一列,但必须有更好的解决方案,使每件事都只在一个 groupby 中。
谁能帮我解决这个问题?
谢谢
不能使用agg
,因为每个函数只作用于一列,所以这种基于另一列的过滤是不可能的。
解决方案使用GroupBy.apply
:
def spendings_X_month(group, n_months):
a = group['order_id'].count()
b = group['order_amount'].sum()
c = group['order_amount'].mean()
d = group.loc[group['cust_days_since_reg'] <= n_months*30,
'order_amount'].sum()
cols = ['order_id_count','order_amount_sum','order_amount_mean','order_amount_spendings']
return pd.Series([a,b,c,d], index=cols)
cust = orders.groupby('cust_id').apply(spendings_X_month, 1).reset_index()
print (cust)
cust_id order_id_count order_amount_sum order_amount_mean \
0 1 5.0 375.0 75.000000
1 2 3.0 155.0 51.666667
order_amount_spendings
0 220.0
1 135.0
我需要对我的数据框进行分组,并在不同的列上使用多个聚合函数。而且这个聚合有些是有条件的。
这是一个例子。数据是2个客户的所有订单,我想计算每个客户的一些信息。比如他们的订单数,他们的总消费和平均消费。
import pandas as pd
data = {'order_id' : range(1,9),
'cust_id' : [1]*5 + [2]*3,
'order_amount' : [100,50,70,75,80,105,30,20],
'cust_days_since_reg' : [0,10,25,37,52,0,17,40]}
orders = pd.DataFrame(data)
aggregation = {'order_id' : 'count',
'order_amount' : ['sum', 'mean']}
cust = orders.groupby('cust_id').agg(aggregation).reset_index()
cust.columns = ['_'.join(col) for col in cust.columns.values]
这很好用,给了我:
但我必须添加一个带有参数和条件的聚合函数:客户在前 X 个月内花费的金额(X 必须是可自定义的)
因为我在这个聚合中需要一个参数,所以我尝试了:
def spendings_X_month(group, n_months):
return group.loc[group['cust_days_since_reg'] <= n_months*30,
'order_amount'].sum()
aggregation = {'order_id' : 'count',
'order_amount' : ['sum',
'mean',
lambda x: spendings_X_month(x, 1)]}
cust = orders.groupby('cust_id').agg(aggregation).reset_index()
但是最后一行给我错误:KeyError: 'cust_days_since_reg'
。
这一定是一个范围错误,cust_days_since_reg
列在这种情况下一定是不可见的。
我可以单独计算最后一列,然后将生成的数据帧连接到第一列,但必须有更好的解决方案,使每件事都只在一个 groupby 中。
谁能帮我解决这个问题?
谢谢
不能使用agg
,因为每个函数只作用于一列,所以这种基于另一列的过滤是不可能的。
解决方案使用GroupBy.apply
:
def spendings_X_month(group, n_months):
a = group['order_id'].count()
b = group['order_amount'].sum()
c = group['order_amount'].mean()
d = group.loc[group['cust_days_since_reg'] <= n_months*30,
'order_amount'].sum()
cols = ['order_id_count','order_amount_sum','order_amount_mean','order_amount_spendings']
return pd.Series([a,b,c,d], index=cols)
cust = orders.groupby('cust_id').apply(spendings_X_month, 1).reset_index()
print (cust)
cust_id order_id_count order_amount_sum order_amount_mean \
0 1 5.0 375.0 75.000000
1 2 3.0 155.0 51.666667
order_amount_spendings
0 220.0
1 135.0