pandas - 在新列

时间:2017-06-20 08:58:27

标签: 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的方法来节省一些计算时间。

感谢您的帮助。

1 个答案:

答案 0 :(得分:1)

这是一个使用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