Python中分类变量的缺失值插补

Posted

技术标签:

【中文标题】Python中分类变量的缺失值插补【英文标题】:Missing values imputation for categorical variables in Python 【发布时间】:2020-02-05 22:34:21 【问题描述】:

我正在为这种情况寻找一种好的插补方法。 我有一个包含分类变量和缺失数据的数据框,如下所示:

    import pandas as pd


var1 = ['a','a','a','c','e',None]
var2 = ['p1','p1','p1','p2','p3','p1']
var3 = ['o1','o1','o1','o2','o3','o1']

df = pd.DataFrame('v1':var1,'v2':var2,'v3':var3)

我正在寻找一种仅支持分类变量的python(也可以是R)的插补方法。这个想法是在给定 var2 和 var3 的情况下预测 var1。 例如,如果我们要预测 var1 中的 NONE 值。我们当然知道 var1='a' 给定 var2='p1' 和 var3 = 'o1' 的概率是 1。我的意思是,P(var1='a' / (var2='p1',var3='o1' ) = 3/3 = 1。我考虑过编写条件模式之类的东西,但也许有人已经对此进行了编程,或者对此有更好的算法。 我只有 3 个具有多个类别的分类变量,其缺失值为 MCAR。值得一提的是,我的数据集大约有超过一百万行(大约 10% 的 NA)。

你有什么要推荐的吗?

提前致谢, 托马斯

【问题讨论】:

你可以使用:pandas.core.categorical.Categorical.fillna 【参考方案1】:

您可以使用 K 最近邻插补。

这是 R 中的一个示例:

library(DMwR)

var1 = c('a','a','a','c','e',NA)
var2 = c('p1','p1','p1','p2','p3','p1')
var3 = c('o1','o1','o1','o2','o3','o1')

df = data.frame('v1'=var1,'v2'=var2,'v3'=var3)
df

knnOutput <- DMwR::knnImputation(df, k = 5) 
knnOutput

输出:

  v1 v2 v3
1  a p1 o1
2  a p1 o1
3  a p1 o1
4  c p2 o2
5  e p3 o3
6  a p1 o1

更新:

KNN 不适用于大型数据集。大型数据集的两个选项是多项式插补和朴素贝叶斯插补。多项式插补稍微容易一些,因为您不需要将变量转换为虚拟变量。我在下面展示的朴素贝叶斯实现需要做更多的工作,因为它需要您转换为虚拟变量。下面,我将展示如何在 R 中适应这些:

# make data with 6M rows
var1 = rep(c('a','a','a','c','e',NA), 10**6)
var2 = rep(c('p1','p1','p1','p2','p3','p1'), 10**6)
var3 = rep(c('o1','o1','o1','o2','o3','o1'), 10**6)
df = data.frame('v1'=var1,'v2'=var2,'v3'=var3)

####################################################################
## Multinomial imputation
library(nnet)
# fit multinomial model on only complete rows
imputerModel = multinom(v1 ~ (v2+ v3)^2, data = df[!is.na(df$v1), ])

# predict missing data
predictions = predict(imputerModel, newdata = df[is.na(df$v1), ])

####################################################################
#### Naive Bayes
library(naivebayes)
library(fastDummies)
# convert to dummy variables
dummyVars <- fastDummies::dummy_cols(df, 
                                     select_columns = c("v2", "v3"), 
                                     ignore_na = TRUE)
head(dummyVars)

dummy_cols 函数将虚拟变量添加到现有数据框中,因此现在我们将仅使用 4:9 列作为我们的训练数据。

#     v1 v2 v3 v2_p1 v2_p2 v2_p3 v3_o1 v3_o2 v3_o3
# 1    a p1 o1     1     0     0     1     0     0
# 2    a p1 o1     1     0     0     1     0     0
# 3    a p1 o1     1     0     0     1     0     0
# 4    c p2 o2     0     1     0     0     1     0
# 5    e p3 o3     0     0     1     0     0     1
# 6 <NA> p1 o1     1     0     0     1     0     0
# create training set
X_train <- na.omit(dummyVars)[, 4:ncol(dummyVars)]
y_train <- na.omit(dummyVars)[, "v1"]

X_to_impute <- dummyVars[is.na(df$v1), 4:ncol(dummyVars)]


Naive_Bayes_Model=multinomial_naive_bayes(x = as.matrix(X_train), 
                                          y = y_train)

# predict missing data
Naive_Bayes_preds = predict(Naive_Bayes_Model, 
                                  newdata = as.matrix(X_to_impute))


# fill in predictions
df$multinom_preds[is.na(df$v1)] = as.character(predictions)
df$Naive_Bayes_preds[is.na(df$v1)] = as.character(Naive_Bayes_preds)
head(df, 15)


#         v1 v2 v3 multinom_preds Naive_Bayes_preds
#    1     a p1 o1           <NA>              <NA>
#    2     a p1 o1           <NA>              <NA>
#    3     a p1 o1           <NA>              <NA>
#    4     c p2 o2           <NA>              <NA>
#    5     e p3 o3           <NA>              <NA>
#    6 <NA> p1 o1              a                 a
#    7     a p1 o1           <NA>              <NA>
#    8     a p1 o1           <NA>              <NA>
#    9     a p1 o1           <NA>              <NA>
#    10    c p2 o2           <NA>              <NA>
#    11    e p3 o3           <NA>              <NA>
#    12 <NA> p1 o1              a                 a
#    13    a p1 o1           <NA>              <NA>
#    14    a p1 o1           <NA>              <NA>
#    15    a p1 o1           <NA>              <NA>

【讨论】:

KNN 是个好主意,但我需要比 KNN 更有效的东西。我忘了提到我的数据有超过一百万行:/ 无论如何,非常感谢! 我明白了。我已经用一些适用于大型数据集的新想法更新了我的答案。 谢谢蔡琳。还有一个问题,你为什么在多项式函数中使用这个公式 (v1 ~ (v2+ v3)^2?你认为通过神经网络的多项式对数线性模型是否适用于只有分类变量的数据集? (v2+ v3)^2v1 + v2 + v1:v2 的 R 简写(即 v1、v2 和交互)。在这种情况下,交互可能不是必需的——它可能对更复杂的关系更有用。神经网络也可以工作,但训练时间可能会成为一个问题,具体取决于数据集的大小和网络架构(除其他外)。 哦,我不知道。感谢大家的帮助!【参考方案2】:

如果您可以访问 GPU,您可以查看 DataWig from AWS Labs 以进行深度学习驱动的分类插补。您可以尝试批量大小(取决于可用的 GPU 内存)和超参数优化。可以具体选择categorical encoders和embedding。

作为旁注,还有算法 MICE(链式方程的多元插补)。 Miceforest 是默认在 CPU 上运行的库的一个示例。然而,后端使用 LightGBM(Gradient Boosting Machine)进行随机森林分类。当 LightGBM 为built for GPU's 时,您可以将几个参数从miceforest 传递给.tune_parameters() 函数。例如,device="gpu",gpu_platform_id=0,gpu_device_id=0 等。关于如何优化 GPU 性能的更多信息可以在这里找到https://lightgbm.readthedocs.io/en/latest/GPU-Performance.html

【讨论】:

以上是关于Python中分类变量的缺失值插补的主要内容,如果未能解决你的问题,请参考以下文章

KNNImputer:一种可靠的缺失值插补方法

R语言高级方法进行缺失数据多重插补案例演示

使用KNN进行缺失值填补详解及实践

单元无回答的缺失数据处理方法

R语言缺失值的处理——回归预测法

缺失值处理