如何处理伯努利朴素贝叶斯的缺失数据?

数据挖掘 Python 分类 scikit-学习 朴素贝叶斯分类器 缺失数据
2021-09-19 21:51:28

我正在处理一个如下所示的分类数据数据集:

    content_1   content_2   content_4   content_5   content_6   
0         NaN         0.0         0.0         0.0         NaN 
1         NaN         0.0         0.0         0.0         NaN   
2         NaN         NaN         NaN         NaN         NaN   
3         0.0         NaN         0.0         NaN         0.0   

这些代表用户从 Intranet 下载,其中向用户展示了下载特定内容的机会。1表示用户看到内容并下载它,0表示用户看到内容但没有下载它,并且NaN表示用户没有看到/没有显示那条内容。

我正在尝试使用 scikit-learn Bernoulli Naive Bayes 模型来预测用户下载的概率content_1,假设他们已经看到下载/未下载content_2-7

我已经删除了所有content_1等于的数据,NaN因为我显然只对用户主动做出决定的数据点感兴趣。这给出的数据如下:

    content_1   content_2   content_3   content_4   content_5   content_6   
0         1.0         NaN         1.0         NaN         NaN         1.0 
1         0.0         NaN         NaN         0.0         1.0         0.0    
2         1.0         0.0         NaN         NaN         NaN         1.0    

在上述框架中,NaN, 是一个缺失值。对于Nan存在 a 的数据点,我希望算法忽略该类别,并仅使用计算中存在的那些类别。

我从这些问题中知道:1,在处理缺失值时基本上有 3 个选项:

  1. 如果任何类别包含a,则忽略数据点NaN(即删除该行)
  2. 插补一些其他占位符值(例如 -1 等)或
  3. 估算与整个数据集分布相对应的一些平均值。

但是,由于以下原因,这些都不是最佳选择:

  1. 每行至少包含 1 个 NaN。这意味着,在这种安排下,我将丢弃整个数据集。显然不行。
  2. 我不希望missing value添加到概率计算中,如果我Nan用 -1 替换就会发生这种情况。我也在使用伯努利朴素贝叶斯,所以据我所知,这需要单独的0 or 1值。
  3. 由于这是分类数据,因此以这种方式这样做对我来说没有意义(它要么被看到,要么没有,如果没有,则不需要)。

这里的答案表明,做到这一点的最佳方法是,在计算概率时,如果它是一个缺失值,则忽略该类别(基本上你是在说:仅根据我提供的具有非缺失值的特定类别计算概率)。

我不知道在使用 scikit-learn 朴素贝叶斯模型时如何对此进行编码,是否将其作为缺失值进行编码。

这是我到目前为止所拥有的:

df=pd.read_clipboard()
from sklearn import datasets
from sklearn.naive_bayes import BernoulliNB
# Create train input / output data
y_train = df['content_1'].values
X_train = df.drop('content_1', axis=1).values
# Loud Bernoulli Naive Bayes model
clf = BernoulliNB()
clf.fit(X_train, y_train)

显然,由于 present ,这会返回一个错误NaNs那么如何调整 scikit-learn Bernoulli 模型以自动忽略带有 的列NaNs,而只选择带有 0 或 1 的列?

我知道这对于库存模型可能是不可能的,并且查看文档似乎表明了这一点。因此,这可能需要大量编码,所以我会这样说:我不是要求某人去编码(我也不期望它);我希望被指出正确的方向,例如,如果有人遇到过这个问题/他们如何解决这个问题/相关的博客或教程帖子(我的搜索结果一无所获)。

在此先感谢-感谢您的阅读。

2个回答

您的搜索结果是正确的:无需删除或输入数据,就没有内置的方法来做您想做的事BernoulliNB

但是,有一条出路:根据数据中的过滤样本训练单独的贝叶斯模型,然后通过堆叠它们来组合它们的预测。

过滤

此处过滤意味着:

  • 从原始样本中分离出样本df,每个样本只有df.columns. 这样,您将有一个DataFrameonly for content_2,一个 for content_2, content_3,在一种列的阶乘组合中。
  • 确保每个样本仅由子集中的任何列都没有NaNs的行组成。

这部分在你的情况下有点简单,但有点冗长:你会有n(n 阶乘) 列组合,每个组合都会产生一个单独的样本。例如,您可以有一个名为的示例,df_c2其中仅包含content_2值为 0 或 1 的行,df_c2_c3仅填充content_2content_3列,等等。

这些样本会使NaN您训练的每个模型都不存在值。以一种聪明的方式实现这一点可能很麻烦,所以我建议从最简单的场景开始——例如两个样本,两个模型;您将逐渐提高并在代码中找到可靠的解决方案。

堆叠贝叶斯模型

这称为贝叶斯模型平均(BMA),作为一个概念,它在本文中得到了彻底解决。在那里,归因于贝叶斯模型预测的权重是其后验概率。

内容可能难以一口气吸收,如果其中一些内容不适合您,请放心。这里的要点是您将每个模型的预测概率乘以权重 0 < w < 1然后求和(求和结果应在[0,1])。您可以先凭经验确定权重,然后看看它对您有什么帮助。


编辑:

由于我提出的解决方案增加了复杂性,正如这个(也有用的)答案中所述,您可以选择在纯 Python 中实现朴素贝叶斯,因为它并不复杂(并且有很多教程可供参考)。这将使算法更容易满足您的需求。

一种选择是 scikit-learn 的sklearn.impute.IterativeImputer. initial_strategy可以设置为“most_frequent”,这是对特征的伯努利分布进行建模的有用方法。