python – pandas – 将列的一部分聚合到新列中的新值

我有一个大型pandas数据帧df,仓库数据显示收到的项目数量.

想象一下结构的相关部分:

Date         SKU    received
2017-05-29   sku1   0
2017-05-30   sku1   0
2017-05-31   sku1   0
2017-06-01   sku1   0
2017-06-02   sku1   6
2017-06-03   sku1   2
2017-05-29   sku2   4
2017-05-30   sku2   4
2017-05-31   sku2   0
2017-06-01   sku2   0
2017-06-02   sku2   0
2017-06-03   sku2   24

从这里我想重建订单流程.我知道,股票水平在星期一进行审查,根据库存水平,新订单被放置.大约一周后,订单到达仓库,有时分成多个发货.

我想为工作日创建一个额外的列(df [“Weekday”])和已下订单(df [“Order”]).根据工作日,我想汇总下一个4到11天的“收到”栏的数据,仅限于相关的SKU.

输出可能如下所示:

Date         SKU    received    Weekday    Order
2017-05-29   sku1   0           0          8
2017-05-30   sku1   0           1          0
2017-05-31   sku1   0           2          0  
2017-06-01   sku1   0           3          0
2017-06-02   sku1   6           4          0
2017-06-03   sku1   2           5          0
2017-05-29   sku2   4           0          24
2017-05-30   sku2   4           1          0
2017-05-31   sku2   0           2          0
2017-06-01   sku2   0           3          0
2017-06-02   sku2   0           4          0
2017-06-03   sku2   24          5          0

这是我试过的代码:

import pandas as pd

# 0 is Monday, 1 is Tuesday, etc
df["Weekday"] = df["Date"].dt.dayofweek

# create new column for the orders
df["Order"] = 0

min_days = 4
max_days = min_days + 7

for i in range(len(df)):
    if df.loc[i, "Weekday"] == 0:
        df.loc[i, "Order"] = df.loc[(df.Date >= df.loc[i, "Date"] + pd.to_timedelta(min_days, unit="D")) &
                                    (df.Date < df.loc[i, "Date"] + pd.to_timedelta(max_days, unit="D")) &
                                    (df.SKU == df.loc[i, "SKU"]), "received"].sum()

它似乎可以完成这项工作,但速度很慢.也许有人可以帮我找到一个更加pythonic / pandas的方法来节省一些计算时间.

谢谢你的帮助.

最佳答案 这是一个使用pandas groupby和transform的可能解决方案.

第一个想法是,你可以通过计算滚动金额的差异来实现两天之间的计数.另外,请注意两次恢复订单([:: – 1])的技巧,以便将来可以选择滚动金额.

def count_between(ts, min_days, max_days):
    return ts[::-1].pipe(lambda y: y.rolling(max_days,1).sum() - y.rolling(min_days-1,1).sum())[::-1]

此函数将为您提供每天的结果,因此您将结果限制为星期一,仅将所有其他条目设置为0(使用[.where] [1]).

将Date设置为索引后,您可以执行以下操作:

order = df.groupby('SKU')\
          .transform(lambda x: count_between(x, min_days, max_days)\
                               .where(lambda y: y.index.dayofweek==0, other = 0))
order.columns = ['Order']

这给出了预期的结果:

pd.concat([df, order], axis = 1)
Out[319]: 
             SKU  received  Order
Date                             
2017-05-29  sku1         0    8.0
2017-05-30  sku1         0    0.0
2017-05-31  sku1         0    0.0
2017-06-01  sku1         0    0.0
2017-06-02  sku1         6    0.0
2017-06-03  sku1         2    0.0
2017-05-29  sku2         4   24.0
2017-05-30  sku2         4    0.0
2017-05-31  sku2         0    0.0
2017-06-01  sku2         0    0.0
2017-06-02  sku2         0    0.0
2017-06-03  sku2        24    0.0
点赞