Como passar outra coluna inteira como argumento para pandas fillna ()


99

Gostaria de preencher os valores ausentes em uma coluna com valores de outra coluna, usando o fillnamétodo.

(Li que repetir cada linha seria uma prática muito ruim e que seria melhor fazer tudo de uma vez, mas não consegui descobrir como fazer isso fillna.)

Dados anteriores:

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

Dados depois de:

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

Respostas:


182

Você pode fornecer esta coluna para fillna(veja os documentos ), ela usará esses valores em índices correspondentes para preencher:

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

8
Agradável! Não sabia que fillnaleva uma série.
— Ami Tavory

1
Obrigado! Achei que a série tinha que ter o tamanho exato do número de valores de NA.
— xav

Ele também funciona para dataframes de linhas multicolunares. Esse recurso de fillna é muito útil.
— Wertikal

Eu tenho que dizer que amo isso!
— Taylrl

22

Você poderia fazer

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

A construção geral do RHS usa o padrão ternário do pandaslivro de receitas (que vale a pena ler em qualquer caso). É uma versão vetorial de a? b: c.


Não é a solução que usei para este problema, mas um padrão muito interessante! Obrigado!
— xav

existe uma maneira de usar isso para várias colunas? por exemplo, se este df tivesse cat1, cat2, cat3, cat4, cat5 e digamos que cat5 estivesse vazio. haveria uma maneira de preencher cat5 com valores de cat1 se cat1 vazio, em seguida, cat2, se cat2 vazio, em seguida, cat3 etc.?
— user8322222

@ user8322222 Estou definitivamente atrasado, mas se alguém estiver tendo essa dúvida, você pode fazer np.where aninhado, assim como faria no excel cell = np.where (cond, val_true, np.where (cond, val_true, val_false), )
— Kaisar

Você quer mencionar que isso está apenas redefinindo os pandas embutidos pd.DataFrame.fillna(). E eu suspeito que o comportamento do caso extremo pode ser diferente, por exemplo, para comprimentos de série incompatíveis de diferentes dataframes: dfA ['Cat1'], dfB ['Cat2']
— smci

9

Basta usar o valueparâmetro em vez de 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

Obrigado pela resposta! O que muda para usar valor em vez do método descrito por joris?
— xav

@xav valueé o primeiro parâmetro, então joris está realmente fazendo exatamente a mesma coisa. Como ele disse, veja os docs .
— chrisaycock

Sim, a docstring é um pouco enganosa, pois methodestá listada primeiro.
— joris

7

pandas.DataFrame.combine_first também funciona.

( Atenção: como "As colunas do índice de resultado serão a união dos respectivos índices e colunas", você deve verificar se o índice e as colunas são correspondidos. )

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

Compare com outras respostas:

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

Não usei este método abaixo:

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)

porque levantará uma exceção:

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

o que significa que np.isnan pode ser aplicado a arrays NumPy de dtype nativo (como np.float64), mas aumenta TypeError quando aplicado a arrays de objetos .

Então, eu reviso o método:

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

Aqui está uma abordagem mais geral (o método fillna é provavelmente melhor)

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

Sei que essa é uma pergunta antiga, mas recentemente precisei fazer algo semelhante. Consegui usar o seguinte:

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)

O que produz:

  Cat1
0  cat
1  dog
2  cat
3  ant

Espero que isto ajude alguém!

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.