Як передати інший цілий стовпець як аргумент pandas fillna ()


95

Я хотів би заповнити відсутні значення в одному стовпці значеннями з іншого стовпця, використовуючи 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

Відповіді:


174

Ви можете надати цей стовпець 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 дуже корисна.
Вертикаль,

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), ).
Кайсар,

Ви хочете зазначити, що це просто переосмислення вбудованих панд pd.DataFrame.fillna(). І я підозрюю, що поведінка кутових випадків може відрізнятися, наприклад, для невідповідної довжини рядів з різних кадрів даних: dfA ['Cat1'], dfB ['Cat2']
smci

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

Дякую за відповідь! Що змінює використання значення, а не методу, описаного joris?
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)

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

Сподіваюся, це комусь корисно!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.