本文结构:前言——数据介绍——检查缺失值分布——缺失值插补(4种方法)——总结

前言:

现实生活中的数据是纷繁杂乱的,收集来的数据有缺失和录入错误司空见惯,所以学习如果处理这些常见问题是每一个数据人必须掌握的技能,俗话说巧妇难为无米之炊,不能很好的处理原始数据会给后来的建模带来麻烦,甚至引入不必要的偏差和错误,数据科学家都熟悉“垃圾进垃圾出”的说法。本文介绍的是数据预处理中非常重要的一步——缺失值处理。

数据介绍:

本文数据来自西南财经大学统计学院李可老师提供的信贷数据。其数据是完好的,共有2万多条记录。本文随机挑选1000条数据,并对其中的贷款额(loan_amnt)和信用等级(grade)随机选取20个数据点设置为缺失值(NA)。

# 设置工作路径
 setwd('D:\\缺失值处理常见办法')
# 加载数据集
 loandata <- read.csv('loanData.csv', header = TRUE)

# 随机选取1000条记录,并将其中部分数据设置为缺失值
 set.seed(1)
 ind <- sample(nrow(loandata), 1000)
 data.sample <- na.omit(loandata)[ind,]     # 确保样本数据是无缺失的
 data.copy <- data.sample                   # 复制数据,为后来的结果做对比操作

 data.copy$loan_amnt[sample(nrow(data.copy), 20)] <- NA        #设置缺失值
 data.copy$grade[sample(nrow(data.copy), 20)] <- NA            #设置缺失值

检查缺失值分布:

所有学过R语言的同学应该都清楚is.na()函数可以检查数据中是否有缺失值,但R语言还有两个有趣的包可以帮助我们快速了解数据框中的缺失值的分布情况——mice包和VIM包。

# mice包检测
 require(mice)
 summary(data.copy)
 md.pattern(data.copy)
# 本例结果(不同抽样结果不必完全一样)

R语言各个变量有多少缺失值 r语言缺失值插补_r语言

图1为mice包中md.pattern()函数的输出结果,’1’代表完好数据,’0’代表缺失值。左侧第一列,’963’代表有963条记录是完全没有缺失值的,第一个’17’代表有17条数据仅loan_amnt变量存在缺失值,’3’代表有3条记录在loan_amnt和grade同时存在缺失值。

#VIM包检测
 require(VIM)
 aggr_plot <- aggr(data.copy, col = c('blue','red'),numbers = TRUE,sortVars = TRUE, labels=names(data.copy),Cex.axis = .7, gap = 3,Ylab = c("Missing data histogram","Missing value pattern"))

R语言各个变量有多少缺失值 r语言缺失值插补_r语言_02


图2为VIM包中aggr()函数的输出结果,它是对缺失值分布的可视化。其中手动设置蓝色为完好值,红色为缺失值。

缺失值插补:

1). 处理方法 —- 删除行/列 (na.action=na.omit())
适用条件:
足够大数据集 (model doesn’t lose power)
不会引入偏差 (no disproportionate or non-representation of classes)

删列:不起重要预测作用的变量

2). 处理方法 —- 替换 (mean / median / mode)
适用条件:
不需要非常精确的估算

# 用均值和特定值替换
# 自定义插补函数
 impute <- function(x, x.impute){ifelse(is.na(x),x.impute,x)}

 impute(data.copy$loan_amnt, mean(ata.copy$loan_amnt))   #均值替换   
 impute(data.copy$loan_amnt, 20)        # 特定值替换

3). 最近邻插补——kNN

# 最近邻填补缺失值
 require(DMwR)
 knnOutput <- knnImputation(data.copy[c(-1,-4,-5)]) 
 anyNA(knnOutput)

# 将插补值与实际值进行对照
 actuals <-data.sample$loan_amnt[is.na(data.copy$loan_amnt)]
 predicteds <- knnOutput[is.na(data.copy$loan_amnt),
 "loan_amnt"]

# 两样本均值检验并计算其相似度
 t.test(actuals, predicteds)        # 接受差值为0的假设
 cor(actuals, predicteds)           # 在粗处理的情况下相似度可以达到63%左右

4). 分类回归树——rpart
相比于kNN,rpart方法可以应用于分类数据

注意点:rpart()建立分类回归树模型

  • 对于分类变量,添加参数:method = “class”
  • 对于数值变量,添加参数:method = “anova”
# rpart填补缺失值
 require(rpart)
# 对分类变量的预测建模
 class_mod <- rpart(grade ~ ., data =  data.copy[!is.na(data.copy$grade), ][-1],method = "class", na.action = na.omit)
# 对连续变量的预测建模
 anova_mod <- rpart(loan_amnt ~ ., data =data.copy[!is.na(data.copy$loan_amnt), ][-1],method = "anova", na.action = na.omit)

# 根据模型进行预测      
 grade_pred <- predict(class_mod,data.copy[is.na(data.copy$grade), ], type = 'class')
 loan_amnt_pred <- predict(anova_mod,data.copy[is.na(data.copy$loan_amnt), ])

# 将loan_amnt的实际值与预测值对比
 actuals <-data.sample$loan_amnt[is.na(data.copy$loan_amnt)] 
 predicteds <- loan_amnt_pred

# 检验
 t.test(actuals, predicteds)        # 接受差值为0的假设
 cor(actuals, predicteds)       # 在粗处理的情况下相似度可以达到67%左右

注意:无论是最近邻还是分类回归树插补法,在预测建模时都不应该包含响应变量。

总结:
对缺失值插值有很多注意和值得研究的地方,本文仅是选取了部分常用的方法,结合R语言,粗略地介绍之。粗糙石砖,还望引玉。