Python Pandas Fillna 中位数不起作用

Posted

技术标签:

【中文标题】Python Pandas Fillna 中位数不起作用【英文标题】:Python Pandas Fillna Median not working 【发布时间】:2018-08-14 03:18:03 【问题描述】:

我正在尝试在包含多列和多行的数据框中填充所有 nan。我正在使用它来训练多变量 ML 模型,所以我想用中位数填充每列的 nans。只是为了测试中值函数,我这样做了:

training_df.loc[[0]] = np.nan # Sets first row to nan
print(training_df.isnull().values.any()) # Prints true because we just inserted nans
test = training_df.fillna(training_df.median()) # Fillna with median
print(test.isnull().values.any()) # Check afterwards

但是当我这样做时,没有任何反应,最后一行的打印仍然返回 True。如果我尝试更改为使用这样的中值函数:

training_df.fillna(training_df.median(), inplace=True)

什么也没有发生。如果我这样做:

training_df = training_df.fillna(training_df.median(), inplace=True)

Training_df 变为无。我该如何解决这个问题?

【问题讨论】:

我要做的第一件事是使用training_df.info() 检查training_df 的数据类型。如果您有任何未存储为数字类型的列,则可能会发生您所描述的行为。 另外,当您使用inplace=True 时,不要将结果分配给变量,因为它始终是None。这就是为什么你的最后一行将整个变量设置为None 【参考方案1】:

正如@thesilkworm 建议的那样,首先将您的系列转换为数字。下面是一个最小的例子:

import pandas as pd, numpy as np

df = pd.DataFrame([[np.nan, np.nan, np.nan],
                   [5, 1, 2, 'hello'],
                   [1, 4, 3, 4],
                   [9, 8, 7, 6]], dtype=object)

df = df.fillna(df.median())  # fails

df[df.columns] = df[df.columns].apply(pd.to_numeric, errors='coerce')

df = df.fillna(df.median())  # works

【讨论】:

【参考方案2】:

您可以使用np.nanmedian + 字典推导来重命名。

df = pd.DataFrame("col1": [1,2,np.nan,3], "col2": [5, np.nan, 10, np.nan])

col_map = df.columns.get_loc(col):col for col in df.columns # 0: "col1", 1: "col2"
median_values = pd.Series(np.nanmedian(df, axis=0)).rename(col_map)
df = df.fillna(median_values)

>> df
   col1 col2
0   1.0 5.0
1   2.0 7.5
2   2.0 10.0
3   3.0 7.5

您可以看到 jpp 在.apply() 之后调用df.median() 的答案中的间歇步骤与我上面定义的median_series 相同。

print(df.median()) # after .apply()
col1    2.0
col2    7.5
dtype: float64

print(median_series)
col1    2.0
col2    7.5
dtype: float64

注意:如果您的 df 中的某个值是我们在生产中经常需要的“hi”之类的字符串,则使用 np.nanmedian 会出错。

解释: 在大多数情况下,我仍然喜欢 jpp 的答案,但有时如果我的数据很大或者我正在将数据发送到 ML API 端点,我不想使用 errors='coerce' 来覆盖所有内容并 想要返回错误。想象一下您在 6 个月后投入生产的场景,并且您的一些 col1 值作为字符串传递:[1, 2, 'hi', 'bye']。使用errors=coerce 会将hibye 设置为NaN。您将不会意识到字符串从您未进行的某些上游更改泄漏到列中,并且您的 ML 算法正在像正常一样传递分数,但实际上它只是对一堆 NaN 进行评分。您的模型性能会在不知道原因的情况下下降,实际上它是一个很好的模型,它只是没有对正确的数据进行评分。公司赔钱,你就被解雇了。我意识到我偏离了一个不太可能的滑坡,但想强调重点。

我们想要如果在 prod 中出现此错误:

df = pd.DataFrame("col1": [1,2,np.nan,'hi'], "col2": [5, np.nan, 10, np.nan])
col_map = df.columns.get_loc(col):col for col in df.columns # 0: "col1", 1: "col2"
median_series = pd.Series(np.nanmedian(df, axis=0)).rename(col_map)
>> 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''

【讨论】:

以上是关于Python Pandas Fillna 中位数不起作用的主要内容,如果未能解决你的问题,请参考以下文章

pandas中如何对指定列做fillna

Python pandas 使用 fillna() 来避免对 NaN 值进行错误拆分

数据分析——python,pandas:DataFrame对象(merge函数,fillna函数的使用)排序

Pandas 使用 groupby 和模式填充

带有递增值的 Pandas fillna

如何将另一整列作为参数传递给 pandas fillna()