【问题标题】:pandas - adding new aggregated featurepandas - 添加新的聚合功能
【发布时间】:2021-01-21 09:42:39
【问题描述】:

我在 pandas 中有这个数据框:

   day customer  amount
0    1    cust1     500
1    2    cust2     100
2    1    cust1      50
3    2    cust1     100
4    2    cust2     250
5    6    cust1      20

为方便起见:

df = pd.DataFrame({'day': [1, 2, 1, 2, 2, 6],
                   'customer': ['cust1', 'cust2', 'cust1', 'cust1', 'cust2', 'cust1'],
                   'amount': [500, 100, 50, 100, 250, 20]})

我想创建一个新列“amount2days”,以便汇总过去两天每位客户的金额,以获得以下数据框:

   day customer  amount    amount2days   ----------------------------
0    1    cust1     500    500           (no past transactions)
1    2    cust2     100    100           (no past transactions)
2    1    cust1      50    550           (500 + 50 = rows 0,2 
3    2    cust1     100    650           (500 + 50 + 100, rows 0,2,3)
4    2    cust2     250    350           (100 + 250, rows 1,4) 
5    6    cust1      20    20            (notice day is 6, and no day=5 for cust1)

即我想执行以下(伪)代码:

df['amount2days'] = df_of_past_2_days['amount'].sum()

对于每一行。这样做最方便的方法是什么?

我希望对一天进行求和,但天数不一定要在每个新行中递增,如示例所示。我仍然想总结过去 2 天的金额。

【问题讨论】:

标签: python pandas


【解决方案1】:

groupbySeries.rollingsum 一起使用

通知: 这里有必要添加DataFrame.reset_index以避免数据对齐错误:

df['amount2days'] = (df.groupby('customer')['amount']
                       .rolling(2, min_periods=0)
                       .sum()
                       .reset_index(level=0, drop=True))
print (df)
   day customer  amount  amount2days
1    1    cust1     500        500.0
2    2    cust1     100        600.0
3    3    cust1     250        350.0

为什么不在这里使用.to_numpy?因为如果不是默认索引,那么输出应该被错误地分配 - 检查下面的示例:

df = pd.DataFrame({'day': {0: 1, 2: 2, 5: 3, 1: 1, 6: 2, 4: 3}, 'customer': {0: 'cust2', 2: 'cust2', 5: 'cust2', 1: 'cust1', 6: 'cust1', 4: 'cust1'}, 'amount': {0: 5000, 2: 1000, 5: 2500, 1: 500, 6: 100, 4: 250}})
print (df)
   day customer  amount
0    1    cust2    5000
2    2    cust2    1000
5    3    cust2    2500
1    1    cust1     500
6    2    cust1     100
4    3    cust1     250

df['amount2days'] = (df.groupby('customer', sort=False).amount
                       .rolling(2, min_periods=0)
                       .sum()
                       .to_numpy())

df['amount2days1'] = (df.groupby('customer')['amount']
                       .rolling(2, min_periods=0)
                       .sum()
                       .reset_index(level=0, drop=True))
print (df)
   day customer  amount  amount2days  amount2days1
0    1    cust2    5000        500.0        5000.0
2    2    cust2    1000        600.0        6000.0
5    3    cust2    2500        350.0        3500.0
1    1    cust1     500       5000.0         500.0
6    2    cust1     100       6000.0         600.0
4    3    cust1     250       3500.0         350.0

编辑:一般解决方案:

def f(x):
    N = 1
    for i in pd.unique(x['day']):
        y = x[x['day'].between(i - N, i)]
        x.loc[y.index[-1], 'amountNdays'] = y['amount'].sum()
    
    return x

df = df.groupby('customer').apply(f)
df['amountNdays'] = df['amountNdays'].fillna(df['amount'])
print (df)
   day customer  amount  amountNdays
0    1    cust1     500        500.0
1    2    cust2     100        100.0
2    1    cust1      50        550.0
3    2    cust1     100        650.0
4    2    cust2     250        350.0
5    6    cust1      20         20.0

【讨论】:

  • 谢谢。我已经更新了我的问题以更清楚。我的数据不一定会在每个新行中增加“天”,但我仍然想向后汇总 2 天。在这种情况下,简单的滚动会起作用吗?
  • 在向后行没有什么可以求和的情况下仍然无法工作,我再次编辑了我的示例(应该只有 20,但这种方法在那里给出 120)。谢谢。
  • @jezarel 与“那里”我的意思是最后一行的“amount2days”。
  • 也许有一种方法可以轻松地将其概括为amount_x_days?
  • @user112112 - 添加通用解决方案
【解决方案2】:

您可以使用熊猫的rolling 进行移动窗口操作(取决于熊猫的版本,reset_index 如 jezrael 的回答会更安全):

df['amount2days'] = (df.groupby('customer', sort=False).amount
                       .rolling(2, min_periods=0)
                       .sum()
                       .to_numpy()) 

print(df)
   day customer  amount  amount2days
1    1    cust1     500        500.0
2    2    cust1     100        600.0
3    3    cust1     250        350.0

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-26
  • 2015-12-10
相关资源
最近更新 更多