2017-02-27 48 views
3

我有一個數據幀df是像這樣定義:以更有效的方式後續行之間的應用功能與熊貓

import numpy as np 
import pandas as pd 
dic = {'A':['1A','1A','3C','3C','3C','7M','7M','7M'],'B':[10,15,49,75,35,33,45,65],'C':[11,56,32,78,45,89,15,14],'D':[111,0,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan],'E':[0,222,np.nan,np.nan,np.nan,np.nan,np.nan,np.nan]} 

df = pd.DataFrame(dic) 

我的目標是具有A列在同一項目行之間進行一些計算。

的函數被定義爲是這樣的(但可以是任何東西):

def fun(a,b,c,d): 
    out = a*c + b/2 + d*b 
    return out 

這樣的操作的結果將根據以下規則被存儲在列d和E:

# Fill column D 
for j in range(0,len(df)-1): 
    if df['A'].iloc[j]==df['A'].iloc[j+1] and pd.isnull(df['D'].iloc[j]): 
     df['D'].iloc[j] = fun(df['B'].iloc[j],df['B'].iloc[j],df['B'].iloc[j+1],df['B'].iloc[j+1]) 

# Fill column E  
for j in reversed(range(1,len(df))): 
    if df['A'].iloc[j-1]==df['A'].iloc[j] and pd.isnull(df['E'].iloc[j]): 
     df['E'].iloc[j] = fun(df['B'].iloc[j],df['B'].iloc[j],df['B'].iloc[j-1],df['B'].iloc[j-1]) 

兩個循環非常相似,但第二個循環是從最後一個元素循環到第一個數據幀。 我的代碼工作正常,結果應該是這樣的:

  # Before #       # After # 
    A B C D E   A B C  D  E 
0 1A 10 11 111 0  0 1A 10 11 111.0  0.0 
1 1A 15 56 0 222  1 1A 15 56  0.0 222.0 
2 3C 49 32 NaN NaN  2 3C 49 32 7374.5  NaN 
3 3C 75 78 NaN NaN  3 3C 75 78 5287.5 7387.5 
4 3C 35 45 NaN NaN  4 3C 35 45  NaN 5267.5 
5 7M 33 89 NaN NaN  5 7M 33 89 2986.5  NaN 
6 7M 45 15 NaN NaN  6 7M 45 15 5872.5 2992.5 
7 7M 65 14 NaN NaN  7 7M 65 14  NaN 5882.5 

你能夠改善這樣的代碼,以便在使用某些功能構建從熊貓庫使其更有效率?我想有一些更優雅的方式來實現我的結果。

注意:第一行和第二行已經值(111 00 222),因此它們不能被函數來計算!

+0

嘗試使用Series.diff – yuval

+0

@ user2476373感謝您的評論:)你能提供給我關於如何使用它更多的細節和爲什麼它是合適的對於我的問題? –

回答

0

爲了解決我定義的另一個函數,它接受作爲輸入fun

def fun2(df,s): 
    X= fun(df.B,df.C,df.B.shift(s),df.C.shift(s)) 
    return X 

DE可以填充像這樣我的問題:

df2['D']=np.where((df2.A.shift(-1)==df2.A) & (df2.D.isnull()==True),fun2(df2,-1),df2.D) 
df2['E']=np.where((df2.A.shift(1)==df2.A) & (df2.E.shift(1).isnull()==True),fun2(df2,+1),df2.E) 

注意:儘管更緊湊,這種方法可能會比較慢

1

你可以使用np.wheredataframe.shift()

  • np.where就像if語句
  • datafrmae.shift() - 換檔指數期間所需數量與可選的時間頻率

    df['D']=np.where(df.A.shift(-1)==df.A,func(df['B'],df['B'],df.B.shift(-1),df.B.shift(-1)),np.NaN) 
    
+0

感謝您的答案;那麼df ['E']呢? –

+0

我還注意到答案不正確,因爲第一行和第二行在字典(111 0,0 222)中定義了固定值......而你的答案正在修改結果 –

+0

我能修復你的答案但是df ['E']仍然丟失 –

1

您可以先按A的值進行分組,然後應用矢量化函數:

def fun(a,b,c,d): 
    out = a*c + b/2 + d*b 
    return out 

def apply_func(df): 
    mask = pd.isnull(df['D'][:-1]) 
    df['D'][:-1][mask] = fun(df['B'][:-1].values, df['B'][:-1].values, 
          df['B'][1:].values, df['B'][1:].values) 
    mask = pd.isnull(df['E'][1:]) 
    df['E'][1:][mask] = fun(df['B'][1:].values, df['B'][1:].values, 
          df['B'][:-1].values, df['B'][:-1].values) 
    return df 

然後:

df = df.groupby('A').apply(apply_func).reset_index(drop=True) 

    A B C  D  E 
0 1A 10 11 305.0  NaN 
1 1A 15 56  NaN 307.5 
2 3C 49 32 7374.5  NaN 
3 3C 75 78 5287.5 7387.5 
4 3C 35 45  NaN 5267.5 
5 7M 33 89 2986.5  NaN 
6 7M 45 15 5872.5 2992.5 
7 7M 65 14  NaN 5882.5 
+0

我還注意到答案是不正確的,因爲第一行和第二行在字典中定義了固定值(111 0,0 222)...而你的答案正在修改結果 –

+0

@FedericoGentile:看看你的示例DataFrame。列D和E只有NaN值。我看到「Before」和「After」DataFrame之間存在不協調,所以我只是將該函數應用於「Before」數據框。如果D列和E列具有已定義的值,則該函數不應影響它們。 – Jacquot

+0

感謝您指出:) –