R語言:缺失值處理
前言
《數據挖掘:R語言實戰》第5章數據預處理,本章我們將使用mice軟件包中的示例數據集來進行數據預處理演示,由於mice軟件包以軟件包lattice、MASS及nnet為基礎建立,因此在加載mice軟件包前要先安裝、加載這三個軟件包。本節為大家介紹缺失值處理。
缺失值是數據中經常出現的問題,也是任何數據集中都可能出現的問題,無回答、錄入錯誤等調查中常會出現的現象都會導致缺失數據。缺失值通常會用一些特殊符號進行標記,比如9999、1990年1月1日,或者是“*”、“?”、“#”、“$”等符號。
缺失數據會影響分析工作的進行,進而影響統計工作的效率,還會導致分析的偏差。數據使用者、分析者往往缺乏缺失值處理方面的知識,僅僅對數據進行簡單刪除或插補會影響數據規模和數據結構,進而影響分析結果。
目錄
1. 判斷是否存在缺失值
2. 缺失值處理
1. 缺失值與數值比較
在數據預處理中,首先要做的通常是判斷是否存在缺失值。在R語言中缺失值通常以NA表示,可以使用函數is.na判斷缺失值。
#計算nhanes2中缺失值的數量
> sum(is.na(nhanes2))
[1] 27
另一個常用到的函數是complete.cases,用來判斷某一觀測樣本是否完整。
#計算nhanes2中完整樣本的數量
> sum(complete.cases(nhanes2))
[1] 13
兩個函數結果分別表示數據中共有27個缺失值以及數據框中共有13條完整觀測值,即有12條觀測值中存在缺失值。
在存在缺失數據的情況下,需要進一步對數據缺失狀況進行觀測,判斷缺失數據是否隨機。我們可以利用mice包中的md.pattern函數完成這一任務。
#觀測nhanes2中缺失值的情況
> md.pattern(nhanes2)
age hyp bmi chl
13 1 1 1 1 0
1 1 1 0 1 1
3 1 1 1 0 1
1 1 0 0 1 2
7 1 0 0 0 3
0 8 9 10 27
>
其中1表示沒有缺失數據,0表示存在缺失數據。第一行第一列的13表示有13個樣本是完整的,即不存在缺失數據。第一列最后一個7表示有7個樣本少了hyp、bmi、chl三個變量,最后一行表示各個變量缺失的樣本數合計。
對於缺失數據最簡單粗暴的方式,即是直接刪除含有缺失值的樣本,這樣做有時也是最為簡單有效的方法,但前提是缺失數據的比例較少,且缺失數據是隨機出現的,這樣刪除缺失數據后對分析結果影響不大。
另外,也可采取用變量均值或中位數來代替缺失值的方式,其優點在於不會減少樣本信息,處理簡單;其缺點在於當缺失數據不是隨機出現時會產成偏誤。
而多重插補法(Multivariate Imputation)通過變量間的關系對缺失數據進行預測,利用蒙特卡洛方法生成多個完整的數據集,再對這些數據集分別進行分析,最后對分析結果進行匯總處理。
在R語言中,可以通過調用mice包中的mice函數實現,函數的基本形式是:
mice(data, m = 5,...)
其中,data代表一個有缺失值的數據框或矩陣,缺失值用NA表示;m表示插補重數,即生成m個完整數據集,默認值為m=5。
舉個例子,若要構建以chl為因變量,age、hyp、bmi為自變量的線性回歸模型,因為nhanes2數據中存在缺失值,不能直接用來構建模型,因此可以利用mice()函數,通過如下方式構建模型:
> # 生成4組完整的數據庫並賦給imp
> imp=mice(nhanes2,m=4)
iter imp variable
1 1 bmi hyp chl
1 2 bmi hyp chl
1 3 bmi hyp chl
1 4 bmi hyp chl
2 1 bmi hyp chl
2 2 bmi hyp chl
2 3 bmi hyp chl
2 4 bmi hyp chl
3 1 bmi hyp chl
3 2 bmi hyp chl
3 3 bmi hyp chl
3 4 bmi hyp chl
4 1 bmi hyp chl
4 2 bmi hyp chl
4 3 bmi hyp chl
4 4 bmi hyp chl
5 1 bmi hyp chl
5 2 bmi hyp chl
5 3 bmi hyp chl
5 4 bmi hyp chl
> # 生成線性回歸模型
> fit=with(imp,lm(chl~age+hyp+bmi))
> fit
call :
with.mids(data = imp, expr = lm(chl ~ age + hyp + bmi))
call1 :
mice(data = nhanes2, m = 4)
nmis :
age bmi hyp chl
0 9 8 10
analyses :
[[1]]
Call:
lm(formula = chl ~ age + hyp + bmi)
Coefficients:
(Intercept) age2 age3 hyp2
-29.3721 42.0197 60.0936 0.6452
bmi
7.4739
[[2]]
Call:
lm(formula = chl ~ age + hyp + bmi)
Coefficients:
(Intercept) age2 age3 hyp2
10.017 62.164 76.705 -11.433
bmi
5.546
[[3]]
Call:
lm(formula = chl ~ age + hyp + bmi)
Coefficients:
(Intercept) age2 age3 hyp2
34.7142 36.1401 46.6008 -0.3335
bmi
5.1506
[[4]]
Call:
lm(formula = chl ~ age + hyp + bmi)
Coefficients:
(Intercept) age2 age3 hyp2
31.090 46.228 66.794 -5.168
bmi
5.243
> # 對建立的4個模型進行匯總
> pooled=pool(fit)
> # 展示pooled的內容
> summary(pooled)
est se t df
(Intercept) 11.612394 66.290179 0.1751752 10.773211
age2 46.637976 23.213129 2.0091207 9.557044
age3 62.548392 26.015523 2.4042719 9.379841
hyp2 -4.072112 19.618366 -0.2075663 15.608178
bmi 5.853575 2.339205 2.5023781 9.980666
Pr(>|t|) lo 95 hi 95 nmis
(Intercept) 0.86419087 -134.6669203 157.89171 NA
age2 0.07359557 -5.4108898 98.68684 NA
age3 0.03857194 4.0584799 121.03830 NA
hyp2 0.83825159 -45.7462023 37.60198 NA
bmi 0.03136061 0.6401328 11.06702 9
fmi lambda
(Intercept) 0.3555612 0.24608572
age2 0.4016100 0.28824681
age3 0.4086948 0.29476141
hyp2 0.1959925 0.09917185
bmi 0.3850863 0.27308700
>
生成多個完整數據集儲存於imp中,再對imp進行線性回歸,最后用pool函數對回歸結果進行匯總。匯總結果的前面部分和普通回歸結果相似,nmis表示了變量中的缺失數據個數,fmi表示fraction of missing information,即由缺失數據貢獻的變異。
2. 缺失值處理
在對是否存在缺失值進行判斷后,我們將對缺失值的處理方法進行講解。
1.刪除法
在不影響數據結構的情況下,刪除法是最簡單的將缺失數據集轉變成完整數據集的方法。根據數據處理的不同角度,可以將刪除法分為以下4種。
(1)刪除觀測樣本。
(2)刪除變量:當某個變量缺失值較多且對研究目標影響不大時,可以將整個變量整體刪除。
(3)使用完整原始數據分析:當數據存在較多缺失而其原始數據完整時,可以使用原始數據替代現有數據進行分析。
(4)改變權重:當刪除缺失數據會改變數據結構時,通過對完整數據按照不同的權重進行加權,可以降低刪除缺失數據帶來的偏差。
2.插補法
刪除數據雖然簡單易行,但會帶來信息浪費、改變數據結構等問題,因此在條件允許的情況下,找到缺失值的替代值來進行插補,盡可能還原真實數據是更好的方法。
下面介紹均值插補、回歸插補、二階插補、熱平台、冷平台、抽樣填補等單一變量插補,多變量插補是單變量插補的推廣,請讀者自行嘗試。
在插補方法中,最簡單的是從總體中隨機抽取某個樣本代替缺失樣本。
R程序如下:
# 返回nhanes2數據集中第4列為NA的行
> sub=which(is.na(nhanes2[,4])==TRUE)
# 將第4列不為NA的數存入數據集dataTR中
> dataTR=nhanes2[-sub,]
# 將第4列為NA的數存入數據集dataTE中
> dataTE=nhanes2[sub,]
# 在非缺失值中簡單抽樣
> dataTE[,4]=sample(dataTR[,4],length(dataTE[,4]),replace=T)
> dataTE
age bmi hyp chl
1 20-39 NA <NA> 186
4 60-99 NA <NA> 113
10 40-59 NA <NA> 187
11 20-39 NA <NA> 204
12 40-59 NA <NA> 238
15 20-39 29.6 no 131
16 20-39 NA <NA> 186
20 60-99 25.5 yes 229
21 20-39 NA <NA> 206
24 60-99 24.9 no 238
均值法是通過計算缺失值所在變量所有非缺失觀測值的均值,使用均值來代替缺失值的插補方法。
類似的,可以使用中位數、四分位數等進行插補,下面僅以均值法為例來對nhanes2數據集的第4列進行實現。
# 返回nhanes2數據集中第4列為NA的行
> sub=which(is.na(nhanes2[,4])==TRUE)
# 將第四列不為NA的數存入數據集dataTR中
> dataTR=nhanes2[-sub,]
# 將第四列為NA的數存入數據集dataTE中
> dataTE=nhanes2[sub,]
# 用非缺失值的均值代替缺失值
> dataTE[,4]=mean(dataTR[,4])
> dataTE
age bmi hyp chl
1 20-39 NA <NA> 191.4
4 60-99 NA <NA> 191.4
10 40-59 NA <NA> 191.4
11 20-39 NA <NA> 191.4
12 40-59 NA <NA> 191.4
15 20-39 29.6 no 191.4
16 20-39 NA <NA> 191.4
20 60-99 25.5 yes 191.4
21 20-39 NA <NA> 191.4
24 60-99 24.9 no 191.4
由於隨機插補和均值插補中沒有利用到相關變量信息,因此會存在一定偏差,而回歸模型是將需要插補變量作為因變量,其他相關變量作為自變量,通過建立回歸模型預測出因變量的值對缺失變量進行插補。
# 返回nhanes2數據集中第4列為NA的行
> sub=which(is.na(nhanes2[,4])==TRUE)
# 將第4列不為NA的數存入數據集dataTR中
> dataTR=nhanes2[-sub,]
# 將第4列為NA的數存入數據集dataTE中
> dataTE=nhanes2[sub,]
# dataTE數據
> dataTE
age bmi hyp chl
1 20-39 NA <NA> NA
4 60-99 NA <NA> NA
10 40-59 NA <NA> NA
11 20-39 NA <NA> NA
12 40-59 NA <NA> NA
15 20-39 29.6 no NA
16 20-39 NA <NA> NA
20 60-99 25.5 yes NA
21 20-39 NA <NA> NA
24 60-99 24.9 no NA
# 利用dataTR中age為自變量,chl為因變量構建線性回歸模型lm
> lm=lm(chl~age,data=dataTR)
# 利用dataTE中數據按照模型lm對nhanes2中chl中的缺失數據進行預測
> nhanes2[sub,4]=round(predict(lm,dataTE))
# 缺失值處理后的nhanes2的前若6條
> head(nhanes2)
age bmi hyp chl
1 20-39 NA <NA> 169
2 40-59 22.7 no 187
3 20-39 NA no 187
4 60-99 NA <NA> 225
5 20-39 20.4 no 113
6 60-99 NA <NA> 184
熱平台插補是指在非缺失數據集中找到一個與缺失值所在樣本相似的樣本(匹配樣本),利用其中的觀測值對缺失值進行插補。
# 存在缺失值的樣本
> accept=nhanes2[which(apply(is.na(nhanes2),1,sum)!=0),]
# 無缺失值的樣本
> donate=nhanes2[which(apply(is.na(nhanes2),1,sum)==0),]
> accept[1,]
age bmi hyp chl
1 20-39 NA <NA> 169
> donate[1,]
age bmi hyp chl
2 40-59 22.7 no 187
上述程序按照樣本中是否含有缺失值將nhanes2分成存在缺失值和無缺失值兩個數據表,分別命名為accept和donate。對於accept中的每個樣本,熱平台插補就是在donate中找到與該樣本相似的樣本,用相似樣本的對應值代替該樣本的缺失值。如,對於accept中的第2個樣本,插補方法如下:
> accept[2,]
age bmi hyp chl
3 20-39 NA no 187
# 尋找與accept中第2個樣本相似的樣本
> sa=donate[which(donate[,1]==accept[2,1]&donate[,3]==accept[2,3]&donate[,4]==accept[2,4]),]
> sa
age bmi hyp chl
8 20-39 30.1 no 187
# 用找到的樣本的對應值替代缺失值
> accept[2,2]=sa[1,2]
> accept[2,]
age bmi hyp chl
3 20-39 30.1 no 187
在實際操作中,尤其當變量數量很多時,通常很難找到與需要插補樣本完全相同的樣本,此時可以按照某些變量將數據分層,在層中對缺失值使用均值插補,即采取冷平台插補方法。
# 按照變量hyp分層
> level1=nhanes2[which(nhanes2[,3]=="yes"),]
> level1
age bmi hyp chl
14 40-59 28.7 yes 204
17 60-99 27.2 yes 284
18 40-59 26.3 yes 199
20 60-99 25.5 yes 225
# 用層內均值代替第4個樣本的缺失值
> level1[4,4]=mean(level1[1:3,4])
> level1
age bmi hyp chl
14 40-59 28.7 yes 204
17 60-99 27.2 yes 284
18 40-59 26.3 yes 199
20 60-99 25.5 yes 229