2016-12-11 127 views
3
import pandas as pd 
import numpy as np 
rng = pd.date_range('1/1/2011', periods=6, freq='H') 
df = pd.DataFrame({'A': [0, 1, 2, 3, 4,5], 
        'B': [0, 1, 2, 3, 4,5], 
        'C': [0, 1, 2, 3, 4,5], 
        'D': [0, 1, 2, 3, 4,5], 
        'E': [1, 2, 3, 3, 7,6], 
        'F': [1, 1, 3, 3, 7,6], 
        'G': [0, 0, 1, 0, 0,0] 

        }, 
       index=rng) 

一個簡單的數據幀幫我解釋一下:在新的數據幀返回第一個匹配值/列名

df 


        A B C D E F G 
2011-01-01 00:00:00 0 0 0 0 1 1 0 
2011-01-01 01:00:00 1 1 1 1 2 1 0 
2011-01-01 02:00:00 2 2 2 2 3 3 1 
2011-01-01 03:00:00 3 3 3 3 3 3 0 
2011-01-01 04:00:00 4 4 4 4 7 7 0 
2011-01-01 05:00:00 5 5 5 5 6 6 0 

當我篩選的值大於2,我得到以下的輸出:

df[df >= 2] 

        A B C D E F G 
2011-01-01 00:00:00 NaN NaN NaN NaN NaN NaN NaN 
2011-01-01 01:00:00 NaN NaN NaN NaN 2.0 NaN NaN 
2011-01-01 02:00:00 2.0 2.0 2.0 2.0 3.0 3.0 NaN 
2011-01-01 03:00:00 3.0 3.0 3.0 3.0 3.0 3.0 NaN 
2011-01-01 04:00:00 4.0 4.0 4.0 4.0 7.0 7.0 NaN 
2011-01-01 05:00:00 5.0 5.0 5.0 5.0 6.0 6.0 NaN 

對於每一行我想知道哪一列首先有匹配值(從左到右)。所以在2011-01-01 01:00:00的行上,它是E行,值爲2.0。

enter image description here

所需的輸出:

我想獲得一個新的數據框在一個名爲「價值」列中的第一個匹配值,另一列名爲「從上校」捕獲列名是從哪裏來的。

如果看不到匹配,則從最後一列輸出(本例中爲G)。謝謝你的幫助。

     "Value" "From Col" 
    2011-01-01 00:00:00 NaN G 
    2011-01-01 01:00:00 2 E 
    2011-01-01 02:00:00 2 A 
    2011-01-01 03:00:00 3 A 
    2011-01-01 04:00:00 4 A 
    2011-01-01 05:00:00 5 A 

回答

2

試試這個:

def get_first_valid(ser): 
    if len(ser) == 0: 
     return pd.Series([np.nan,np.nan]) 

    mask = pd.isnull(ser.values) 
    i = mask.argmin() 
    if mask[i]: 
     return pd.Series([np.nan, ser.index[-1]]) 
    else: 
     return pd.Series([ser[i], ser.index[i]]) 


In [113]: df[df >= 2].apply(get_first_valid, axis=1) 
Out[113]: 
         0 1 
2011-01-01 00:00:00 NaN G 
2011-01-01 01:00:00 2.0 E 
2011-01-01 02:00:00 2.0 A 
2011-01-01 03:00:00 3.0 A 
2011-01-01 04:00:00 4.0 A 
2011-01-01 05:00:00 5.0 A 

或:

In [114]: df[df >= 2].T.apply(get_first_valid).T 
Out[114]: 
         0 1 
2011-01-01 00:00:00 NaN G 
2011-01-01 01:00:00 2 E 
2011-01-01 02:00:00 2 A 
2011-01-01 03:00:00 3 A 
2011-01-01 04:00:00 4 A 
2011-01-01 05:00:00 5 A 

PS我採取了Series.first_valid_index()功能的源代碼,並做了一個骯髒的黑客出來吧......

說明:

In [221]: ser = pd.Series([np.nan, np.nan, 5, 7, np.nan]) 

In [222]: ser 
Out[222]: 
0 NaN 
1 NaN 
2 5.0 
3 7.0 
4 NaN 
dtype: float64 

In [223]: mask = pd.isnull(ser.values) 

In [224]: mask 
Out[224]: array([ True, True, False, False, True], dtype=bool) 

In [225]: i = mask.argmin() 

In [226]: i 
Out[226]: 2 

In [227]: ser.index[i] 
Out[227]: 2 

In [228]: ser[i] 
Out[228]: 5.0 
+0

Thanks maxu!完美的作品。所以我試圖理解這一點,但掙扎。掩碼查找缺少的值。然後該函數查找掩碼的argmin,以便嘗試查找任何NaN的索引? – ade1e

+1

@adele,很高興我能幫上忙。我已經添加了解釋部分 - 請檢查... – MaxU

2

首先,根據標準篩選值並刪除包含所有NaNs的行。然後,使用idxmax返回True條件的第一次出現。這類似於我們的第一個系列。

要創建第二個系列中,遍歷所述第一系列(索引,值)元組對,同時追加存在於原始DF這些位置。

ser1 = (df[df.ge(2)].dropna(how='all').ge(2)).idxmax(1) 
ser2 = pd.concat([pd.Series(df.loc[i,r], pd.Index([i])) for i, r in ser1.iteritems()]) 

創建一個新的DF,其索引屬於原來DF,並與它填補遺漏值在從山口的最後列名。

req_df = pd.DataFrame({"From Col": ser1, "Value": ser2}, index=df.index) 
req_df['From Col'].fillna(df.columns[-1], inplace=True) 
req_df 

enter image description here

+1

非常好,謝謝。我標記了答案 – ade1e

0

我不跟大熊貓工作,所以這可以被認爲只是作爲一個註腳,但在純Python也有可能使用reduce找到第一個非None指數。

>>> a 
[None, None, None, None, 6, None, None, None, 3, None] 

>>> print(reduce(lambda x, y: (x or y[1] and y[0]), enumerate(a), None)) 
4 
相關問題