R语⾔学习系列15-缺失值处理⽅法
15. 缺失值处理⽅法
⽬录:
⼀. 直接删除法
⼆. ⽤均值/中位数/众数填补
三.探索变量的相关性插补
四.探索样本的相似性填补
五.分类树与回归树预测法插补(rpart包)bootstrap 5
六.多重插补法(mice包)
正⽂:
⼀、直接删除法
即直接删除含有缺失值的样本,有时最为简单有效,但前提是缺失数据的⽐例较少,且缺失数据是随机出现的,这样删除缺失数据后对分析结果影响不⼤。
1. 向量删除缺失值
x<-c(1,2,3,NA,5)
mean(x)#默认不忽略NA值或NaN值,注意与NULL的区别
[1] NA
mean(=TRUE)#忽略缺失值
[1] 2.75
x1<-x[!is.na(x)]#去掉向量中的NA值
x1
[1] 1 2 3 5
x2<-na.omit(x)#返回去掉NA值的向量
x2
[1] 1 2 3 5
attr(,"na.action")
[1] 4
attr(,"class")
[1] "omit"
na.fail(x)#若向量有NA值,则返回Error
Error in na.fail.default(x) : 对象⾥有遺漏值
na.fail(x1)#若向量不含NA值,则返回该向量
[1] 1 2 3 5
it(x),"na.action")#返回向量中NA值的下标
[1] 4
attr(,"class")
[1] "omit"
x[is.na(x)]<-0#将向量x中的NA值替换为0
x
[1] 1 2 3 0 5
2. 删除含缺失值的样本数据
⽤DMwR包实现。
library(DMwR)#⽤⾃带数据集algae,18个变量,200个观测值library(VIM)
sum(!complete.cases(algae))#查看含有缺失值的样本个数
[1] 16
algae1<-na.omit(algae)#直接删除所有含缺失值的样本
sum(!complete.cases(algae1))
[1] 0
#只删除缺失值过多的样本:缺失值个数⼤于列数的20%
algae2<-algae[-manyNAs(algae,0.2),]#数据框的“删除⾏”操作sum(!complete.cases(algae2))
其中,函数manyNAs(x,nORp)⽤来查数据框x中缺失值过多(≥缺失⽐例nORp)的⾏;nORp默认为0.2,即缺失值个数≥列数的20%
注:当删除缺失数据会改变数据结构时,通过对完整数据按照不同的权重进⾏加权,可以降低删除缺失数据带来的偏差。
3. 删除变量
若数据的某变量(列)有较多的缺失值且对研究⽬标影响不⼤时,可以将整列删除,这需要在变量的重
要性和观测的数量之间做权衡。
4. 做统计分析时排除缺失值
例如,做线性回归时,设置na.it即可:
lm(medv~ptratio+rad, data=BostonHousing,na.it)
⼆、⽤均值/中位数/众数填补
其优点在于不会减少样本信息,处理简单;其缺点在于当缺失数据不是随机出现时会产成偏误。若某⾃变量对因变量的影响⽐较⼩,那么这种粗略的估计是可以接受的,且有可能会产⽣令⼈满意的结果。
使⽤mlbench包中的BostonHousing数据集作为演⽰数据。由于BostonHousing数据集没有缺失值,为了演⽰需要,在数据集中随机
插⼊缺失值。通过这种⽅法,不仅可以评估由数据缺失带来的精度损失,也可以⽐较不同处理⽅式的效果好坏。
#初始化数据集
library(mlbench)
data("BostonHousing",package="mlbench")
treated<-BostonHousing#14个变量,506个观测值
#填充缺失值(随机替换两个变量各40个NA)
set.seed(100)
treated[sample(1:nrow(treated),40),"rad"]<-NA
treated[sample(1:nrow(treated),40),"ptratio"]<-NA
#查看缺失状况
sum(!complete.cases(treated))#查看缺失值数⽬
[1] 75
library(mice)
md.pattern(treated)#查看缺失模式
crimzninduschasnoxrm age dis tax b lstatmedv 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
⽤均值/中位数/众数填补的代码实现:
library(Hmisc)
treated$ptratio=impute(treated$ptratio, mean) #插补均值treated$ptratio=impute(treated$ptratio, median) #插补中位数treated$ptratio=impute(treated$ptratio, 20.2) #填充特定值treated$ptratio[is.na(treated$ptratio)]
<-mean(treated$ptratio, na.rm=T)#⼿动插补均值
#计算均值和中位数插补的准确度
library(DMwR)
actuals<-BostonHousing$ptratio[is.na(treated$ptratio)]
predicteds1<-rep(mean(treated$=TRUE),length (actuals))
regr.eval(actuals,predicteds1)
maemsermsemape
1.62324034 4.19306071
2.04769644 0.09545664
predicteds2<-rep(median(treated$=TRUE),lengt h(actuals))
regr.eval(actuals,predicteds2)
maemsermsemape
1.63500000 4.78600000
2.18769285 0.09933331
注1:R语⾔中没有直接求众数的函数,可⽤sort(table(x))先求频数再排序观察到,再⽤特定值填充。
注2:函数regr.eval()⽤来返回真实值与预测值差异的若⼲统计量:mae为平均绝对误差;mse为均⽅误差;rmse为均⽅根误差;mape 为平均绝对百分误差。
另外,DMwR包中提供了函数centralImputation(),可以⽤数据的中⼼趋势值来填补缺失值:数值型变量使⽤中位数,名义变量使⽤众数。
三、探索变量的相关性插补
探寻变量之间的相关关系,到相关性较⾼的两个变量后,再寻他们之间的线性回归关系,最后通过线性回归关系计算缺失值进⾏填补。
1. 探寻变量之间的相关关系
使⽤上⼀篇中的⽅法,或者
library(DMwR)
symnum(cor(algae[,4:18],use="complete.obs"))
mPmOCl NO NH o P Ch a1 a2 a3 a4 a5 a6 a7
mxPH 1
mnO2 1
Cl 1
NO3 1
NH4 , 1
oPO4 . . 1
PO4 . . * 1
Chla . 1
a1 . . . 1
a2 . . 1
a3 1
a4 . . . 1
a5 1
a6 . . . 1
a7 1
attr(,"legend")
[1] 0 ‘ ’0.3 ‘.’ 0.6 ‘,’ 0.8 ‘+’ 0.9 ‘*’ 0.95 ‘B’ 1
注:函数cor()的⽤来产⽣变量之间的相关值矩阵,设定参数use="complete.obs"可以使R在计算相关值时忽略含有NA值的样本。函数symnum()是⽤来改善结果的输出形式的。
可见变量oPO4和PO4,a1和a4可能有较强的线性相关关系。
2. 先得到回归关系
lm(PO4~oPO4,data=algae,na.it)
Coefficients:
(Intercept) oPO4
42.897 1.293
可见变量PO4与oPO4之间的线性回归关系为:
PO4=1.293*oPO4+42.897
3. 利⽤回归关系计算缺失值进⾏插补
#构造函数计算缺失值
fillPO4<-function(x)
{
if(is.na(x)) return(NA) else
return(1.293*x+42.897)
}
#使⽤sapply函数对缺失值进⾏插补
algae[is.na(algae$PO4),"PO4"]<-sapply(algae[is.na(alga e$PO4),"oPO4"],fillPO4)
四、探索样本的相似性填补
利⽤多个样本(⾏)之间的相似性填补缺失值。度量相似性的指标有很多,常⽤的是欧⽒距离。
DMwR包中的函数knnImputation()使⽤k近邻⽅法来填充缺失值。具体过程如下:对于需要插值的记录,基于欧⽒距离计算k个和它最近的观测;再将这k个近邻的数据利⽤距离逆加权算出填充值,最后⽤该值替代缺失值。
该⽅法的优点是只需调⽤⼀次函数就能对所有缺失值进⾏填充。该函数的参数是除了因变量之外所有变量组成的数据框,因为你⽆法对未知的因变量进⾏插值。
函数knnImputation()的基本格式:
knnImputation(data, k=10, meth="weighAvg", ...)
其中,data为数据框格式的数据集;k设定近邻数,默认为10;meth 指定计算缺失值的⽅法,默认为weighavg(加权平均),也可选median (中位数)。
knnOutput<-knnImputation(treated[,!names(treated) %in% "medv"])#KNN插值,剔除因变量medv
sum(is.na(knnOutput))#检查是否插补所有NA值
[1] 0
actuals<-BostonHousing$ptratio[is.na(treated$ptratio)] predicts<-knnOutput[is.na(treated$ptratio),"ptratio"]
regr.eval(actuals,predicts)
maemsermsemape
1.00188715 1.97910183 1.40680554 0.05859526
可见,与均值插补法相⽐,mape值从0.095降到0.059,降低了约38%.
knn插值法的缺点是,对因⼦类变量的插补效果不好。rpart包和mice 包提供了更灵活的解决⽅案:
五、分类树与回归树预测法插补——rpart包
rpart的优点是只需⼀个未缺失值就可以填充整个数据样本。对因⼦型变量,rpart函数可把method设为class(分类树);对数值型变量就设定method=anova(回归树)。当然,也要剔除因变量。
函数rpart()的基本格式为:
rpart(formula, data, na.action, method,parms,...)
其中,formula为回归⽅程的形式,如y~x1+x2;data为数据框;na.action 指定缺失值处理⽅式,默认为na.rpart;method根据树的末端的数据类型选择相应变量分割⽅法,有四种取值:连续型取anova,离散型取class,计数型取poisson,⽣存分析型取exp;parms⽤来设置三个参数:先验概率、损失矩阵、分类纯度的度量⽅法。
library(rpart)
#rad为因⼦型变量
class_mod<-rpart(rad~.-medv, data=treated[!is.na(treat ed$rad),], na.it, method="class") #ptratio为数值型变量anova_mod<-rpart(ptratio~.-medv, data=treated[!is.na(t reated$ptratio),], na.actio
it, method="anova") #预测插补值rad_pred<-predict(class_mod, treated[is.na(treated$ra d),])
ptratio_pred<-predict(anova_mod, treated[is.na(treated $ptratio),])
#计算ptratio的插补精度
ptratio_actu<-BostonHousing$ptratio[is.na(treated$ptra tio)]
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论