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+网站上的另一篇文章。

  尽管通过本文你已经对各类处理方法有了初步了解,但这还不足以帮助你判断每种方法的优劣。当你下次处理缺失值的时候,这些方法是值得一试的。

参考资料

posted @ 2016-05-19 11:42  银河统计  阅读(16789)  评论(0编辑  收藏  举报