如何使用 Pandas 的 fillna() 方法填充列的众数?

37

我有一个数据集,其中有一列名为“原籍国”的列,包含约30000条记录。其中一些记录是缺失的,用NaN表示,因此我想用mode()值来填充它们。 我写了这样的代码:

data['Native Country'].fillna(data['Native Country'].mode(), inplace=True)

然而,当我计算缺失值数量时:

for col_name in data.columns: 
    print ("column:",col_name,".Missing:",sum(data[col_name].isnull()))

对于“Native Country”列,它仍然显示相同数量的NaN值。

8个回答

70

只需调用系列的第一个元素:

data['Native Country'].fillna(data['Native Country'].mode()[0], inplace=True)

或者您可以使用赋值运算符完成相同的操作:

data['Native Country'] = data['Native Country'].fillna(data['Native Country'].mode()[0])

9

注意,NaN 可能是您数据框的众数:在这种情况下,您会将 NaN 替换为另一个 NaN。


7
Pandas 0.24.0+ 默认情况下不会计算 NaN 值:https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.mode.html - DearVolt

2
import numpy as np

import pandas as pd

print(pd.__version__)

1.2.0

df = pd.DataFrame({'Country': [np.nan, 'France', np.nan, 'Spain', 'France'], 'Purchased': [np.nan,'Yes', 'Yes', 'No', np.nan]})
国家 已购买
0 无效值 无效值
1 法国
2 无效值
3 西班牙
4 法国 无效值
 df.fillna(df.mode())  ## only applied on first row because df.mode() returns a dataframe with one row
国家 购买
0 法国
1 法国
2 未知
3 西班牙
4 法国 未知
df = pd.DataFrame({'Country': [np.nan, 'France', np.nan, 'Spain', 'France'], 'Purchased': [np.nan,'Yes', 'Yes', 'No', np.nan]})

df.fillna(df.mode().iloc[0]) ## convert df to a series
国家 购买过
0 法国
1 法国
2 法国
3 西班牙
4 法国

1
你可以获取数字“mode”或任何其他策略
1. 对于mode:
    num = data['Native Country'].mode()[0]
    data['Native Country'].fillna(num, inplace=True)

对于平均数和中位数:
    num = data['Native Country'].mean() #or median(); No need of [0] because it returns a float value.
    data['Native Country'].fillna(num, inplace=True)

或者像这样一行代码。
data['Native Country'].fillna(data['Native Country'].mode()[0], inplace=True)

1
如果我们使用fillna(df['colX'].mode())来填充缺失值,由于mode()的结果是一个Series,它只会为匹配索引的前几行填充。至少在以下情况下是这样的:
fill_mode = lambda col: col.fillna(col.mode())
df.apply(fill_mode, axis=0)

然而,仅仅通过使用Series的第一个值fillna(df['colX'].mode()[0]),我认为我们冒着在数据中引入意外偏差的风险。如果样本是多峰的,那么仅仅采用第一个众数值会使本来就有偏差的插补方法变得更糟。例如,如果我们有[0, 21, 99]作为同等最频繁的值,那么仅仅取0是不够的。或者在给定列中TrueFalse值出现频率相同时,用False填充缺失值。

我没有一个明确的解决方案。如果使用众数是必要的,从所有局部极大值中分配一个随机值可能是一种方法。


运行此代码后,在我的情况下,数据集中仍然存在NA值。pandas版本1.5.2 - paulduf

0

因此,我注意到df.mean()返回一个pd.Series,而在具有混合类型(包括数值和分类)的数据集上调用的df.mode则返回一个pd.DataFrame,其与df具有相同的列,且第0行给出众数。 这是预期的,因为Series的类型必须是唯一的,但仍然导致df.fillna(df.mode())失败,而df.fillna(df.mean())可以正常工作。

以下是一个解决此问题的一行代码:

df.fillna({k: v[0] for k, v in df.mode().to_dict().items()})

另一个问题是第一个值v[0]是从可能的模式列表中选择的,正如this answer所指出的那样,但是这仍然可以通过对v应用另一个聚合函数来改进。

0

对于那些像我一样来到这里,想要填充多个列中的NA值,按多个列进行分组,并且在组中只有NA值时出现mode函数无法返回任何结果的问题:

df[['col_to_fill_NA_1','col_to_fill_NA_2']] = df.groupby(['col_to_group_by_1', 'col_to_group_by_2'], dropna=False)[['col_to_fill_NA_1','col_to_fill_NA_2']].transform(lambda x: x.fillna(x.mode()[0]) if len(x.mode()) == 1 else x)

您可以填写任意数量的“col_to_fill_NA”,并按任意数量的“col_to_group_by”进行分组。 如果存在mode,则if语句返回mode,并在仅包含NAs的组中返回NAs。


-1
尝试类似以下的代码: fill_mode = lambda col: col.fillna(col.mode()) 并使用以下函数: new_df = df.apply(fill_mode, axis=0)

在这种情况下,Audris Ločmelis已经提供了更好的答案。 - paulduf

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