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

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

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.


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

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)

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)

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!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.