R语言 缺失值处理


数据科学中, 数据中缺少值是现实问题中常见的现象。了解如何有效地处理缺失值是减少偏差和生成强大模型的必要步骤。 当一个观测在数据框架的一列中丢失或包含字符值而不是数值时,就会出现缺失值。必须删除或替换缺失的值,以便从数据中得出正确的结论。让我们探讨如何处理缺少的值以及如何实现它们的各种选项。


数据准备

让我们使用mlbench包中的BostonHousing数据集来讨论处理缺失值的各种方法。虽然原始的BostonHousing数据没有缺失值,但是我将随机引入缺失值。这样,我们就可以根据实际值来验证假定的缺失值,从而知道重新生成实际数据的方法有多有效。让我们从mlbench包导入数据并随机插入缺失的值(NA)开始。


data ("BostonHousing", package="mlbench") #加载数据
original <- BostonHousing # 备份原始数据
set.seed(100)
BostonHousing[sample(1:nrow(BostonHousing), 40), "rad"] <- NA
BostonHousing[sample(1:nrow(BostonHousing), 40), "ptratio"] <- NA

到这里,随机的缺失值(NA)就被插入到BostonHousing数据中了。

为了验证,用head()打印一部分:


head(BostonHousing)
插入的随机缺失值
插入的随机缺失值

处理缺失值的方法有四种:

1.删除观测

如果您的数据集中有大量的观测,其中所有要预测的类都充分地表示在训练数据中,那么尝试删除(或者在构建模型时不包括缺失的值,例如设置na.action=na.omit)那些包含缺失值的观测(行)。确保删除观察后,确保:

  • 有足够的数据点,所以模型不会失去动力。
  • 不要引入偏见(意思是不相称或不代表阶级)。

例如,针对上面的数据,可以:


lm(medv ~ ptratio + rad, data=BostonHousing, na.action=na.omit)

2.删除变量

如果有特定的变量相对于其他变量有较多的缺失值,而且,如果通过删除,一个变量可以节省许多观测,那么最好排除该变量,除非它是一个非常重要的因素。这是一个在变量的重要性和失去一些观察结果之间作权衡的问题。


3.用平均值/中位数/众数估算

用平均值/中值/模式替换缺失值是处理缺失值的一种粗略方法。

根据上下文的不同,比如,如果变化很小,或者变量对响应的影响很小,这样粗略的近似是可以接受的,可能会给出令人满意的结果。


library(Hmisc)
impute(BostonHousing$ptratio, mean)  # 用平均值替代
impute(BostonHousing$ptratio, median)  # 中值替代
impute(BostonHousing$ptratio, 20)  # 特定数字替代

让我们计算一下计算平均值时的准确度


library(DMwR)
actuals <- original$ptratio[is.na(BostonHousing$ptratio)]
predicteds <- rep(mean(BostonHousing$ptratio, na.rm=T), length(actuals))
regr.eval(actuals, predicteds)
#>        mae        mse       rmse       mape 
#> 1.62324034 4.19306071 2.04769644 0.09545664

4.预测

4.1 kNN 填充

DMwR::knnImputation使用k近邻法来填充缺失值。简单来说,kNN估算的作用如下:对于每一个要估算的观察,它根据欧氏距离确定k个最接近的观察,并计算这些k个观测的加权平均值(基于距离的加权)。

这样做的好处是,只需对函数进行一次调用,就可以将所有变量中缺少的所有值利用该函数进行替换。它把整个数据框架作为参数,你甚至不需要指定你想替换的变量。但是要注意,在注入时不要包含响应变量,因为在测试/生产环境中注入时,如果数据包含缺失的值,此时将无法使用未知的响应变量。


library(DMwR)
knnOutput <- knnImputation(BostonHousing[, !names(BostonHousing) %in% "medv"])  # 执行KNN替代.
anyNA(knnOutput)

计算精确度:


actuals <- original$ptratio[is.na(BostonHousing$ptratio)]
predicteds <- knnOutput[is.na(BostonHousing$ptratio), "ptratio"]
regr.eval(actuals, predicteds)
#>        mae        mse       rmse       mape 
#> 1.00188715 1.97910183 1.40680554 0.05859526 

平均绝对百分误差(mape)比平均(mean imputation)提高了约39%。好。


4.2 rpart

DMwR::knnImputation的限制是,当缺少的值来自一个因子变量时,有时可能不适合使用它。rpart和mice都可以灵活地处理这种情况。rpart的优点是你只需要在预测字段中有一个变量是非NA。

这里的想法是我们将使用rpart来预测缺失值而不是kNN。要处理因子变量,可以在调用rpart()时设置method=class。对于数字,我们使用,method=anova。在这里,我们需要确保不训练rpart的响应变量(medv)。


library(rpart)
class_mod <- rpart(rad ~ . - medv, data=BostonHousing[!is.na(BostonHousing$rad), ], method="class", na.action=na.omit)  # since rad is a factor
anova_mod <- rpart(ptratio ~ . - medv, data=BostonHousing[!is.na(BostonHousing$ptratio), ], method="anova", na.action=na.omit)  # since ptratio is numeric.
rad_pred <- predict(class_mod, BostonHousing[is.na(BostonHousing$rad), ])
ptratio_pred <- predict(anova_mod, BostonHousing[is.na(BostonHousing$ptratio), ])

计算ptratio的精度:


actuals <- original$ptratio[is.na(BostonHousing$ptratio)]
predicteds <- ptratio_pred
regr.eval(actuals, predicteds)
#>        mae        mse       rmse       mape 
#> 0.71061673 0.99693845 0.99846805 0.04099908 

相对于knnImputation,平均绝对百分比误差(mape)又提高了约30%。很好。

rad的精度:


actuals <- original$rad[is.na(BostonHousing$rad)]
predicteds <- as.numeric(colnames(rad_pred)[apply(rad_pred, 1, which.max)])
mean(actuals != predicteds)  # 计算misclass误差
#> 0.25  

这样会产生25%的分类误差。对于一个因子变量来说还不错!


4.3 mice

mice是Multivariate Imputation by Chained Equations的缩写,是一个为缺失值处理提供高级特性的R包。它使用了一种不太常见的两步实现替代的方法,使用mice()构建模型,使用complete()生成完整的数据。mice(df)功函数产生df的多个完整副本,每一个都有不同的缺失数据的补充。complete()函数返回其中一个或几个数据集,默认值为第一个。让我们看看如何输入“rad”和“ptratio”:


library(mice)
miceMod <- mice(BostonHousing[, !names(BostonHousing) %in% "medv"], method="rf")  # 以随机森林为基础,对老鼠进行替代。
miceOutput <- complete(miceMod)  # generate the completed data.
anyNA(miceOutput)
#> FALSE

让我们来计算ptratio的精度:


actuals <- original$ptratio[is.na(BostonHousing$ptratio)]
predicteds <- miceOutput[is.na(BostonHousing$ptratio), "ptratio"]
regr.eval(actuals, predicteds)
#>        mae        mse       rmse       mape 
#> 0.36500000 0.78100000 0.88374204 0.02121326

与rpart相比,平均绝对百分比误差(mape)提高了约48%。非常好!。

计算rad的精度:


actuals <- original$rad[is.na(BostonHousing$rad)]
predicteds <- miceOutput[is.na(BostonHousing$rad), "rad"]
mean(actuals != predicteds)  # compute misclass error.
#> 0.15

错误分类误差减少到15%,即40个观察中的6个。与rpart的25%相比,这是一个很好的改进。




公众号

关注公众号,获取一手资讯

“ R语言 缺失值处理 ” comments 0

评论/回复

电子邮件地址不会被公开。 必填项已用*标注