2017-02-09 196 views
0

我想在遍歷行時更新某些列值,但花了很長時間。我使用itertuples()而不是iterrows()作爲建議herehere,我不能使用apply函數,因爲我想在一次迭代中更新兩列。Python Pandas:在遍歷行時對DataFrame值進行一些更新

我將使用一個簡化的例子,因爲我的案例涉及10-ish多列,與下面的代碼無關。在這裏包括它們會使代碼看起來更糟糕。

import pandas as pd 
import numpy as np 

df = pd.DataFrame(np.random.randint(0, 5, size=(90000, 4)), 
        columns=['Initial', 'A', 'B']) 

df['code'] = list('KLMNOP' * 15000) # Adding column 'code' 

df = df.sort_values('code') # Sorting the df by 'code' 

df['Total'] = np.nan 

然後,我想更新基礎上的AB值列InitialTotal,然後也由以前行的Total更新Initial。 我的意思是,Total被結轉到下一行的Initial當電流code等於前一行的code

def produce_total(init, a, b): 
    if a >= 2 and b >= 2: 
     return init + 1 
    return init 

last_code = '' 
last_total = -100 
for row in df.itertuples(): 
    # Print the current checkpoint 
    if(row.Index % 1000 == 0): 
     print row.Index 

    # Carry over the prev Total to current Initial 
    if last_code == row.code: 
     df.loc[row.Index, 'Initial'] = last_total 

    # Prepare the updated Initial value 
    # Because what is inside 'row' seems unaffected by the update 
    new_initial = df.loc[row.Index, 'Initial'] 

    # Find Total and assign to the df 
    new_total = produce_total(
     new_initial, 
     row.A, 
     row.B 
    ) 
    df.loc[row.Index, 'Total'] = new_total 

    last_code = row.code 
    last_total = new_total 

代碼跑了將近一個小時,但只能達到30000指數十歲上下。任何想法或建議爲另一個或兩個有效的方法來做到這一點?

或者,我還需要考慮其他方面(刪除一些列等)?

非常感謝!

回答

0

IIUC,你需要使用pandas cumsum

這是我假定什麼,因爲每個碼初始總數始終是-100,&當過一個& B的值都大於2,需要添加一個先前的行總數。

import pandas as pd 
import numpy as np 

df = pd.DataFrame(np.random.randint(0, 5, size=(90000, 3)), 
        columns=['Initial', 'A', 'B']) 
df['code'] = list('KLMNOP' * 15000) # Adding column 'code' 

df = df.sort_values('code') # Sorting the df by 'code' 

df['new_Initial'] = np.where((df.A>2) & (df.B>2) ,1,0) 

df.set_value(0, 'new_Initial', -100) 
df.set_value(1, 'new_Initial', -100) 
df.set_value(2, 'new_Initial', -100) 
df.set_value(3, 'new_Initial', -100) 
df.set_value(4, 'new_Initial', -100) 

df['Total'] = df.groupby(['code']).new_Initial.cumsum() 
print df 

輸出

 Initial A B code new_Initial Total 
0   1 0 2 K   -100 -100 
84312  4 1 2 K   0 -100 
34110  1 4 0 K   0 -100 
34104  2 0 4 K   0 -100 
34098  0 4 3 K   1 -99 
34092  4 1 0 K   0 -99 
34086  2 2 4 K   0 -99 
34080  1 2 2 K   0 -99 
84318  4 2 2 K   0 -99 
34074  2 3 2 K   0 -99 
34116  2 1 1 K   0 -99 
34068  4 3 0 K   0 -99 
34056  4 3 4 K   1 -98 
34050  2 4 1 K   0 -98 
34044  1 1 0 K   0 -98 
84324  1 0 2 K   0 -98 
34038  0 1 0 K   0 -98 
34032  1 2 0 K   0 -98 
34026  0 1 1 K   0 -98 
34020  0 4 4 K   1 -97 
34014  0 0 4 K   0 -97 
34062  4 0 3 K   0 -97 
34122  2 3 3 K   1 -96 
34128  1 1 1 K   0 -96 
34134  3 2 3 K   0 -96 
34242  0 1 3 K   0 -96 
34236  4 3 2 K   0 -96 
34230  4 3 1 K   0 -96 
34224  4 2 0 K   0 -96 
84294  2 3 2 K   0 -96 
     ... .. .. ...   ... ... 
51245  4 4 0 P   0 2355 
51239  3 3 1 P   0 2355 
51365  0 1 2 P   0 2355 
51371  1 3 4 P   1 2356 
51377  4 2 3 P   0 2356 
51383  0 2 2 P   0 2356 
51515  0 2 1 P   0 2356 
51509  4 2 2 P   0 2356 
51503  3 0 0 P   0 2356 
51497  1 3 0 P   0 2356 
51491  4 3 2 P   0 2356 
51485  3 3 2 P   0 2356 
51479  4 0 3 P   0 2356 
51473  2 3 3 P   1 2357 
51467  3 4 3 P   1 2358 
51461  4 0 2 P   0 2358 
51827  4 0 2 P   0 2358 
51455  1 2 1 P   0 2358 
51443  3 0 4 P   0 2358 
51437  0 0 4 P   0 2358 
51431  2 2 2 P   0 2358 
51425  3 2 1 P   0 2358 
51419  2 3 2 P   0 2358 
51413  2 0 2 P   0 2358 
51407  0 1 3 P   0 2358 
51401  4 2 2 P   0 2358 
51395  2 4 4 P   1 2359 
51389  1 3 3 P   1 2360 
51449  3 4 0 P   0 2360 
89999  0 1 4 P   0 2360 
相關問題