Отфильтруйте первый элемент в списке, который соответствует критериям для каждой строки панд - PullRequest
1 голос
/ 09 октября 2019

Вопрос / проблема: Я хотел бы создать еще один столбец, который содержит первый столбец (из многих) / или значение в списке, который соответствует критериям (который должен отличаться от «nan»).

Я работаю над фреймом данных, который содержит несколько столбцов, которые служат в качестве флагов, каждый столбец представляет собой отдельный тип флага. Вот как это выглядит:

         id_number  createdat  ... flag_3.3.3.2.1 flag_3.3.3.2.2 flag_3.3.3.3.1
1             718v 2019-08-14  ...            nan      3.3.3.2.2      3.3.3.3.1
2             566m 2019-07-10  ...            nan            nan            nan
3             636p 2019-06-12  ...      3.3.3.2.1            nan      3.3.3.3.1
4             630r 2019-06-30  ...            nan            nan            nan
26815         066p 2019-08-24  ...      3.3.3.2.1      3.3.3.2.2      3.3.3.3.1
26816         769b 2019-08-10  ...            nan            nan            nan

Мне удалось создать столбец, который генерирует список всех значений столбцов, содержащих «флаг _»:

payday_cols = [col for col in df if col.startswith('flag_')]
df['flagging'] = df[payday_cols].values.tolist()
print(df)
         id_number  ... flag_3.3.3.3.1                                           flagging
1             718v  ...            nan  [nan, nan, nan, nan, nan, nan, nan, nan, nan, ...
2             566m  ...            nan  [nan, nan, nan, nan, nan, nan, nan, nan, nan, ...
3             636p  ...            nan  [nan, nan, 2.2, nan, nan, nan, nan, nan, nan, ...
4             630r  ...            nan  [nan, nan, nan, 3.1, nan, nan, nan, nan, 3.3.2...                                          ...
26815         066p  ...      3.3.3.3.1  [nan, nan, nan, nan, 3.2, nan, nan, nan, nan, ...
26816         769b  ...            nan  [1, nan, nan, nan, nan, nan, nan, nan, 3.3.2.1...

ЧтоМне не хватает способа создать последний столбец, который содержит первое значение списка, отличающееся от nan, или nan, если нет значения, отличного от nan. Вывод будет таким:

         id_number  ... flag_3.3.3.3.1                                           flagging      flag
1             718v  ...            nan  [nan, nan, nan, nan, nan, nan, nan, nan, nan, ...       nan
2             566m  ...            nan  [nan, nan, nan, nan, nan, nan, nan, nan, nan, ...       nan
3             636p  ...            nan  [nan, nan, 2.2, nan, nan, nan, nan, nan, nan, ...       2.2
4             630r  ...            nan  [nan, nan, nan, 3.1, nan, nan, nan, nan, 3.3.2...       3.1
26815         066p  ...      3.3.3.3.1  [nan, nan, nan, nan, 3.2, nan, nan, nan, nan, ...       3.2
26816         769b  ...            nan  [1, nan, nan, nan, nan, nan, nan, nan, 3.3.2.1...   3.3.2.1

Большое спасибо, и если вам понадобится, чтобы я сгенерировал значения, подобные этим, чтобы вы могли воссоздать этот случай, я отредактирую этот пост вместе с ним.

Ответы [ 3 ]

3 голосов
/ 09 октября 2019

Метод 1 :

Попробуйте bfill и .iloc

df[payday_cols].bfill(1).iloc[:,0]

Out[92]:
1        3.3.3.2.2
2              NaN
3        3.3.3.2.1
4              NaN
26815    3.3.3.2.1
26816          NaN
Name: flag_3.3.3.2.1, dtype: object

Метод 2 :

Другое решение - использовать numy argmax для notna и передать результат в lookup

m = df[payday_cols].notna().values.argmax(1)
df[payday_cols].lookup(df.index, np.array(payday_cols)[m])

Out[145]: array(['3.3.3.2.2', nan, '3.3.3.2.1', nan, '3.3.3.2.1', nan], dtype=object)

Примечание: вывод основан на этом примере

In [83]: df

Out[83]:
      id_number   createdat flag_3.3.3.2.1 flag_3.3.3.2.2 flag_3.3.3.3.1  
1          718v  2019-08-14            NaN      3.3.3.2.2      3.3.3.3.1
2          566m  2019-07-10            NaN            NaN            NaN
3          636p  2019-06-12      3.3.3.2.1            NaN      3.3.3.3.1
4          630r  2019-06-30            NaN            NaN            NaN
26815      066p  2019-08-24      3.3.3.2.1      3.3.3.2.2      3.3.3.3.1
26816      769b  2019-08-10            NaN            NaN            NaN
1 голос
/ 09 октября 2019

Мое решение:

  • Преобразовать столбец, содержащий списки, в DataFrame (применяя pd.Series к каждому элементу).
  • Примените к каждой строке функцию, основанную на first_valid_index .

Итак, давайте предположим, что df :

df = pd.DataFrame({ "flagging": [
    [np.nan, np.nan, np.nan, np.nan], [np.nan, 2.2, np.nan, 0.2],
    [np.nan, 1.1, np.nan, np.nan], [np.nan, np.nan, np.nan, 3.1]]})

Определите следующую функцию:

def func(x):
    ind = x.first_valid_index()
    return None if ind is None else x[ind]

Затем примените ее:

df.flagging.apply(pd.Series).apply(func, axis=1)
1 голос
/ 09 октября 2019

Это должно работать.

df = pd.DataFrame({
    "flagging": [[np.nan, np.nan, np.nan, np.nan], [np.nan, 2.2, np.nan, 0.2], [np.nan, 1.1, np.nan, np.nan], [np.nan, np.nan, np.nan, 3.1]]
})

def get_element(xs):
    xs = [x for x in xs if not pd.isna(x)]
    if xs:
        return xs[0]
    return np.nan

df["flagging"].apply(get_element)

Вывод:

0    NaN
1    2.2
2    1.1
3    3.1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...