2016-12-11 3 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) 

Простой dataframe, чтобы помочь мне объяснить:Возврат первое совпадающее значение/имя столбца в новом dataframe

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

Желаемая выход:

Что я хотел бы получить новый dataframe с первым значением матча в столбце «Значение» и другой колонке под названием «От Col», который захватывает это имя столбца.

Если совпадение не видно, то вывод из последнего столбца (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

Спасибо 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 и заполнить недостающие значения в Из Col с этим из его фамилия столбца.

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

Я не работаю с пандами, так что это можно рассматривать только в качестве сноски, но в чистом питоне есть также возможность найти первый индекс не- None с использованием reduce.

>>> 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 
Смежные вопросы