为何Series.fillna()无法填充DataFrame中全部NaN值?
DataFrame填充NaN后仍存在空值的原因及解决办法
问题描述
我想用随机值填充DataFrame中的NaN值,操作步骤如下:
- 创建df1数据集
- 通过compound列切片筛选出compound为'a'的行得到df2
- 使用
default_rng生成不重复的随机填充序列filler - 调用
df2.month.fillna(filler, inplace=True)执行填充,但结果中仍有NaN值,预期应全部填充完成,请问原因是什么?
原代码及输出
创建df1的代码:
import pandas as pd import numpy as np df1 = pd.DataFrame( list(zip( ['0001', '0001', '0002', '0003', '0004', '0004'], ['a', 'b', 'a', 'b', 'a', 'b'], ['USA', 'USA', 'USA', 'USA', 'USA', 'USA'], [np.nan, np.nan, 'Jan', np.nan, np.nan, 'Jan'], [1,2,3,4,5,6])), columns=['sample ID', 'compound', 'country', 'month', 'value']) df1
df1输出:
sample ID compound country month value 0 0001 a USA NaN 1 1 0001 b USA NaN 2 2 0002 a USA Jan 3 3 0003 b USA NaN 4 4 0004 a USA NaN 5 5 0004 b USA Jan 6
切片生成df2的代码:
df2 = df1.loc[df1.compound == 'a'] df2
df2输出:
sample ID compound country month value 0 0001 a USA NaN 1 2 0002 a USA Jan 3 4 0004 a USA NaN 5
填充代码及输出:
from numpy.random import default_rng rng = default_rng() filler = rng.choice(len(df2.month), size=len(df2.month), replace=False) filler = pd.Series(-abs(filler)) df2.month.fillna(filler, inplace=True) df2
填充后输出:
sample ID compound country month value 0 0001 a USA -1.0 1 2 0002 a USA Jan 3 4 0004 a USA NaN 5
原因分析
核心问题在于**fillna方法是按索引对齐进行填充的**:
- 你生成的
filler序列默认索引是[0,1,2],但df2的索引是[0,2,4] - 填充时,只有索引完全匹配的位置才会被处理:
- df2索引0对应filler索引0,NaN被成功替换为-1.0
- df2索引2对应filler索引2,但该位置原本不是NaN,所以无变化
- df2索引4在filler中没有对应索引(filler最大索引为2),因此该位置的NaN无法被匹配填充,保留了下来
解决方案
让filler的索引与df2的索引完全一致,即可让fillna正确匹配所有NaN位置。有两种实现方式:
方式一:仅为NaN位置生成对应索引的填充序列(更高效)
from numpy.random import default_rng rng = default_rng() # 获取df2中month列的NaN位置索引 nan_indexes = df2[df2['month'].isna()].index # 生成对应数量的不重复随机值 filler_values = rng.choice(range(1, 10), size=len(nan_indexes), replace=False) # 创建与NaN位置索引一致的填充序列 filler = pd.Series(-abs(filler_values), index=nan_indexes) df2['month'].fillna(filler, inplace=True) df2
方式二:生成与df2全量索引一致的填充序列
from numpy.random import default_rng rng = default_rng() # 生成随机值并指定索引为df2的索引 filler = rng.choice(len(df2), size=len(df2), replace=False) filler = pd.Series(-abs(filler), index=df2.index) df2['month'].fillna(filler, inplace=True) df2
两种方式执行后,df2的month列所有NaN都会被正确填充,不会再保留空值。
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

