Python:如何正确处理 pandas DataFrame 中的 NaN,以便在 scikit-learn 中进行特征选择

Python: How to properly deal with NaN's in a pandas DataFrame for feature selection in scikit-learn

这与我发布的一个问题有关 here 但这个问题更具体也更简单。

我有一个 pandas DataFrame,其索引是唯一的用户标识符,列对应于唯一的事件,值 1(参加)、0(未参加)或 NaN(不是 invited/not相关)。对于 NaN,矩阵非常稀疏:有数百个事件,大多数用户最多只被邀请到几十个。

我创建了一些额外的列来衡量 "success",我将其定义为相对于邀请的出席率:

my_data['invited'] = my_data.count(axis=1)
my_data['attended'] = my_data.sum(axis=1)-my_data['invited']
my_data['success'] = my_data['attended']/my_data['invited']

我现在的目标是在 events/columns 上进行特征选择,从最基本的基于方差的方法开始:去除方差低的那些。然后我会查看事件的线性回归,并只保留那些具有大系数和小 p 值的事件。

但我的问题是我有太多 NaN,我不确定处理它们的正确方法是什么,因为大多数 scikit-learn 方法都会因为它们而给我错误。一个想法是用 -1 替换“没有参加”,用 0 替换 'not invited',但我担心这会改变事件的重要性。

谁能建议在不改变每个 feature/event 的统计显着性的情况下处理所有这些 NaN 的正确方法?

编辑:我想补充一点,如果有合理的允许,我很乐意从上面更改 "success" 的指标我继续进行功能选择。我只是想确定哪些事件可以有效地吸引用户兴趣。它非常开放,这主要是练习特征选择。

谢谢!

如果我理解正确的话,您想从 NaN 中清除数据而不显着改变其中的统计属性 - 这样您就可以 运行 进行一些分析后记。

我最近确实遇到了类似的事情,您可能感兴趣的一种简单方法是使用 sklearn 的 'Imputer'。正如 EdChum 前面提到的,一种想法是用轴上的均值代替。其他选项包括例如用中位数替换。

类似于:

from sklearn.preprocessing import Imputer
imp = Imputer(missing_values='NaN', strategy='mean', axis=1)
cleaned_data = imp.fit_transform(original_data)

在这种情况下,这将用每个轴上的平均值替换 NaN(例如,让我们按事件估算,因此轴 = 1)。然后,您可以对清理后的数据进行舍入以确保获得 0 和 1。

我会按事件为数据绘制一些直方图,以健全地检查这种预处理是否显着改变了你的分布——因为我们可能通过将如此多的值交换为均值/众数/沿每个轴的中位数。

Link供参考:http://scikit-learn.org/stable/modules/generated/sklearn.preprocessing.Imputer.html

更进一步(假设以上还不够),您可以交替执行以下操作:

  • 获取数据中的每个事件列,并在删除所有 nan 数字后计算参加 ('p') 与不参加 ('1 - p') 的概率。 [IE。 p = 出席/(出席 + 未出席)]
  • 然后使用伯努利分布生成的随机数替换每个事件列中的 NaN 数,我们符合您估计的 'p',大致如下:

    import numpy as np

    n = 1 # number of trials

    p = 0.25 # estimated probability of each trial (i.e. replace with what you get for attended / total)

    s = np.random.binomial(n, p, 1000)

    # s now contains random a bunch of 1's and 0's you can replace your NaN values on each column with

同样,这本身并不完美,您最终仍然会略微偏向您的数据(例如,更准确的方法是考虑每个用户跨事件的数据依赖性)- 但是从大致匹配的分布中抽样这至少应该比用平均值等任意替换更稳健

希望对您有所帮助!

以上示例已弃用,请使用:

from sklearn.impute import SimpleImputer
imputer = SimpleImputer(missing_values=np.nan, strategy='mean')