R语言:缺失值处理
前言
刚接触缺失数据研究的读者可能会被各式各样的方法和言论弄得眼花缭乱。该领域经典的读本是Little和Rubin的Statistical Analysis with Missing Data, Second Edition(2002)一书。其他比较优秀的专著还有Allison的Missing Data(2001)、Schafer和Graham的"Missing Data: Our View of the State of the Art"(2002),以及Schlomer、Bauman和Card的"Best Practices for Missing Data Management in Counseling Psychology"(2010)。
一个完整的处理方法通常包含以下几个步骤:
(1) 识别缺失数据;
(2) 检查导致数据缺失的原因;
(3) 删除包含缺失值的实例或用合理的数值代替(插补)缺失值。
但遗憾的是,仅有识别缺失数据是最清晰明确的步骤。知道数据为何缺失依赖于你对数据生成过程的理解,而决定如何处理缺失值则需要判断哪种方法的结果最为可靠和精确。
统计学家通常将缺失数据分为三类。它们都用概率术语进行描述,但思想都非常直观。我们将用sleep研究中对做梦时长的测量(有12个动物有缺失值)来依次阐述三种类型。
(1) 完全随机缺失 若某变量的缺失数据与其他任何观测或未观测变量都不相关,则数据为完全随机缺失(MCAR)。若12个动物的做梦时长值缺失不是由于系统原因,那么可认为数据是MCAR。注意,如果每个有缺失值的变量都是MCAR,那么可以将数据完整的实例看做是对更大数据集的一个简单随机抽样。
(2) 随机缺失 若某变量上的缺失数据与其他观测变量相关,与它自己的未观测值不相关,则数据为随机缺失(MAR)。例如,体重较小的动物更可能有做梦时长的缺失值(可能因为较小的动物较难观察),“缺失”与动物的做梦时长无关,那么该数据就可以认为是MAR。此时,一旦你控制了体重变量,做梦时长数据的缺失与出现将是随机的。
(3) 非随机缺失 若缺失数据不属于MCAR或MAR,则数据为非随机缺失(NMAR)。例如,做梦时长越短的动物也更可能有做梦数据的缺失(可能由于难以测量时长较短的事件),那么数据可认为是NMAR。大部分处理缺失数据的方法都假定数据是MCAR或MAR。此时,你可以忽略缺失数据的生成机制,并且(在替换或删除缺失数据后)可以直接对感兴趣的关系进行建模。当数据是NMAR时,想对它进行恰当地分析比较困难,你既要对感兴趣的关系进行建模,还要对缺失值的生成机制进行建模。
处理缺失数据的方法有很多,但不能保证都生成一样的结果。下图列出了一系列可用来处理不完整数据的方法,以及相应的R包。
目录
1. 识别缺失数据
2. 探索缺失值模式
3. 理解缺失值数据的来由和影响
4. 处理缺失值完整实例分析
5. 处理缺失值的其他方法
主要程序包
install.packages(c("VIM","mice"))
library(VIM)
library(mice)
1. 识别缺失数据
首先,我们回顾一下前节的内容并地一步拓展。R使用NA(不可得)代表缺失值,NaN(不是一个数)代表不可能的值。另外,符号Inf和-Inf分别代表正无穷和负无穷。函数is.na()、is.nan()和is.infinite()可分别用来识别缺失值、不可能值和无穷值。每个返回结果都是TRUE或FALSE。表15-1给出了一些示例。
这些函数返回的对象与其自身参数的个数相同。若每个元素的类型检验通过,则由TRUE替换,否则用FALSE替换。例如,令y <- c(1, 2, 3, NA),则is.na(y)返回向量c(FALSE, FALSE, FALSE,TRUE)。
函数complete.cases()可用来识别矩阵或数据框中没有缺失值的行。若每行都包含完整的实例,则返回TRUE的逻辑向量;若每行有一个或多个缺失值,则返回FALSE。
对于识别缺失值,有两点需要牢记。第一点,complete.cases()函数仅将NA和NaN识别为缺失值,无穷值(Inf和-Inf)被当做有效值。第二点,必须使用与本章中类似的缺失值函数来识别R数据对象中的缺失值。像myvar == NA这样的逻辑比较无法实现。
NA:代表缺失值;
NaN:代表不可能的值;
Inf:代表正无穷;
-Inf:代表负无穷。
is.na():识别缺失值;
is.nan():识别不可能值;
is.infinite():无穷值。
is.na()、is.nan()和is.infinte()函数的返回值示例
2. 探索缺失值模式
在决定如何处理缺失数据前,了解哪些变量有缺失值、数目有多少、是什么组合形式等信息非常有用。本节中,我们将介绍探索缺失值模式的图表及相关方法。最后,如果知道了数据为何缺失,这将为后续深入研究提供许多启示。
2.1 列表显示缺失值
你已经学习了一些识别缺失值的基本方法。比如使用complete.cases()函数列出完整的实例,或者相反,列出含一个或多个缺失值的实例。但随着数据集的增大,该方法就逐渐丧失了吸引力。此时你可以转向其他R函数。
mice包中的md.pattern()函数可生成一个以矩阵或数据框形式展示缺失值模式的表格。将函数应用到sleep数据集,可得到:
> library(mice)
> data(sleep,package="VIM")
> md.pattern(sleep)
BodyWgt BrainWgt Pred Exp Danger Sleep Span Gest Dream NonD
42 1 1 1 1 1 1 1 1 1 1 0
2 1 1 1 1 1 1 0 1 1 1 1
3 1 1 1 1 1 1 1 0 1 1 1
9 1 1 1 1 1 1 1 1 0 0 2
2 1 1 1 1 1 0 1 1 1 0 2
1 1 1 1 1 1 1 0 0 1 1 2
2 1 1 1 1 1 0 1 1 0 0 3
1 1 1 1 1 1 1 0 1 0 0 3
0 0 0 0 0 4 4 4 12 14 38
表中1和0显示了缺失值模式,0表示变量的列中有缺失值,1则表示没有缺失值。第一行表述了“无缺失值”的模式(所有元素都为1)。第二行表述了“除了Span之外无缺失值”的模式。第一列表示各缺失值模式的实例个数,最后一列表示各模式中有缺失值的变量的个数。此处可以看到,有42个实例没有缺失值,仅2个实例缺失了Span。9个实例同时缺失了NonD和Dream的值。数据集包含了总共(42 × 0) + (2 × 1) + … + (1 × 3) = 38个缺失值。最后一行给出了每个变量中缺失值的数目。
2.2 图形探究缺失数据
虽然md.pattern()函数的表格输出非常简洁,但我通常觉得用图形展示模式更为清晰。VIM包提供了大量能可视化数据集中缺失值模式的函数,本节我们将学习其中几个:aggr()、matrixplot()和scattMiss()。aggr()函数不仅绘制每个变量的缺失值数,还绘制每个变量组合的缺失值数。
2.2.1 例1:使用函数aggr()函数绘图。
library("VIM")
aggr(sleep,prop=FALSE,numbers=TRUE)
aggr(sleep, prop = TRUE, numbers = TRUE)
上述代码的结果见下图。
(VIM包将会打开GUI界面,你可以关闭它;本章我们使用代码完成所有的工作。)可以看到,变量NonD有最大的缺失值数(14),有2个哺乳动物缺失了NonD、Dream和Sleep的评分。42个动物没有缺失值。
代码aggr(sleep, prop = TRUE, numbers = TRUE)将生成相同的图形,但用比例代替了计数。选项numbers = FALSE(默认)删去数值型标签。
2.2.2 例2:使用函数matrixplot()函数绘图。
matrixplot(sleep)
matrixplot()函数可生成展示每个实例数据的图形。matrixplot(sleep)的图形见下图。
此处,数值型数据被重新转换到[0, 1]区间,并用灰度来表示大小:浅色表示值小,深色表示值大。默认缺失值为红色。
该图形可以进行交互,单击一列将会按其对应的变量重排矩阵。图中的行便按BodyWgt降序排列。通过矩阵图,你可以看出某些变量的缺失值模式是否与其他变量的真实值有关联。此图中可以看到,无缺失值的睡眠变量(Dream、NonD和Sleep)对应着较小的体重(BodyWgt)或脑重(BrainWgt)。
2.2.3 例3:使用函数marginplot()函数绘图。
marginplot()函数可生成一幅散点图,在图形边界展示两个变量的缺失值信息。以做梦时长与哺乳动物妊娠期时长的关系为例,来看下列代码:它的生成图形见下图。参数pch和col为可选项,控制着绘图符号和使用的颜色。
library("VIM")
marginplot(sleep[c("Gest","Dream")],pch=c(20),col=c("darkgray","red","blue"))
图形的主体是Gest和Dream(两变量数据都完整)的散点图。左边界的箱线图展示的是包含(深灰色)与不包含(红色)Gest值的Dream变量分布。注意,在灰度图上红色是更深的阴影。四个红色的点代表着缺失了Gest得分的Dream值。在底部边界上,Gest和Dream间的关系反过来了。可以看到,妊娠期和做梦时长呈负相关,缺失妊娠期数据时动物的做梦时长一般更长。两个变量均有缺失值的观测个数在两边界交叉处(左下角)用蓝色输出。VIM包有许多图形可以帮助你理解缺失数据在数据集中的模式,包括用散点图、箱线图、直方图、散点图矩阵、平行坐标图、轴须图和气泡图来展示缺失值的信息,因此这个包很值得探索。
2.3 用相关性探索缺失值
影子矩阵:用指示变量替代数据集中的数据(1表示缺失,0表示存在),这样生成的矩阵有时称作影子矩阵。
求这些指示变量间和它们与初始(可观测)变量间的相关性,有且于观察哪些变量常一起缺失,以及分析变量“缺失”与其他变量间的关系。
head(sleep)
str(sleep)
x<-as.data.frame(abs(is.na(sleep)))
head(sleep,n=5)
head(x,n=5)
y<-x[which(sd(x)>0)]
cor(y)
cor(sleep,y,use="pairwise.complete.obs")
3. 理解缺失值数据的来由和影响
识别缺失数据的数目、分布和模式有两个目的:
(1)分析生成缺失数据的潜在机制;
(2)评价缺失数据对回答实质性问题的影响。
即:
(1)缺失数据的比例有多大?
(2)缺失数据是否集中在少数几个变量上,抑或广泛存在?
(3)缺失是随机产生的吗?
(4)缺失数据间的相关性或与可观测数据间的相关性,是否可以表明产生缺失值的机制呢?
若缺失数据集中在几个相对不太重要的变量上,则可以删除这些变量,然后再进行正常的数据分析;
若有一小部分数据随机分布在整个数据集中(MCAR),则可以分析数据完整的实例,这样仍可得到可靠有效的结果;
若以假定数据是MCAR或MAR,则可以应用多重插补法来获得有铲的结论。
若数据是NMAR,则需要借助专门的方法,收集新数据,或加入一个相对更容易、更有收益的行业。
4. 处理缺失值完整实例分析
4.1 行删除
函数complete.cases()、na.omit()可用来存储没有缺失值的数据框或矩阵形式的实例(行):
# code1
newdata<-mydata[complete.cases(mydata),]
newdata<-na.omit(mydata)
# code2
options(digits=1)
cor(na.omit(sleep))
cor(sleep,use="complete.obs")
fit<-lm(Dream~Span+Gest,data=na.omit(sleep))
summary(fit)
4.2 多重插补
多重插补(MI)是一种基于重复模拟的处理缺失值的方法。
MI从一个包含缺失值的数据集中生成一组完整的数据集。每个模拟数据集中,缺失数据将使用蒙特卡洛方法来填补。
此时,标准的统计方法便可应用到每个模拟的数据集上,通过组合输出结果给出估计的结果,以及引入缺失值时的置信敬意。
可用到的包Amelia、mice和mi包
mice() 函数首先从一个包含缺失数据的数据框开始,然后返回一个包含多个完整数据集的对象。每个完整数据集都是通过对原始数据框中的缺失数据进行插而生成的。
with() 函数可依次对每个完整数据集应用统计模型
pool() 函数将这些单独的分析结果整合为一组结果。
最终模型的标准误和p值都将准确地反映出由于缺失值和多重插补而产生的不确定性。
基于mice包的分析通常符合以下分析过程:
# 示例说明code
library(mice)
imp<-mice(mydata,m)
fit<-with(imp,analysis)
pooled<-pool(fit)
summary(pooled)
# mydata是一个饮食缺失值的矩阵或数据框;
# imp是一个包含m个插补数据集的列表对象,同时还含有完成插补过程的信息,默认的m=5
# analysis是一个表达式对象,用来设定应用于m个插补的统计分析方法。方法包括做线回归模型的lm()函数、做广义线性模型的glm()函数、做广义可加模型的gam()、及做负二项模型的nbrm()函数。
# fit是一个包含m个单独统计分析结果的列表对象;
# pooled是一个包含这m个统计分析平均结果的列表对象。
具体例子实现过程
> library(mice)
> data(sleep,package="VIM")
> imp <- mice(sleep,seed=1234)
iter imp variable
1 1 NonD Dream Sleep Span Gest
1 2 NonD Dream Sleep Span Gest
1 3 NonD Dream Sleep Span Gest
1 4 NonD Dream Sleep Span Gest
1 5 NonD Dream Sleep Span Gest
2 1 NonD Dream Sleep Span Gest
2 2 NonD Dream Sleep Span Gest
2 3 NonD Dream Sleep Span Gest
2 4 NonD Dream Sleep Span Gest
2 5 NonD Dream Sleep Span Gest
3 1 NonD Dream Sleep Span Gest
3 2 NonD Dream Sleep Span Gest
3 3 NonD Dream Sleep Span Gest
3 4 NonD Dream Sleep Span Gest
3 5 NonD Dream Sleep Span Gest
4 1 NonD Dream Sleep Span Gest
4 2 NonD Dream Sleep Span Gest
4 3 NonD Dream Sleep Span Gest
4 4 NonD Dream Sleep Span Gest
4 5 NonD Dream Sleep Span Gest
5 1 NonD Dream Sleep Span Gest
5 2 NonD Dream Sleep Span Gest
5 3 NonD Dream Sleep Span Gest
5 4 NonD Dream Sleep Span Gest
5 5 NonD Dream Sleep Span Gest
> fit <- with(imp,lm(Dream~Span+Gest))
> pooled <- pool(fit)
> summary(pooled)
est se t df Pr(>|t|) lo 95 hi 95 nmis fmi lambda
(Intercept) 2.546 0.255 10.0 52 1e-13 2.035 3.057 NA 0.09 0.05
Span -0.005 0.012 -0.4 52 7e-01 -0.029 0.020 4 0.09 0.05
Gest -0.004 0.001 -2.7 56 1e-02 -0.007 -0.001 4 0.05 0.02
> imp
Multiply imputed data set
Call:
mice(data = sleep, seed = 1234)
Number of multiple imputations: 5
Missing cells per column:
BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
0 0 14 12 4 4 4 0 0 0
Imputation methods:
BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
"" "" "pmm" "pmm" "pmm" "pmm" "pmm" "" "" ""
VisitSequence:
NonD Dream Sleep Span Gest
3 4 5 6 7
PredictorMatrix:
BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
BodyWgt 0 0 0 0 0 0 0 0 0 0
BrainWgt 0 0 0 0 0 0 0 0 0 0
NonD 1 1 0 1 1 1 1 1 1 1
Dream 1 1 1 0 1 1 1 1 1 1
Sleep 1 1 1 1 0 1 1 1 1 1
Span 1 1 1 1 1 0 1 1 1 1
Gest 1 1 1 1 1 1 0 1 1 1
Pred 0 0 0 0 0 0 0 0 0 0
Exp 0 0 0 0 0 0 0 0 0 0
Danger 0 0 0 0 0 0 0 0 0 0
Random generator seed value: 1234
> imp$imp$Dream
1 2 3 4 5
1 1.0 0.5 0.5 0.5 0.3
3 2.6 2.1 1.5 1.8 1.3
4 3.4 3.1 3.4 1.2 3.4
14 0.3 0.5 0.5 0.3 1.2
24 1.8 1.3 3.6 0.9 5.6
26 2.3 3.1 2.0 2.6 2.1
30 1.2 0.3 3.4 2.6 2.3
31 3.4 0.5 0.6 1.0 0.5
47 0.5 1.5 1.5 2.2 3.4
53 0.3 0.5 0.5 0.5 0.6
55 0.5 0.9 2.6 2.7 2.4
62 1.0 2.1 0.5 3.9 3.6
>
>
> # 利用complete()函数可观察m个插补数据集中的任意一个,格式为:complete(imp,action=#)
> # eg:
>
> dataset3<-complete(imp,action=3)
> dataset3
BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
1 7e+03 6e+03 2 0.5 3 39 645 3 5 3
2 1e+00 7e+00 6 2.0 8 4 42 3 1 3
3 3e+00 4e+01 11 1.5 12 14 60 1 1 1
4 9e-01 6e+00 13 3.4 16 2 25 5 2 3
5 3e+03 5e+03 2 1.8 4 69 624 3 5 4
6 1e+01 2e+02 9 0.7 10 27 180 4 4 4
7 2e-02 3e-01 16 3.9 20 19 35 1 1 1
8 2e+02 2e+02 5 1.0 6 30 392 4 5 4
9 3e+00 3e+01 11 3.6 14 28 63 1 2 1
10 5e+01 4e+02 8 1.4 10 50 230 1 1 1
11 4e-01 6e+00 11 1.5 12 7 112 5 4 4
12 5e+02 4e+02 3 0.7 4 30 281 5 5 5
13 6e-01 2e+00 8 2.7 10 18 46 2 1 2
14 2e+02 4e+02 3 0.5 3 40 365 5 5 5
15 7e-02 1e+00 6 2.1 8 4 42 1 1 1
16 3e+00 2e+01 9 0.0 9 50 28 2 2 2
17 8e-01 4e+00 7 4.1 11 6 42 2 2 2
18 2e-01 5e+00 10 1.2 11 10 120 2 2 2
19 1e+00 2e+01 5 1.3 6 34 28 1 2 1
20 6e+01 8e+01 12 6.1 18 7 21 1 1 1
21 5e+02 7e+02 11 0.3 11 28 400 5 5 5
22 3e+01 1e+02 3 0.5 4 20 148 5 5 5
23 1e-01 1e+00 11 3.4 14 4 16 3 1 2
24 2e+02 4e+02 8 3.6 12 39 252 1 4 1
25 8e+01 3e+02 5 1.5 6 41 310 1 3 1
26 4e+01 1e+02 11 2.0 13 16 63 1 1 1
27 1e-01 4e+00 10 3.4 14 9 28 5 1 3
28 1e+00 6e+00 7 0.8 8 8 68 5 3 4
29 5e+02 7e+02 2 0.8 3 46 336 5 5 5
30 1e+02 2e+02 7 3.4 11 22 100 1 1 1
31 4e+01 6e+01 3 0.6 4 16 33 3 5 4
32 5e-03 1e-01 8 1.4 9 3 22 5 2 4
33 1e-02 2e-01 18 2.0 20 24 50 1 1 1
34 6e+01 1e+03 6 1.9 8 100 267 1 1 1
35 1e-01 3e+00 8 2.4 11 13 30 2 1 1
36 1e+00 8e+00 8 2.8 11 4 45 3 1 3
37 2e-02 4e-01 12 1.3 13 3 19 4 1 3
38 5e-02 3e-01 11 2.0 13 2 30 4 1 3
39 2e+00 6e+00 14 5.6 19 5 12 2 1 1
40 4e+00 1e+01 14 3.1 17 6 120 2 1 1
41 2e+02 5e+02 8 1.0 8 24 440 5 5 5
42 5e-01 2e+01 15 1.8 17 12 140 2 2 2
43 1e+01 1e+02 10 0.9 11 20 170 4 4 4
44 2e+00 1e+01 12 1.8 14 13 17 2 1 2
45 2e+02 2e+02 6 1.9 8 27 115 4 4 4
46 2e+00 1e+01 8 0.9 8 18 31 5 5 5
47 4e+00 4e+01 11 1.5 12 14 63 2 2 2
48 3e-01 2e+00 11 2.6 13 5 21 3 1 3
49 4e+00 5e+01 7 2.4 10 10 52 1 1 1
50 7e+00 2e+02 8 1.2 10 29 164 2 3 2
51 8e-01 1e+01 6 0.9 7 7 225 2 2 2
52 4e+00 2e+01 5 0.5 5 6 225 3 2 3
53 1e+01 1e+02 2 0.5 3 17 150 5 5 5
54 6e+01 2e+02 3 0.6 4 20 151 5 5 5
55 1e+00 1e+01 8 2.6 11 13 90 2 2 2
56 6e-02 1e+00 8 2.2 10 4 100 3 1 2
57 9e-01 3e+00 11 2.3 13 4 60 2 1 2
58 2e+00 1e+01 5 0.5 5 8 200 3 1 3
59 1e-01 2e+00 13 2.6 16 2 46 3 2 2
60 4e+00 6e+01 10 0.6 10 24 210 4 3 4
61 4e+00 4e+00 13 6.6 19 3 14 2 1 1
62 4e+00 2e+01 18 0.5 19 13 38 3 1 1
5. 处理缺失值的其他方法
软件包 | 描 述 |
Hmisc | 包含多种函数,支持简单插补、多重插补和典型变量插补 |
mvnmle | 对多元正态颁数据中缺失值的最大似然估计 |
cat | 对数线性模型中多元类别型变量的多重插补 |
arrayImpute\arraryMissPattern、SeqKnn | 处理微阵列缺失值数据的实用函数 |
longitudinalData | 相关的函数列表,比如对时间序列缺失值进行插补的一系列函数 |
kmi | 处理生存分析缺失值的Kaplan-Meier多重插补 |
mix | 一般位置模型中混合类别型和连续型数据的多重插补 |
pan | 多元面板数据或聚类的多重插补 |
参考资料
R语言:处理缺失值1
R语言:处理缺失值2