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