Pandas数据框fillna()只在某些列中原地填充。

274
我试图将 Pandas 数据帧中部分列的空值填充为 0。 当我执行以下操作时:
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    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

它将每个None替换为0。我的要求是,只替换ab列中的None,而不替换c列的None

如何最好地实现这一点?


如果更多的pandas方法也有inplace、include和exclude(列的子集),那就太好了。对于正则表达式也是如此。 - undefined
10个回答

408

您可以通过赋值选择所需的列:

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

生成的输出符合预期:

     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

3
好的,这正是我想要的!谢谢。有没有在原地进行此操作的方法?我的原始数据框相当大。 - Sait
3
我认为这样就地进行操作并没有任何性能提升,因为您无论如何都会覆盖原始数据框。 - EdChum
7
这里的loc是多余的,df[['a', 'b']] = df[['a', 'b']].fillna(value=0)仍然可以正常工作。 - EdChum
3
它不会产生一个临时数据框,因此需要更多的内存来完成操作吗?(我更关心内存而不是时间复杂度。) - Sait
10
对于许多操作, inplace 仍将在副本上运行。 我不知道 fillna 是否是这种情况。 请参见来自pandas核心开发人员的此回答 - root
显示剩余4条评论

200
您可以使用dictfillna在不同的列中填充不同的值。
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

分配回去之后

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

2
非常酷!顺便说一下,如果你想的话,你可以使用fromkeys来创建字典。+1 - U13-Forward
1
如果实际上显示不同列的不同值,答案/示例将更清晰。 - RufusVS
@RufusVS 是的,但仍然要尝试匹配原帖作者的期望输出。 - BENY
4
这是比已被接受的答案更好的解决方案,因为它避免了链式索引问题,例如,如果与df.fillna({'a':0,'b':0}, inplace=True)一起使用。 - Alex
3
如何在字典中使用 ffillbfill 等方法? - shaik moeed

52

你可以使用 Wen 的解决方案并设置 inplace=True 来避免复制对象:

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

其结果为:

     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

7
虽然这是正确的,但避免复制并不一定更好。 - jpp

19

使用顶部答案会产生关于对df切片副本进行更改的警告。 假设您有其他列,更好的方法是传递一个字典:
df.fillna({'A': 'NA', 'B': 'NA'}, inplace=True)


12

这应该可以正常工作,而且没有版权警告

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

9

以下是一行代码实现以上操作的方法:

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

细节解析: df[['a', 'b']] 选择你想要填充NaN值的列,value=0 告诉它用零来填充NaN,inplace=True 将使更改永久生效,无需复制对象。


6
这似乎会引发"SettingWithCopyWarning"警告,并且更改未在“df”中反映出来。 - Michael
有没有一种方法可以在第n列右侧的每一列上使用fillna(0)函数? - Arthur D. Howland

5

或类似于:

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

如果还有更多内容:

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

5

由于某种奇怪的原因,这并没有起作用(使用 Pandas:'0.25.1')

df[['col1', 'col2']].fillna(value=0, inplace=True)

另一种解决方案:

subset_cols = ['col1','col2']
[df[col].fillna(0, inplace=True) for col in subset_cols]

示例:

df = pd.DataFrame(data={'col1':[1,2,np.nan,], 'col2':[1,np.nan,3], 'col3':[np.nan,2,3]})

输出:

   col1  col2  col3
0  1.00  1.00   nan
1  2.00   nan  2.00
2   nan  3.00  3.00

使用列表推导式来填充fillna值:

subset_cols = ['col1','col2']
[df[col].fillna(0, inplace=True) for col in subset_cols]

输出:

   col1  col2  col3
0  1.00  1.00   nan
1  2.00  0.00  2.00
2  0.00  3.00  3.00

我认为inplace不是一个好的实践方式,请查看这个这个 - jezrael
所以在我看来,最好的做法是先发出“inplace”警告,然后从pandas中删除它。 - jezrael
如此简单的建议 - 总是避免原地操作,这里永远不会出现这样的问题 ;) - jezrael

0
有时候这个语法不起作用:
df[['col1','col2']] = df[['col1','col2']].fillna()

请使用以下内容替代:
df['col1','col2']

0

如果你正在寻找更高效的方法,

for col in ['a', 'b']:
    v = df.loc[:, col].values
    np.nan_to_num(v, 0.0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接