作者 Selva Prabhakaran

译者 钱亦欣

在处理一些真实数据时,样本中往往会包含缺失值(Missing values)。我们需要对缺失值进行适宜的处理,才能建立更为有效的模型,使得后续预测分析能有更小的偏差。本文将罗列不同的缺失值处理方法,并进行具体应用。

数据准备和缺失模式设定

本文使用mlbench包中的BostonHousing数据集作为示例来演示不同的缺失值处理方法。由于原始的数据集并不包含缺失值,我们需要随机删除一些数据。通过这种方法,我们不仅可以评估由数据缺失带来的精度损失,也可以比较不同处理方式的效果好坏。让我们先加载这个数据集,并随机删除一些数据。

# 加载数据集
data ("BostonHousing", package="mlbench")
original <- BostonHousing  # backup original data# 引入缺失值
set.seed(100)
BostonHousing[sample(1:nrow(BostonHousing), 40), "rad"] <- NA
BostonHousing[sample(1:nrow(BostonHousing), 40), "ptratio"]       #>      crim zn indus chas   nox    rm  age    dis rad tax ptratio      b lstat medv
#> 1 0.00632 18  2.31    0 0.538 6.575 65.2 4.0900   1 296    15.3 396.90  4.98 24.0
#> 2 0.02731  0  7.07    0 0.469 6.421 78.9 4.9671   2 242    17.8 396.90  9.14 21.6
#> 3 0.02729  0  7.07    0 0.469 7.185 61.1 4.9671   2 242    17.8 392.83  4.03 34.7
#> 4 0.03237  0  2.18    0 0.458 6.998 45.8 6.0622   3 222    18.7 394.63  2.94 33.4
#> 5 0.06905  0  2.18    0 0.458 7.147 54.2 6.0622   3 222    18.7 396.90  5.33 36.2
#> 6 0.02985  0  2.18    0 0.458 6.430 58.7 6.0622   3 222

缺失值已经生成好了,尽管我们已经知道哪些位置的数据缺失,但还是用mice包中的md.pattern函数快速检查下。

# 缺失值的模式
library(mice)
md.pattern(BostonHousing)  # 返回数据的缺失值的模式#>     crim zn indus chas nox rm age dis tax b lstat medv rad ptratio
#> 431    1  1     1    1   1  1   1   1   1 1     1    1   1       1  0
#>  35    1  1     1    1   1  1   1   1   1 1     1    1   0       1  1
#>  35    1  1     1    1   1  1   1   1   1 1     1    1   1       0  1
#>   5    1  1     1    1   1  1   1   1   1 1     1    1   0       0  2
#>        0  0     0    0   0  0   0   0   0 0     0    0  40      40 80

缺失值处理方法

目前共有四种方法来处理缺失值:

1. 删除观测(记录)

如果你的数据集拥有大量观测,足以用来建立模型,那你可以把包含缺失值的观测删去(或者在建模时选择不纳入这些观测,如设定na.action=na.omit)。在删去相应观测后,请确保:

  1. 你有足够的样本点可以用来建模。
  2. 没有引入偏差(译者注:即认为这些缺失值是随机产生的,删除对应观测后,样本总体还是一个随机样本而非选择样本)。
# 例子
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)  # 用特殊值替代(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.62324034 4.19306071 2.04769644 0.09545664

4.用预测值插值

用预测值插值是一种比较前沿的方法,我们有很多模型可以实现这个过程,比如KNN插值,rpart还有mice。

4.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
#> 1.00188715 1.97910183 1.40680554 0.05859526

与均值插值相比,mape的值降低了39个百分点。总体还不错。

4.2 rpart

利用knn插值的局限在于它对于因子类变量的插补效果可能不尽如人意。这种情况下rpart和mice就提供了更灵活的解决方案。rpart的优势是你只需要一个未缺失值就可以插补整个样本。

插值思路是利用rpart(决策树)替代knn来预测缺失值。对于因子类变量而言,我们在调用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.71061673 0.99693845 0.99846805 0.04099908

与knn相比,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)  # 计算误分类比率
#> 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")  # 基于随机森林模型进行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.36500000 0.78100000 0.88374204 0.02121326

mape值与rpart相比又提升了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%),这是一个了不起的提升。

如果你想了解的更深入,这里是mice包的手册和DataScience+上另一篇关于mice包的文章。

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

如果你有任何问题请在下方留言或访问我的LinkedIn。

原文刊载于datascience+网站

链接:http://datascienceplus.com/missing-value-treatment/

R语言中的缺失值处理相关推荐

  1. 在R语言中进行缺失值填充:估算缺失值

    介绍 缺失值被认为是预测建模的首要障碍.因此,掌握克服这些问题的方法很重要.最近我们被客户要求撰写关于缺失值处理的研究报告,包括一些图形和统计输出. 估算缺失值的方法的选择在很大程度上影响了模型的预测 ...

  2. R语言中的特殊值 NA NULL NaN Inf

    这几个都是R语言中的特殊值,都是R的保留字, NA:Not available  表示缺失值   用 is.na() 来判断是否为缺失值 NULL:表示空值,即没有内容  用 is.null() 来判 ...

  3. r语言中正定矩阵由于误差不正定_R语言之数据处理(一)

    在上一篇小文中,提到了关于R语言导入数据的一些方法,之后的重点就转向了数据的处理上.数据处理其实在整个数据分析项目中所占用的时间是比较多的,所以根据处理的目的不同,也有不同的处理方法.在R语言中,我通 ...

  4. R语言中的数据处理包dplyr、tidyr笔记

    R语言中的数据处理包dplyr.tidyr笔记 dplyr包是Hadley Wickham的新作,主要用于数据清洗和整理,该包专注dataframe数据格式,从而大幅提高了数据处理速度,并且提供了与其 ...

  5. r语言中检测异常值_R中的异常值检测

    r语言中检测异常值 介绍 (Introduction) An outlier is a value or an observation that is distant from other obser ...

  6. R语言中的管道操作——magrittr包

    R语言中的管道操作--magrittr包 一.项目环境 开发工具:RStudio R:3.5.2 相关包:magritter 二.数据准备以及问题阐述 这次要解决的问题是如何使用提取数据框中所有包含缺 ...

  7. R语言中的地理/投影坐标系统(下)[翻译]

    原文链接:https://mgimond.github.io/Spatial/coordinate-systems-in-r.html. 译文分上.下两篇,这里为下篇. ❝ 「译者注」:在原文的本部分 ...

  8. R语言中使用pkgbuild::find_rtools查看是否有Rtools、使用Sys.which函数查看make是否存在、如果没有则安装、使用writeLines函数绑定R和Rtools

    R语言中使用pkgbuild::find_rtools(debug = TRUE)查看是否有Rtools.使用Sys.which函数查看make是否存在.如果没有则安装Rtools.使用writeLi ...

  9. R语言删除包含缺失值的行并将字符数据列(character)转化为因子列(factor)实战

    R语言删除包含缺失值的行并将字符数据列(character)转化为因子列(factor)实战 目录

最新文章

  1. 我与我的专业计算机作文500字,我的好朋友——电脑
  2. 记录 android 开发的一个 面试 问题
  3. Android当中layer-list使用来实现多个图层堆叠到一块儿
  4. 牛客题霸 [斐波那契数列] C++题解/答
  5. Android :ScaleAnimation
  6. Java延时队列DelayedQueue
  7. 跨境电商ERP系统怎么使用?
  8. 基于自然语言处理的需求到类图转化的文献调查
  9. [HNOI2013]题解
  10. 汉典速查: 一个简易的国学阅读工具
  11. 函数对称性常见公式_函数的对称性
  12. EMC传导骚扰的共模电流与差模电流
  13. 在Unity3D中制作VR全景视频、图片
  14. 计算机二级vb考试怎么准备,计算机二级考试内容是什么 各科目该怎么准备
  15. java布道师_JavaWeb主管布道师
  16. LiveData原理解析
  17. 目标检测:EfficientDet(官方开源版)训练自己的数据
  18. 助你成功的10个万能谈话技巧
  19. 2014蓝桥杯B组初赛试题《啤酒和饮料》
  20. 【Qt】 Fractal Designer 5.0 - Help(中文版)

热门文章

  1. 汕头大学本科学生毕业论文(设计)撰写规范(2018版)
  2. Linux性能测试工具之Disk(四)
  3. 本地主机Xshell连接虚拟机Linux CentOS7
  4. Crumb -面包屑状的嵌套按钮
  5. 用java如何画动物_用画小狗的方法来解释Java值传递
  6. 交换机短路_交换机端口短路 导致上网不正常
  7. 大数据分析未来财富管理谁会脱颖而出?
  8. 小白福利-手把手教你如何重新安装你的系统
  9. ios 扫码枪外设 键盘模式_iPadOS 显威力,苹果 iPad Pro 终于用上带触控板的外接键盘...
  10. 《C++ Concurrency in Action》笔记