Pandas dataframe fillna () apenas algumas colunas no lugar

144

Eu estou tentando preencher nenhum valor em um dataframe do Pandas com 0 para apenas alguns subconjuntos de colunas.

Quando eu faço:

import pandas as pd
df = pd.DataFrame(data={'a':[1,2,3,None],'b':[4,5,None,6],'c':[None,None,7,8]})
print df
df.fillna(value=0, inplace=True)
print df

A saída:

     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  NaN  7.0
3  NaN  6.0  8.0
     a    b    c
0  1.0  4.0  0.0
1  2.0  5.0  0.0
2  3.0  0.0  7.0
3  0.0  6.0  8.0

Ele substitui todos os Nonepor 0. O que eu quero fazer é substituir apenas Nones em colunas ae b, mas não c.

Qual a melhor maneira para fazer isto?

Sait
fonte

Respostas:

218

Você pode selecionar as colunas desejadas e fazê-lo por atribuição:

df[['a', 'b']] = df[['a','b']].fillna(value=0)

A saída resultante é como o esperado:

     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  0.0  7.0
3  0.0  6.0  8.0
raiz
fonte
Sim, é exatamente isso que eu quero! Obrigado. Alguma maneira de fazer isso no local? Meu dataframe original é bem grande.
Sait
1
Eu não acho que haja qualquer ganho de desempenho ao fazer isso no lugar enquanto você está substituindo o df orig qualquer maneira
EdChum
4
O loc é supérfluo aqui, df[['a', 'b']] = df[['a','b']].fillna(value=0)continuará a funcionar
EdChum
2
@ EdChum Não produz um quadro de dados temporário e, portanto, precisa de mais memória para fazer isso? (Eu estou mais preocupado com memória de complexidade de tempo.)
Sait
7
Para muitas operações, inplaceainda funcionará em uma cópia. Não sei se é o caso fillnaou não. Veja esta resposta de um dos principais desenvolvedores do pandas.
root
85

Você pode usar dict, fillnacom valor diferente para coluna diferente

df.fillna({'a':0,'b':0})
Out[829]: 
     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  0.0  7.0
3  0.0  6.0  8.0

Depois de atribuí-lo de volta

df=df.fillna({'a':0,'b':0})
df
Out[831]: 
     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  0.0  7.0
3  0.0  6.0  8.0
YOBEN_S
fonte
1
muito legal, Btw para o dict que você pode usar, fromkeysse quiser, +1
U10-Forward
1
A resposta / exemplo seria mais clara se realmente mostrasse valores diferentes para as diferentes colunas.
RufusVS
@RufusVS que é certo, mas ainda tentar igualar o op é esperado saída
YOBEN_S
1
Esta é a melhor solução que a resposta aceita, porque evita problemas encadeados de indexação, por exemplo, se usado comdf.fillna({'a':0,'b':0}, inplace=True)
Alex
19

Você pode evitar fazer uma cópia do objeto usando a solução de Wen e inplace = True:

df.fillna({'a':0, 'b':0}, inplace=True)
print(df)

Qual produz:

     a    b    c
0  1.0  4.0  NaN
1  2.0  5.0  NaN
2  3.0  0.0  7.0
3  0.0  6.0  8.0
Leesa H.
fonte
1
Enquanto isso estiver correto, evitando uma cópia não é necessariamente melhor .
jpp
7

Veja como você pode fazer tudo em uma linha:

df[['a', 'b']].fillna(value=0, inplace=True)

Divisão: df[['a', 'b']]seleciona as colunas nas quais você deseja preencher os valores de NaN, value=0diz para ele preencher os NaNs com zero e inplace=Truetornará as alterações permanentes, sem a necessidade de fazer uma cópia do objeto.

Josephine M. Ho
fonte
7

o uso da resposta superior gera um aviso sobre como fazer alterações em uma cópia de uma fatia df. Supondo que você tenha outras colunas, a melhor maneira de fazer isso é passar um dicionário:
df.fillna({'A': 'NA', 'B': 'NA'}, inplace=True)

Jonathan
fonte
3

Ou algo como:

df.loc[df['a'].isnull(),'a']=0
df.loc[df['b'].isnull(),'b']=0

e se houver mais:

for i in your_list:
    df.loc[df[i].isnull(),i]=0
Sub-10
fonte
0

Às vezes, essa sintaxe não funciona:

df[['col1','col2']] = df[['col1','col2']].fillna()

Use o seguinte:

df['col1','col2']
Sarath Baby
fonte