R语言-缺失值处理1
R语言中缺失值处理
前言
在处理数据的过程中,样本往往会包含缺失值。我们有必要对缺失值进行处理,这样不但可以降低预测分析的数据偏差,而且还可以构建有效的模型。本文将简要介绍几种常见的数据缺失值处理方法。
目录
1. 数据准备和模式设定
2. 删除记录
3. 删除变量
4. 用均值/中位数/众数进行插补
5. 预测法
1. 数据准备和模式设定
本文所涉及到的几种数据缺失值处理方法都是使用mlbench包中的BostonHousing数据集作为演示数据。由于BostonHousing数据集没有缺失值,为了演示需要,在数据集中随机插入缺失值。通过这种方法,我们不仅可以评估由数据缺失带来的精度损失,也可以比较不同处理方式的效果好坏。
# 初始化数据
# install.packages('mlbench')
library(mlbench)
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
在插入缺失值之后,我们可以使用mice包中md.pattern函数查看缺失值的“数据模式”
# 缺失值的模式
library(mice)
md.pattern(BostonHousing)
crim zn indus chas nox rm age dis tax ptratio b lstat medv rad
466 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0
40 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1
0 0 0 0 0 0 0 0 0 0 0 0 0 40 40
以下是处理缺失值数据的常见四种方法:
2. 删除记录
如果训练数据集包含有大量的观测值,那么你可以尝试删除包含缺失值的观测行(或者是在构建模型的时候不包含缺失值,例如设置na.action=na.omit)。在删除含有缺失值的观测行之前请确保满足以下两个条件:
- 有足够样本点
- 不会引入偏差
举例如下:
lm(medv ~ ptratio + rad, data=BostonHousing, na.action=na.omit)
3. 删除变量
如果数据集中的某个特定变量包含许多的缺失值,并且通过删除这个特定变量你可以保留许多的观测值。除非该变量是一个非常重要的预测指标,否则我建议你删除它。应用这个方法需要我们在变量的重要性和观测的数量之间做权衡。
4. 用均值/中位数/众数进行插补
处理缺失值数据的一种简单粗暴方法是插补均值、中位数或者众数。在具体环境下,如果该自变量对因变量的影响比较小,那么这种粗略的估计是可以接受的,并且有可能会产生令人满意的结果。
举例如下:
library(Hmisc)
impute(BostonHousing$ptratio, mean) # 插补均值
impute(BostonHousing$ptratio, median) # 插补中位数
impute(BostonHousing$ptratio, 20) # 填充特定值
# 手动插值
BostonHousing$ptratio[is.na(BostonHousing$ptratio)] <- mean(BostonHousing$ptratio, na.rm = T)
下面通过均值来插补缺失值,并计算准确度。
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.65000000 3.91387214 1.97835086 0.09577013
5. 预测法
用预测值来处理缺失值的一种高级的方法,主要包括:KNN插值,rpart包,mice包
5.1 kNN插值法
DMwR包中的knnImputation函数使用k近邻方法来填充缺失值。具体过程如下:对于需要插值的记录,基于欧氏距离计算k个和它最近的观测。接着将这k个近邻的数据利用距离逆加权算出填充值,最后用该值替代缺失值。
该方法的优点是只需调用一次函数就能对所有缺失值进行填充。该函数的参数是除了响应变量之外所有变量组成的数据框。这是因为你无法对未知的响应变量进行插值。
library(DMwR)
knnOutput <- knnImputation(BostonHousing[, !names(BostonHousing) %in% "medv"]) # 使用KNN插值.
anyNA(knnOutput)
#> FALSE
检查精度
actuals <- original$ptratio[is.na(BostonHousing$ptratio)]
predicteds <- knnOutput[is.na(BostonHousing$ptratio), "ptratio"]
regr.eval(actuals, predicteds)
#> mae mse rmse mape
#> 0.90718277 1.77887569 1.33374499 0.05469914
与均值插值法相比,mape的值降低了42.8个百分点。
5.2 rpart
knn插值法的缺点是对因子类变量的插补效果不好。rpart包和mice包提供了更灵活的解决方案。rpart的优点是只需一个未缺失值就可以填充整个数据样本。
对因子变量而言,rpart函数式可以把method设为class(分类树)。数值型变量就设定method=anova(回归树)。当然,我们也要剔除响应变量。
library(rpart)
class_mod <- rpart(rad ~ . - medv, data=BostonHousing[!is.na(BostonHousing$rad), ], method="class", na.action=na.omit) # rad变量是因子型变量
anova_mod <- rpart(ptratio ~ . - medv, data=BostonHousing[!is.na(BostonHousing$ptratio), ], method="anova", na.action=na.omit) # ptratio是数值型变量
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.61655453 0.74165850 0.86119597 0.03643275
与knn插值法相比,mape值又额外下降了33.3%。好极了。
rad的插补精度
actuals <- original$rad[is.na(BostonHousing$rad)]
predicteds <- as.numeric(colnames(rad_pred)[apply(rad_pred, 1, which.max)])
mean(actuals != predicteds) # 计算误分类比率
#> 0.2179487
仅有21.7%的缺失值被误分类,这个结果也不坏。
5.3 mice
mice是链式方程多元插值的简写(Multivariate Imputation by Chained Equations)。mice包提供了多种先进的缺失值处理方法。它使用一种不同寻常的方法来进行两步插值:首先利用mice函数建模再用complete函数生成完整数据。mice(df)会返回df的多个完整副本,每个副本都对缺失的数据插补了不同的值。complete()函数则会返回这些数据集中的一个(默认)或多个。下面演示用该方法如何对rad和ptratio这两个变量进行插值:
library(mice)
miceMod <- mice(BostonHousing[, !names(BostonHousing) %in% "medv"], method="rf") # 基于随机森林模型进行mice插值
miceOutput <- complete(miceMod) # 生成完整数据
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.31000000 0.62950000 0.79341036 0.01984801
mape值与rpart相比提升了45.8个百分点。
rad的插补精度:
actuals <- original$rad[is.na(BostonHousing$rad)]
predicteds <- miceOutput[is.na(BostonHousing$rad), "rad"]
mean(actuals != predicteds) # compute misclass error.
#> 0.3076923
误分类比率为30%,也就是说40个缺失观测里插补错误的只有12个。相对rpart方法的错误率(25%)来说,有点稍微的下降。
如果你想更深入的了解,可以查看mice包的手册和DataScience+网站上的另一篇文章。
尽管通过本文你已经对各类处理方法有了初步了解,但这还不足以帮助你判断每种方法的优劣。当你下次处理缺失值的时候,这些方法是值得一试的。
参考资料
©哈尔滨商业大学 银河统计工作室
银河统计工作室成员由在校统计、计算机部分师生和企业数据数据分析师组成,维护和开发银河统计网和银河统计博客(技术文档)。专注于数据挖掘技术研究和运用,探索统计学、应用数学和IT技术有机结合,尝试大数据条件下新型统计学教学模式。