Missing data là những giá trị dữ liệu bị thiếu trong dataset được kí hiệu là NA hoặc để trống hoặc 99, .v.v. Nếu dataset của bạn có từ 10% missing data trở lên thì rất nhiều khả năng là các phép phân tích, dự đoán thống kê khó có thể cho được kết quả chính xác.
Có nhiều cách để giải quyết vấn đề missing data sao cho kết quả đáng tin cậy nhất. Trước hết, chúng ta phải biết mức độ “trầm trọng” của missing data lớn đến mức nào, xảy ra với biến số nào và những dòng dữ liệu nào đã bị missing.
Hai packages thường sử dụng để giải quyết vần đề này là VIM (visualization and imputation of missing values) và MICE (Multivariate Imputation via Chained Equations).
Bộ dữ liệu sleep trong package “VIM” được chọn để minh họa cho chủ đề này.
library(VIM)
library(mice)
data(sleep, package="VIM")
head(sleep)
## BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
## 1 6654.000 5712.0 NA NA 3.3 38.6 645 3 5 3
## 2 1.000 6.6 6.3 2.0 8.3 4.5 42 3 1 3
## 3 3.385 44.5 NA NA 12.5 14.0 60 1 1 1
## 4 0.920 5.7 NA NA 16.5 NA 25 5 2 3
## 5 2547.000 4603.0 2.1 1.8 3.9 69.0 624 3 5 4
## 6 10.550 179.5 9.1 0.7 9.8 27.0 180 4 4 4
Dataset ‘sleep’ là bộ dữ liệu về giấc ngủ của một loài động vật có vú, gồm 62 cá thể và 10 biến số:
BodyWgt: Cân nặng BrainWgt: Cân nặng bộ não
NonD: Thời gian ngủ không có giấc mơ
Dream: Thời gian ngủ có giấc mơ
Sleep: Thời gian ngủ tổng cộng
Span
Gest
Pred
Exp
Danger
….
Với head(sleep), rõ ràng ta thấy trong “sleep” có những giá trị bị missing được gán cho chữ NA. Để biết có những biến số nào bị missing ta dùng lệnh sau:
sleep[!complete.cases(sleep),]
## BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
## 1 6654.000 5712.0 NA NA 3.3 38.6 645 3 5 3
## 3 3.385 44.5 NA NA 12.5 14.0 60 1 1 1
## 4 0.920 5.7 NA NA 16.5 NA 25 5 2 3
## 13 0.550 2.4 7.6 2.7 10.3 NA NA 2 1 2
## 14 187.100 419.0 NA NA 3.1 40.0 365 5 5 5
## 19 1.410 17.5 4.8 1.3 6.1 34.0 NA 1 2 1
## 20 60.000 81.0 12.0 6.1 18.1 7.0 NA 1 1 1
## 21 529.000 680.0 NA 0.3 NA 28.0 400 5 5 5
## 24 207.000 406.0 NA NA 12.0 39.3 252 1 4 1
## 26 36.330 119.5 NA NA 13.0 16.2 63 1 1 1
## 30 100.000 157.0 NA NA 10.8 22.4 100 1 1 1
## 31 35.000 56.0 NA NA NA 16.3 33 3 5 4
## 35 0.122 3.0 8.2 2.4 10.6 NA 30 2 1 1
## 36 1.350 8.1 8.4 2.8 11.2 NA 45 3 1 3
## 41 250.000 490.0 NA 1.0 NA 23.6 440 5 5 5
## 47 4.288 39.2 NA NA 12.5 13.7 63 2 2 2
## 53 14.830 98.2 NA NA 2.6 17.0 150 5 5 5
## 55 1.400 12.5 NA NA 11.0 12.7 90 2 2 2
## 56 0.060 1.0 8.1 2.2 10.3 3.5 NA 3 1 2
## 62 4.050 17.0 NA NA NA 13.0 38 3 1 1
Trên đây là tập hợp những rows có ít nhất một NA. Khi dataset của chúng ta lớn và có nhiều NA thì chúng ta cần có một báo cáo tóm tắt về các rows và columns chứa NA. Để có điều đó chúng ta dùng lệnh sau:
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
Giải thích báo cáo:
Với giá trị ’1" cho biết không NA, và “0” là có NA. Cột thứ nhất cho biết số lượng row chứa các giá trị dữ liệu tương ứng bên phải. Cột cuối cùng cho biết có bao nhiêu NA trong dòng tương ứng. Hàng cuối cùng bên dưới cho biết tổng số NA có trong cột tương ứng ở trên.
Như vậy, chúng ta có 42 row không bị NA, có 2 row có 1 NA ở biến số Span, có 3 row có một NA ở biến số Gest, có 9 row có 2 NA ở Dream và NonD. Và lần lượt đến dòng cuối cùng, cho biết có tổng cộng 38 giá trị NA trong sleep, trong đó NonD có 14 NA, Dream có 12 NA và Gest có 4 NA, ….
Với VIM, các NA được biểu diễn bằng biểu đồ cho chúng ta thấy hình ảnh dễ hiểu hơn:
mice_plot <- aggr(sleep, col=c('navyblue','yellow'),
numbers=TRUE, sortVars=TRUE,
labels=names(sleep), cex.axis=.7,
gap=3, ylab=c("Missing data","Pattern"))
##
## Variables sorted by number of missings:
## Variable Count
## NonD 0.22580645
## Dream 0.19354839
## Sleep 0.06451613
## Span 0.06451613
## Gest 0.06451613
## BodyWgt 0.00000000
## BrainWgt 0.00000000
## Pred 0.00000000
## Exp 0.00000000
## Danger 0.00000000
Màu vàng biểu thị NA, màu xanh không phải NA. Biểu đồ bên trái cho thấy phần trăm mà các biến số tương ứng có giá trị NA. Biểu đồ bên phải cho biết phân trăm của các kiểu phối hợp NA giữa các biến số. Cuối cùng là tổng cộng có 67.7% dữ liệu không bị NA. Với mức độ 32.3% missing là khá lớn trong dataset này.
Đến đây chúng ta đã có được một cái nhìn tổng thể về mức độ trầm trọng như thế nào trong vấn đề missing data của bộ dữ liệu mà chúng ta đang có ý định phân tích.
Vì vậy thay thế các giá trị NA như thế nào cho phù hợp là một yêu cầu thiết thực, nếu không thì chỉ còn chưa đến 70% dữ liệu có thể phân tích được mà thôi.
Đơn giản nhất là chúng ta xem kĩ từng NA để hiểu vì sao chúng bị missing. Tra cứu lại tài liệu nguồn như bệnh án nghiên cứu, phiếu điều tra đối tượng, để lấy thông tin bổ sung cho giá trị NA nếu chúng đã bị nhập sót dữ liệu.
Nếu đó là một row nhập lỗi, bị lặp lại, chúng ta xóa row ấy khỏi dataset.
Nếu missing data là rãi rác ở các dòng có tính ngẫu nhiên (MAR: Missing At Random) thì chúng ta có thể thay thế chúng bằng các giá trị có thể là:
MICE giả định rằng dữ liệu bị mất là Missing at Random (MAR), có nghĩa là xác suất mà một giá trị bị thiếu chỉ phụ thuộc vào giá trị quan sát được và có thể dự đoán chúng bằng các giá trị cùng chủng loại. Nó tính dữ liệu missing dựa vào qui luật biến thiên của các biến số trong dataset.
Ví dụ: Giả sử chúng ta có các biến X1, X2 … .Xk. Nếu X1 có các giá trị còn thiếu, thì nó sẽ được hồi quy trên các biến khác từ X2 đến Xk. Các giá trị còn thiếu trong X1 sẽ được thay thế bằng các giá trị mà nó dự đoán từ các biến số còn lại. Tương tự, nếu X2 có các giá trị còn thiếu, thì các biến X1, X3 đến Xk sẽ được sử dụng trong mô hình dự đoán như các biến độc lập. Sau đó, giá trị còn thiếu sẽ được thay thế bằng giá trị dự đoán.
Theo mặc định, hồi quy tuyến tính được sử dụng để dự đoán giá trị missing của biến liên tục. Hồi quy logistic được sử dụng cho giá trị thiếu trong biến rời rạc. Khi chu kỳ này hoàn tất, nhiều bộ dữ liệu được tạo ra. Những bộ dữ liệu này chỉ khác nhau trong các giá trị bị thiếu. Nói chung, đây được coi là một phương pháp hay để xây dựng các mô hình trên các bộ dữ liệu riêng rẽ và có thể kết hợp các kết quả của chúng.
Chính xác, các phương pháp được sử dụng bởi package MICE là:
PMM (Predictive Mean Matching) - Đối với các biến số liên tục Logreg (Logistic Regression) - Đối với các biến nhị phân (với 2 level) Polyreg (hồi qui đa thức Bayesian) - Đối với các biến factor (>= 2 level) Mô hình tỷ lệ chênh (có thứ tự,>= 2 level)
Với sleep, chúng ta thực hành thay thế NA cho các biến liên tục bằng phương pháp “pmm” với m = 5 (multiple imputations), tức là 5 lần thay thế, sau đó chọn ra missing subset nào chúng ta muốn chọn.
imputed_Data <- mice(sleep, m=5, maxit = 50, method = 'pmm', seed = 500, print=FALSE)
head(imputed_Data)
## $call
## mice(data = sleep, m = 5, method = "pmm", maxit = 50, printFlag = FALSE,
## seed = 500)
##
## $data
## BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
## 1 6654.000 5712.00 NA NA 3.3 38.6 645.0 3 5 3
## 2 1.000 6.60 6.3 2.0 8.3 4.5 42.0 3 1 3
## 3 3.385 44.50 NA NA 12.5 14.0 60.0 1 1 1
## 4 0.920 5.70 NA NA 16.5 NA 25.0 5 2 3
## 5 2547.000 4603.00 2.1 1.8 3.9 69.0 624.0 3 5 4
## 6 10.550 179.50 9.1 0.7 9.8 27.0 180.0 4 4 4
## 7 0.023 0.30 15.8 3.9 19.7 19.0 35.0 1 1 1
## 8 160.000 169.00 5.2 1.0 6.2 30.4 392.0 4 5 4
## 9 3.300 25.60 10.9 3.6 14.5 28.0 63.0 1 2 1
## 10 52.160 440.00 8.3 1.4 9.7 50.0 230.0 1 1 1
## 11 0.425 6.40 11.0 1.5 12.5 7.0 112.0 5 4 4
## 12 465.000 423.00 3.2 0.7 3.9 30.0 281.0 5 5 5
## 13 0.550 2.40 7.6 2.7 10.3 NA NA 2 1 2
## 14 187.100 419.00 NA NA 3.1 40.0 365.0 5 5 5
## 15 0.075 1.20 6.3 2.1 8.4 3.5 42.0 1 1 1
## 16 3.000 25.00 8.6 0.0 8.6 50.0 28.0 2 2 2
## 17 0.785 3.50 6.6 4.1 10.7 6.0 42.0 2 2 2
## 18 0.200 5.00 9.5 1.2 10.7 10.4 120.0 2 2 2
## 19 1.410 17.50 4.8 1.3 6.1 34.0 NA 1 2 1
## 20 60.000 81.00 12.0 6.1 18.1 7.0 NA 1 1 1
## 21 529.000 680.00 NA 0.3 NA 28.0 400.0 5 5 5
## 22 27.660 115.00 3.3 0.5 3.8 20.0 148.0 5 5 5
## 23 0.120 1.00 11.0 3.4 14.4 3.9 16.0 3 1 2
## 24 207.000 406.00 NA NA 12.0 39.3 252.0 1 4 1
## 25 85.000 325.00 4.7 1.5 6.2 41.0 310.0 1 3 1
## 26 36.330 119.50 NA NA 13.0 16.2 63.0 1 1 1
## 27 0.101 4.00 10.4 3.4 13.8 9.0 28.0 5 1 3
## 28 1.040 5.50 7.4 0.8 8.2 7.6 68.0 5 3 4
## 29 521.000 655.00 2.1 0.8 2.9 46.0 336.0 5 5 5
## 30 100.000 157.00 NA NA 10.8 22.4 100.0 1 1 1
## 31 35.000 56.00 NA NA NA 16.3 33.0 3 5 4
## 32 0.005 0.14 7.7 1.4 9.1 2.6 21.5 5 2 4
## 33 0.010 0.25 17.9 2.0 19.9 24.0 50.0 1 1 1
## 34 62.000 1320.00 6.1 1.9 8.0 100.0 267.0 1 1 1
## 35 0.122 3.00 8.2 2.4 10.6 NA 30.0 2 1 1
## 36 1.350 8.10 8.4 2.8 11.2 NA 45.0 3 1 3
## 37 0.023 0.40 11.9 1.3 13.2 3.2 19.0 4 1 3
## 38 0.048 0.33 10.8 2.0 12.8 2.0 30.0 4 1 3
## 39 1.700 6.30 13.8 5.6 19.4 5.0 12.0 2 1 1
## 40 3.500 10.80 14.3 3.1 17.4 6.5 120.0 2 1 1
## 41 250.000 490.00 NA 1.0 NA 23.6 440.0 5 5 5
## 42 0.480 15.50 15.2 1.8 17.0 12.0 140.0 2 2 2
## 43 10.000 115.00 10.0 0.9 10.9 20.2 170.0 4 4 4
## 44 1.620 11.40 11.9 1.8 13.7 13.0 17.0 2 1 2
## 45 192.000 180.00 6.5 1.9 8.4 27.0 115.0 4 4 4
## 46 2.500 12.10 7.5 0.9 8.4 18.0 31.0 5 5 5
## 47 4.288 39.20 NA NA 12.5 13.7 63.0 2 2 2
## 48 0.280 1.90 10.6 2.6 13.2 4.7 21.0 3 1 3
## 49 4.235 50.40 7.4 2.4 9.8 9.8 52.0 1 1 1
## 50 6.800 179.00 8.4 1.2 9.6 29.0 164.0 2 3 2
## 51 0.750 12.30 5.7 0.9 6.6 7.0 225.0 2 2 2
## 52 3.600 21.00 4.9 0.5 5.4 6.0 225.0 3 2 3
## 53 14.830 98.20 NA NA 2.6 17.0 150.0 5 5 5
## 54 55.500 175.00 3.2 0.6 3.8 20.0 151.0 5 5 5
## 55 1.400 12.50 NA NA 11.0 12.7 90.0 2 2 2
## 56 0.060 1.00 8.1 2.2 10.3 3.5 NA 3 1 2
## 57 0.900 2.60 11.0 2.3 13.3 4.5 60.0 2 1 2
## 58 2.000 12.30 4.9 0.5 5.4 7.5 200.0 3 1 3
## 59 0.104 2.50 13.2 2.6 15.8 2.3 46.0 3 2 2
## 60 4.190 58.00 9.7 0.6 10.3 24.0 210.0 4 3 4
## 61 3.500 3.90 12.8 6.6 19.4 3.0 14.0 2 1 1
## 62 4.050 17.00 NA NA NA 13.0 38.0 3 1 1
##
## $m
## [1] 5
##
## $nmis
## BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred
## 0 0 14 12 4 4 4 0
## Exp Danger
## 0 0
##
## $imp
## $imp$BodyWgt
## NULL
##
## $imp$BrainWgt
## NULL
##
## $imp$NonD
## 1 2 3 4 5
## 1 3.2 3.2 3.2 2.1 2.1
## 3 10.9 11.0 11.0 10.6 11.0
## 4 13.2 15.2 15.2 14.3 13.2
## 14 3.2 3.3 3.2 3.2 2.1
## 21 7.4 8.2 8.1 8.4 8.4
## 24 8.6 10.8 10.9 8.4 9.1
## 26 10.4 10.9 10.9 10.8 10.9
## 30 8.4 10.0 8.1 9.1 8.4
## 31 8.3 6.3 7.7 5.2 4.9
## 41 10.8 7.4 8.4 9.7 11.9
## 47 10.8 11.0 11.0 10.6 8.4
## 53 2.1 3.3 3.3 2.1 3.3
## 55 10.4 10.9 8.2 8.3 8.3
## 62 10.6 11.0 10.9 13.8 10.9
##
## $imp$Dream
## 1 2 3 4 5
## 1 0.5 0.0 0.5 2.0 0.5
## 3 1.4 1.5 1.4 2.0 1.5
## 4 3.1 1.3 1.3 2.2 3.1
## 14 0.5 0.5 0.5 0.3 0.9
## 24 3.4 1.3 1.2 3.9 2.6
## 26 2.4 2.0 2.2 2.0 2.0
## 30 2.3 0.9 2.8 1.8 2.3
## 31 0.8 2.0 0.5 0.8 0.6
## 47 1.8 1.5 1.5 1.9 3.4
## 53 0.6 0.5 0.0 0.6 0.5
## 55 0.6 0.0 2.6 2.7 2.6
## 62 2.0 2.2 2.3 3.9 2.3
##
## $imp$Sleep
## 1 2 3 4 5
## 21 8.2 8.3 8.3 8.4 8.6
## 31 9.7 8.0 8.4 5.4 5.4
## 41 12.5 8.3 9.1 10.7 13.2
## 62 13.0 13.2 12.8 17.4 13.0
##
## $imp$Span
## 1 2 3 4 5
## 4 3.2 3.0 2.6 12.0 3.5
## 13 19.0 24.0 5.0 2.6 19.0
## 35 24.0 7.6 7.0 24.0 16.3
## 36 3.0 13.0 3.0 4.5 3.0
##
## $imp$Gest
## 1 2 3 4 5
## 13 42 200 19 19 19
## 19 112 164 230 225 115
## 20 12 17 120 14 12
## 56 25 17 38 21 200
##
## $imp$Pred
## NULL
##
## $imp$Exp
## NULL
##
## $imp$Danger
## NULL
##
##
## $method
## BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred
## "pmm" "pmm" "pmm" "pmm" "pmm" "pmm" "pmm" "pmm"
## Exp Danger
## "pmm" "pmm"
Mỗi một biến số có NA, MICE sẽ cho ra 5 subsets có thể thay thế được. Trong 5 lần imputations trên, tôi muốn chọn subset thứ 3 để thay thế chính thức cho những NA trong “sleep”, vì thế tôi dùng lệnh như sau:
completeData <- complete(imputed_Data,3)
head(completeData, 20)
## BodyWgt BrainWgt NonD Dream Sleep Span Gest Pred Exp Danger
## 1 6654.000 5712.0 3.2 0.5 3.3 38.6 645 3 5 3
## 2 1.000 6.6 6.3 2.0 8.3 4.5 42 3 1 3
## 3 3.385 44.5 11.0 1.4 12.5 14.0 60 1 1 1
## 4 0.920 5.7 15.2 1.3 16.5 2.6 25 5 2 3
## 5 2547.000 4603.0 2.1 1.8 3.9 69.0 624 3 5 4
## 6 10.550 179.5 9.1 0.7 9.8 27.0 180 4 4 4
## 7 0.023 0.3 15.8 3.9 19.7 19.0 35 1 1 1
## 8 160.000 169.0 5.2 1.0 6.2 30.4 392 4 5 4
## 9 3.300 25.6 10.9 3.6 14.5 28.0 63 1 2 1
## 10 52.160 440.0 8.3 1.4 9.7 50.0 230 1 1 1
## 11 0.425 6.4 11.0 1.5 12.5 7.0 112 5 4 4
## 12 465.000 423.0 3.2 0.7 3.9 30.0 281 5 5 5
## 13 0.550 2.4 7.6 2.7 10.3 5.0 19 2 1 2
## 14 187.100 419.0 3.2 0.5 3.1 40.0 365 5 5 5
## 15 0.075 1.2 6.3 2.1 8.4 3.5 42 1 1 1
## 16 3.000 25.0 8.6 0.0 8.6 50.0 28 2 2 2
## 17 0.785 3.5 6.6 4.1 10.7 6.0 42 2 2 2
## 18 0.200 5.0 9.5 1.2 10.7 10.4 120 2 2 2
## 19 1.410 17.5 4.8 1.3 6.1 34.0 230 1 2 1
## 20 60.000 81.0 12.0 6.1 18.1 7.0 120 1 1 1
Đến đây chúng ta đã có bộ dữ liệu hoàn thiện “completeData” có thể được sử dụng để phân tích, xây dựng mô hình hồi qui…
Cám ơn các bạn đã đọc bài viết này. Mong nhận được những lời góp ý, bàn luận để cùng học tập và tiến bộ.