Jak przekazać kolejną całą kolumnę jako argument do pandy fillna ()

99

Chciałbym uzupełnić brakujące wartości w jednej kolumnie wartościami z innej kolumny, używając fillnametody.

(Czytałem, że zapętlanie każdego wiersza byłoby bardzo złą praktyką i że lepiej byłoby zrobić wszystko za jednym razem, ale nie mogłem się dowiedzieć, jak to zrobić fillna.)

Dane przed:

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

Dane po:

Day  Cat1  Cat2
1    cat   mouse
2    dog   elephant
3    cat   giraf
4    ant   ant
xav
źródło

Odpowiedzi:

182

Możesz podać tę kolumnę do fillna(zobacz dokumentację ), użyje ona tych wartości w pasujących indeksach do wypełnienia:

In [17]: df['Cat1'].fillna(df['Cat2'])
Out[17]:
0    cat
1    dog
2    cat
3    ant
Name: Cat1, dtype: object
joris
źródło
8
Miły! Nie wiedziałem, że fillnatrwa seria.
Ami Tavory
1
Dzięki! Pomyślałem, że seria musi mieć dokładną wielkość liczby wartości NA.
xav
Działa również dla ramek danych dla wierszy wielokolumnowych. Ta cecha fillny jest bardzo pomocna.
Wertikal
Muszę powiedzieć, że to mi się podoba!
Taylrl
22

Mógłbyś

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

Ogólna konstrukcja na RHS wykorzystuje trójskładnikowy wzorzec z pandasksiążki kucharskiej (którą warto przeczytać w każdym przypadku). To wersja wektorowa a? b: c.

Ami Tavory
źródło
Nie rozwiązanie, którego użyłem do tego problemu, ale bardzo ciekawy wzór! Dzięki!
xav
czy istnieje sposób użycia tego dla wielu kolumn? np. jeśli ten plik df miał cat1, cat2, cat3, cat4, cat5 i powiedzmy, że cat5 jest pusty. czy byłby sposób na wypełnienie cat5 wartościami z cat1, jeśli cat1 jest pusty, a następnie cat2, jeśli cat2 jest pusty, to cat3 itd.?
user8322222
@ user8322222 Zdecydowanie spóźniłem się, ale jeśli ktoś ma to pytanie, możesz zrobić zagnieżdżone np.where, tak jak w excel cell = np.where (cond, val_true, np.where (cond, val_true, val_false), ).
Kaisar
Chcesz wspomnieć, że to tylko przedefiniowanie wbudowanej pandy pd.DataFrame.fillna(). I podejrzewam, że zachowanie w narożniku może się różnić, np. Dla niedopasowanych długości serii z różnych ramek danych: dfA ['Cat1'], dfB ['Cat2']
smci
9

Po prostu użyj valueparametru zamiast 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
źródło
Dziękuję za odpowiedź! Co się zmienia w używaniu wartości zamiast metody opisanej przez jorisa?
xav
@xav valueto pierwszy parametr, więc joris robi dokładnie to samo. Jak powiedział, zobacz dokumentację .
chrisaycock
Tak, ciąg dokumentacyjny jest nieco mylący, ponieważ methodjest tam wymieniony jako pierwszy.
joris
7

pandas.DataFrame.combine_first również działa.

( Uwaga: ponieważ „kolumny indeksu wyników będą sumą odpowiednich indeksów i kolumn”, należy sprawdzić, czy indeks i kolumny są dopasowane ).

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

Porównaj z innymi odpowiedziami:

%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)

Nie użyłem tej metody poniżej:

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)

ponieważ spowoduje to wyjątek:

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')

co oznacza, że ​​np.isnan można zastosować do tablic NumPy o rodzimym typie dtype (np.float64), ale wywołuje TypeError po zastosowaniu do tablic obiektów .

Więc poprawiam metodę:

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)
Jeremy Z
źródło
0

Oto bardziej ogólne podejście (prawdopodobnie lepsza jest metoda 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)
wróbel
źródło
0

Wiem, że to stare pytanie, ale ostatnio miałem potrzebę zrobienia czegoś podobnego. Udało mi się skorzystać z:

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)

Co daje:

  Cat1
0  cat
1  dog
2  cat
3  ant

Mam nadzieję, że to komuś pomoże!

Jeff Coldplume
źródło