2016-11-21 64 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列不会经常出现负面情况,那么您应该非常快。

这绝对是一个黑客,但它为我完成了工作。