Как передать еще один столбец целиком в качестве аргумента в pandas fillna ()

94

Я хотел бы заполнить недостающие значения в одном столбце значениями из другого столбца, используя fillnaметод.

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

Данные до:

Day  Cat1  Cat2
1    cat   mouse
2    dog   elephant
3    cat   giraf
4    NaN   ant

Данные после:

Day  Cat1  Cat2
1    cat   mouse
2    dog   elephant
3    cat   giraf
4    ant   ant
xav
источник

Ответы:

173

Вы можете предоставить этот столбец fillna(см. Документацию ), он будет использовать эти значения в соответствующих индексах для заполнения:

In [17]: df['Cat1'].fillna(df['Cat2'])
Out[17]:
0    cat
1    dog
2    cat
3    ant
Name: Cat1, dtype: object
Йорис
источник
7
Ницца! Я не знал, что fillnaснимает серию.
Ами Тавори
1
Благодарность! Я думал, что серия должна точно соответствовать количеству значений NA.
xav
Это также работает для фреймов данных для многоколоночных строк. Эта особенность fillna очень помогает.
Wertikal
19

Ты мог бы сделать

df.Cat1 = np.where(df.Cat1.isnull(), df.Cat2, df.Cat1)

Общая конструкция на RHS использует троичный шаблон из pandasповаренной книги (который стоит прочитать в любом случае). Это векторная версия a? b: c.

Ами Тавори
источник
Не то решение, которое я использовал для этой проблемы, но очень интересный паттерн! Благодарность!
xav
есть ли способ использовать это для нескольких столбцов? например, если в этом df были cat1, cat2, cat3, cat4, cat5 и, скажем, cat5 был пуст. есть ли способ заполнить cat5 значениями из cat1, если cat1 пустой, затем cat2, если cat2 пустой, то cat3 и т. д.?
user8322222
@ user8322222 Я определенно опаздываю, но если у кого-то возникнет этот вопрос, вы можете использовать вложенный np.where, как и в excel cell = np.where (cond, val_true, np.where (cond, val_true, val_false), ).
Кайсар
Вы хотите упомянуть, что это просто переопределение встроенных pandas pd.DataFrame.fillna(). И я подозреваю, что поведение в крайнем случае может отличаться, например, для несовпадающих длин серий из разных фреймов данных: dfA ['Cat1'], dfB ['Cat2']
smci 08
8

Просто используйте valueпараметр вместо method:

In [20]: df
Out[20]:
  Cat1      Cat2  Day
0  cat     mouse    1
1  dog  elephant    2
2  cat     giraf    3
3  NaN       ant    4

In [21]: df.Cat1 = df.Cat1.fillna(value=df.Cat2)

In [22]: df
Out[22]:
  Cat1      Cat2  Day
0  cat     mouse    1
1  dog  elephant    2
2  cat     giraf    3
3  ant       ant    4
Chrisaycock
источник
Спасибо за ответ! Что меняет использование ценности вместо метода, описанного йорисом?
xav
@xav value- это первый параметр, поэтому joris на самом деле делает то же самое. По его словам, см. Док .
chrisaycock
Да, строка документации немного вводит в заблуждение, так как methodона указана первой.
joris
7

pandas.DataFrame.combine_first также работает.

( Внимание: поскольку «Столбцы индекса результата будут объединением соответствующих индексов и столбцов», вы должны проверить соответствие индекса и столбцов. )

import numpy as np
import pandas as pd
df = pd.DataFrame([["1","cat","mouse"],
    ["2","dog","elephant"],
    ["3","cat","giraf"],
    ["4",np.nan,"ant"]],columns=["Day","Cat1","Cat2"])

In: df["Cat1"].combine_first(df["Cat2"])
Out: 
0    cat
1    dog
2    cat
3    ant
Name: Cat1, dtype: object

Сравните с другими ответами:

%timeit df["Cat1"].combine_first(df["Cat2"])
181 µs ± 11.3 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

%timeit df['Cat1'].fillna(df['Cat2'])
253 µs ± 10.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit np.where(df.Cat1.isnull(), df.Cat2, df.Cat1)
88.1 µs ± 793 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Я не использовал этот метод ниже:

def is_missing(Cat1,Cat2):    
    if np.isnan(Cat1):        
        return Cat2
    else:
        return Cat1

df['Cat1'] = df.apply(lambda x: is_missing(x['Cat1'],x['Cat2']),axis=1)

потому что это вызовет исключение:

TypeError: ("ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''", 'occurred at index 0')

Это означает, что np.isnan может применяться к массивам NumPy с собственным dtype (например, np.float64), но вызывает TypeError при применении к массивам объектов .

Поэтому я пересматриваю метод:

def is_missing(Cat1,Cat2):    
    if pd.isnull(Cat1):        
        return Cat2
    else:
        return Cat1

%timeit df.apply(lambda x: is_missing(x['Cat1'],x['Cat2']),axis=1)
701 µs ± 7.38 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
Джереми Z
источник
0

Вот более общий подход (вероятно, лучше использовать метод fillna)

def is_missing(Cat1,Cat2):    
    if np.isnan(Cat1):        
        return Cat2
    else:
        return Cat1

df['Cat1'] = df.apply(lambda x: is_missing(x['Cat1'],x['Cat2']),axis=1)
воробей
источник
0

Я знаю, что это старый вопрос, но недавно мне понадобилось сделать что-то подобное. Мне удалось использовать следующее:

df = pd.DataFrame([["1","cat","mouse"],
    ["2","dog","elephant"],
    ["3","cat","giraf"],
    ["4",np.nan,"ant"]],columns=["Day","Cat1","Cat2"])

print(df)

  Day Cat1      Cat2
0   1  cat     mouse
1   2  dog  elephant
2   3  cat     giraf
3   4  NaN       ant

df1 = df.bfill(axis=1).iloc[:, 1]
df1 = df1.to_frame()
print(df1)

Что дает:

  Cat1
0  cat
1  dog
2  cat
3  ant

Надеюсь, это кому-то поможет!

Джефф Колдплюм
источник