Wie man eine weitere ganze Spalte als Argument an pandas fillna () übergibt


88

Ich möchte fehlende Werte in einer Spalte mit fillnaMethoden aus einer anderen Spalte füllen .

(Ich habe gelesen, dass das Durchlaufen jeder Zeile eine sehr schlechte Übung wäre und dass es besser wäre, alles auf einmal zu machen, aber ich konnte nicht herausfinden, wie ich es machen soll fillna.)

Daten vor:

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

Daten nach:

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

Antworten:


165

Sie können diese Spalte bereitstellen fillna(siehe Dokumente ). Sie verwendet diese Werte für übereinstimmende Indizes, um Folgendes auszufüllen:

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

6
Nett! Ich wusste nicht, dass fillnadas eine Serie braucht.
Ami Tavory

Vielen Dank! Ich dachte, die Serie muss genau die Größe der Anzahl der NA-Werte haben.
Xav

Es funktioniert auch für Datenrahmen für mehrspaltige Zeilen. Diese Funktion von fillna ist sehr hilfreich.
Wertikal

18

Du könntest es tun

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

Das Gesamtkonstrukt auf der RHS verwendet das ternäre Muster aus dem pandasKochbuch (das es sich in jedem Fall lohnt , es zu lesen). Es ist eine Vektorversion von a? b: c.


Nicht die Lösung, die ich für dieses Problem verwendet habe, aber ein sehr interessantes Muster! Vielen Dank!
Xav

Gibt es eine Möglichkeit, dies für mehrere Spalten zu verwenden? zB wenn dieser df cat1, cat2, cat3, cat4, cat5 hatte und sagen wir, cat5 war leer. Gibt es eine Möglichkeit, cat5 mit Werten von cat1 zu füllen, wenn cat1 leer ist, dann cat2, wenn cat2 leer ist, dann cat3 usw.?
user8322222

@ user8322222 Ich bin definitiv zu spät, aber wenn jemand diese Frage hat, können Sie np.where verschachteln, genau wie in Excel cell = np.where (cond, val_true, np.where (cond, val_true, val_false), ).
Kaisar

Sie möchten erwähnen, dass dies nur die eingebauten Pandas neu definiert pd.DataFrame.fillna(). Und ich vermute, dass sich das Verhalten in Eckfällen unterscheiden kann, z. B. bei nicht übereinstimmenden Serienlängen aus verschiedenen Datenrahmen: dfA ['Cat1'], dfB ['Cat2']
smci

8

Verwenden Sie einfach den valueParameter anstelle von 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

Danke für die Antwort! Was ändert es, Wert anstelle der von joris beschriebenen Methode zu verwenden?
Xav

@xav valueist der erste Parameter, also macht joris genau das Gleiche. Wie er sagte, siehe die Dokumente .
Chrisaycock

Ja, die Dokumentzeichenfolge ist etwas irreführend, wie methoddort zuerst aufgeführt.
Joris

7

pandas.DataFrame.combine_first funktioniert auch.

( Achtung: Da "Ergebnisindexspalten die Vereinigung der jeweiligen Indizes und Spalten darstellen", sollten Sie überprüfen, ob der Index und die Spalten übereinstimmen. )

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

Vergleichen Sie mit anderen Antworten:

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

Ich habe diese Methode unten nicht angewendet:

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)

weil es eine Ausnahme auslösen wird:

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

Dies bedeutet, dass np.isnan auf NumPy-Arrays vom nativen Typ (wie z. B. np.float64) angewendet werden kann, aber TypeError auslöst, wenn es auf Objektarrays angewendet wird .

Also überarbeite ich die Methode:

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

Hier ist ein allgemeinerer Ansatz (Fillna-Methode ist wahrscheinlich besser)

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

Ich weiß, dass dies eine alte Frage ist, aber ich musste in letzter Zeit etwas Ähnliches tun. Ich konnte Folgendes verwenden:

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)

Welche Ausbeuten:

  Cat1
0  cat
1  dog
2  cat
3  ant

Hoffe das ist hilfreich für jemanden!

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.