2016-11-21 90 views
2

我正在嘗試在熊貓中爲矢量化for循環以提高性能。我有一個數據集,包括用戶,產品,每個服務的日期以及提供的天數。鑑於數據的子集:熊貓:條件累積和的矢量化

testdf = pd.DataFrame(data={"USERID": ["A"] * 6, 
          "PRODUCTID": [1] * 6, 
          "SERVICEDATE": [datetime(2016, 1, 1), datetime(
           2016, 2, 5), 
          datetime(2016, 2, 28), datetime(2016, 3, 25), 
          datetime(2016, 4, 30), datetime(2016, 5, 30)], 
          "DAYSSUPPLY": [30] * 6}) 

testdf=testdf.set_index(["USERID", "PRODUCTID"]) 
testdf["datediff"] = testdf["SERVICEDATE"].diff() 
testdf.loc[testdf["datediff"].notnull(), "datediff"] = testdf.loc[ 
    testdf["datediff"].notnull(), "datediff"].apply(lambda x: x.days) 
testdf["datediff"] = testdf["datediff"].fillna(0) 
testdf["datediff"] = pd.to_numeric(testdf["datediff"]) 
testdf["over_under"] = testdf["DAYSSUPPLY"].shift() - testdf["datediff"] 

我希望得到以下結果:

    DAYSSUPPLY SERVICEDATE datediff over_under desired 
USERID PRODUCTID              
A  1     30 2016-01-01   0   NaN  0 
     1     30 2016-02-05  35  -5.0  0 
     1     30 2016-02-28  23   7.0  7 
     1     30 2016-03-25  26   4.0  11 
     1     30 2016-04-30  36  -6.0  5 
     1     30 2016-05-30  30   0.0  5 

從本質上講,我想我需要的列是over_under的運行總和,但只求和負值如果需要的上一行值> 0。期望不應該得到低於0在[用戶,產品] A組快速和骯髒的循環看起來像這樣:

running_total = 0 
desired_loop = [] 
for row in testdf.itertuples(): 
    over_under=row[4] 
    # skip first row 
    if pd.isnull(over_under): 
     desired_loop.append(0) 
     continue 
    running_total += over_under 
    running_total = max(running_total, 0) 
    desired_loop.append(running_total) 
testdf["desired_loop"] = desired_loop 

        desired_loop 
USERID PRODUCTID    
A  1     0.0 
     1     0.0 
     1     7.0 
     1     11.0 
     1     5.0 
     1     5.0 

我ST矢量化和大熊貓和一般的新病症。我已經能夠在這個DF中矢量化每一個其他的計算,但是這個累積和的特殊情況我只是無法弄清楚如何去做。

謝謝!

回答

0

我有一個類似的問題,並使用一個有點非傳統的迭代解決它。

testdf["desired"] = testdf["over_under"].cumsum() 
current = np.argmax(testdf["desired"] < 0) 
while current != 0: 
    testdf.loc[current:,"desired"] += testdf["desired"][current] # adjust the cumsum going forward 
    # the previous statement also implicitly sets 
    # testdf.loc[current, "desired"] = 0 
    current = np.argmax(testdf["desired"][current:] < 0) 

從本質上講,您正在查找所有「事件」並隨着時間的推移重新調整運行的cumsum。所有的操作和測試操作都是矢量化的,所以如果您的desired列不會經常出現負面情況,那麼您應該非常快。

這絕對是一個黑客,但它爲我完成了工作。