2013-08-30 44 views
2

我有一個數據框,包含多個'actions'列。我如何找到匹配模式的最後一個動作並返回它的列索引或標籤?查找每行中的最後一列匹配模式

我的數據:

name action_1 action_2 action_3 
bill referred referred  
bob  introduced referred referred 
mary introduced  
june introduced referred  
dale referred   
donna introduced 

我想要什麼:

name action_1 action_2 action_3 last_referred 
bill referred referred    action_2 
bob  introduced referred referred action_3 
mary introduced       NA 
june introduced referred    action_2 
dale referred       action_1 
donna introduced       NA 

回答

2

只需使用沿着axis=1apply功能並通過pattern參數作爲額外的參數傳遞給函數。

In [3]: def func(row, pattern): 
      referrer = np.nan 
      for key in row.index: 
       if row[key] == pattern: 
        referrer = key 
      return referrer 
     df['last_referred'] = df.apply(func, pattern='referred', axis=1) 
     df 
Out[3]:  name action_1 action_2 action_3 last_referred 
     0 bill referred referred  None  action_2 
     1 bob introduced referred referred  action_3 
     2 mary introduced        NaN 
     3 june introduced referred    action_2 
     4 dale referred       action_1 
     5 donna introduced        NaN 
+0

我想你可以用幾種不同的方式做矢量化 – Jeff

+0

我很欣賞@ecatmur答案的速度,但我不明白。我沒有使用一個巨大的數據集(應該在我的原始問題中注意到這一點),所以我很欣賞這裏更直接的方法。 – bjornarneson

+0

如果你評估@ ecatmur的答案,你會很快把它記住,它只是寫得太簡單了。 –

1

您可以pandas.meltgroupby做到這一點:

In [123]: molten = pd.melt(df, id_vars='name', var_name='last_referred') 

In [124]: molten 
Out[124]: 
    name last_referred  value 
0 bill  action_1 referred 
1  bob  action_1 introduced 
2 mary  action_1 introduced 
3 june  action_1 introduced 
4 dale  action_1 referred 
5 donna  action_1 introduced 
6 bill  action_2 referred 
7  bob  action_2 referred 
8 mary  action_2   NaN 
9 june  action_2 referred 
10 dale  action_2   NaN 
11 donna  action_2   NaN 
12 bill  action_3   NaN 
13 bob  action_3 referred 
14 mary  action_3   NaN 
15 june  action_3   NaN 
16 dale  action_3   NaN 
17 donna  action_3   NaN 

In [125]: gb = molten.groupby('name') 

In [126]: col = gb.apply(lambda x: x[x.value == 'referred'].tail(1)).last_referred 

In [127]: col.index = col.index.droplevel(1) 

In [128]: col 
Out[128]: 
name 
bill action_2 
bob  action_3 
dale action_1 
june action_2 
Name: last_referred, dtype: object 

In [129]: newdf = df.join(col, on='name') 

In [130]: newdf 
Out[130]: 
    name action_1 action_2 action_3 last_referred 
0 bill referred referred  NaN  action_2 
1 bob introduced referred referred  action_3 
2 mary introduced  NaN  NaN   NaN 
3 june introduced referred  NaN  action_2 
4 dale referred  NaN  NaN  action_1 
5 donna introduced  NaN  NaN   NaN 
+0

我知道你會'融化'我的想法:) –

+0

一旦我開始瞭解'熔化',我用了很多!這是一個相當大的錘子:) –

+0

像regexp;)我同意,我只是總是給OP最簡單,可預測的速度解決方案,並且將異國情調給你:)'apply'應該總是'O(N) 「如果我沒有錯。我甚至不知道如何計算'groupby'的'熔化'行爲? 'O(?)' –

0

您還可以使用idxmax,它返回最大值的第一指標,否則第一個索引。這確實需要添加額外的「NA」列,所以它有點混亂。

revcols = df.columns.values.tolist() 
revcols.reverse() 
tmpdf = df=='referred' 
tmpdf['NA'] = False 
lastrefer = tmpdf[['NA']+revcols].idxmax(axis=1) 
2

矢量化方法,使用arange找到最後一個索引,max,並串聯:

df['last_referred'] = np.r_[[np.NaN], df.columns][ 
     ((df == 'referred') * (np.arange(df.shape[1]) + 1)).max(axis=1).values] 

說明:

我們希望找到的每一行最右邊的單元,其具有值'referred'

>>> df == 'referred' 
    name action_1 action_2 action_3 
0 False  True  True False 
1 False False  True  True 
2 False False False False 
3 False False  True False 
4 False  True False False 
5 False False False False 

一個選項是DataFrame.idxmax,但是這給出了第一個(即,最左邊)發生。但是,假設我們可以用它們的列索引替換True值,我們可以使用正常的max

>>> np.arange(df.shape[1]) 
array([0, 1, 2, 3]) 
>>> (df == 'referred') * np.arange(df.shape[1]) 
    name action_1 action_2 action_3 
0  0   1   2   0 
1  0   0   2   3 
2  0   0   0   0 
3  0   0   2   0 
4  0   1   0   0 
5  0   0   0   0 
>>> ((df == 'referred') * np.arange(df.shape[1])).max(axis=1) 
0 2 
1 3 
2 0 
3 2 
4 1 
5 0 
dtype: int32 

一個問題,雖然:由於True1False0,我們可以通過與整數範圍[0, 1, 2, ...]廣播垂直乘以做到這一點,我們不能告訴'referred'之間的區別在「名稱」列並沒有發生。輕鬆修復;剛剛從1日開始的整數範圍:

>>> ((df == 'referred') * (np.arange(df.shape[1]) + 1)).max(axis=1) 
0 3 
1 4 
2 0 
3 3 
4 2 
5 0 
dtype: int32 

現在只要使用這個數組索引到列名:

>>> df.columns[((df == 'referred') * (np.arange(df.shape[1]) + 1)).max(axis=1).values] 
IndexError: index 4 is out of bounds for size 4 

糟糕!我們需要使0作爲NaN出現,其餘列轉移。我們可以使用np.r_,其串接陣列做到這一點:

>>> np.r_[[np.NaN], df.columns] 
array([nan, 'name', 'action_1', 'action_2', 'action_3'], dtype=object) 
>>> np.r_[[np.NaN], df.columns][ 
     ((df == 'referred') * (np.arange(df.shape[1]) + 1)).max(axis=1).values] 
array(['action_2', 'action_3', nan, 'action_2', 'action_1', nan], dtype=object) 

有你有它。

+0

這絕對是最快的選擇:)如果你能理解它:D對於OP來說增加一些解釋會很棒。 –

+0

+1不錯。僅供參考在熊貓0.12中,您必須訪問'[]'內的'values'。 –

+0

我真的想用cumsum,但這很好! – Jeff

相關問題