2017-06-20 65 views
3

我有一個大的pandas數據框df,倉庫數據顯示接收到的項目數量。pandas - 在新列中聚集列的一部分到新值

想象結構的相關部分爲:

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

這是一個可能的解決方案,它使用熊貓groupby和變換。

第一個想法是,您可以通過計算滾動和的差值來實現兩天之間的計數。此外,請注意兩次還原訂單([::-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 
+0

感謝@FLab。我的'df'實際上有點大,有更多的列,'Date'不是索引,這就是爲什麼我運行代碼'y.index.dayofweek == 0'遇到麻煩。 – Axel

+0

將代碼調整爲'count_between(x.received,min_days,max_days)'和'.where(lambda y:y.Date.dayofweek == 0')沒有幫助。我是否缺少某些東西? – Axel

+0

哦,是的,應該有提到我設置日期作爲索引,你不能操作數據框的一個子集,看起來像報告的例子嗎?在此期間,我會想一個修復 – FLab