::nhanes mice
MICE 소개
Multiple imputation은 평균(mean)이나 중앙값(median) 등 하나의 값으로 결측값을 채워넣는 single imputation과 달리, 결측치(NA
)를 여러가지 변수를 고려하여 채워넣는 방법입니다. 즉, NA
가 있는 변수 이외의 다른 변수들까지 함께 고려하여, 채워넣을 변수를 지정하는 방법입니다.
R에는 multiple imputation을 도와주는 대표적인 패키지인 mice
가 있습니다. mice
는 Multivariate Imputation by Chained Equations 의 약자입니다.
mice
를 통해 연속형, 이분형, 범주형 등 다양한 변수들의 결측값들을 채워넣을 수 있습니다.
설치
MICE 를 사용하기 위한 패키지는 아래와 같습니다. mice
패키지를 통해 MICE를 진행하도록 하겠습니다.
mice
를 활용한 imputation 매커니즘은 아래의 그림과 같습니다.
mice()
: 결측치가 있는 불완전한 데이터에 대해 결측치 대체를 진행합니다. 이 때 결측치가 대체된 여러 개의 데이터를 생성합니다.with()
: 결측치가 대체된 각각의 데이터를 활용해 분석을 진행합니다.결측치가 대체된 데이터마다 분석결과가 만들어집니다 (mira, Multiply imputed repeated analysis).pool()
: 여러 개의 분석 결과를 합칩니다 (mipo, multiply imputed polled object).
데이터 살펴보기
mice
에 내장되어 있는 nhanes
데이터를 이용하도록 하겠습니다.
우선 데이터의 어떤 변수에 NA
가 있는지, 결측값의 규칙을 확인할 수 있습니다.
md.pattern(nhanes)
age hyp bmi chl
13 1 1 1 1 0
3 1 1 1 0 1
1 1 1 0 1 1
1 1 0 0 1 2
7 1 0 0 0 3
0 8 9 10 27
위 코드를 실행하게 되면, 테이블과 그래프가 함께 출력됩니다.
테이블의 경우, 1이 NA
가 아닌 경우, 0이 NA
인 경우를 의미합니다.
좀 더 직관적으로 NA
의 패턴을 이해하려면 그래프를 보는 것이 좋습니다.
위의 그림에서 파란 색은 값이 존재하는 것이고, 빨간색이 NA
인 부분입니다. 그래프를 해석하면 다음과 같습니다.
맨 위는 column별 이름입니다.
오른쪽의 번호는
NA
가 있는 개수를 규칙으로 번호를 매긴 것입니다. 예를 들어 0은 age ~ chl까지 하나도 결측치가 없는 것을 의미합니다. 1의 경우에는 4가지 column중NA
가 한 군데 존재하는 것을 의미합니다. 3의 경우 4가지 column 중 3개에서NA
가 있는 경우를 의미합니다.왼쪽의 번호는 데이터에서 오른쪽의 규칙에 해당하는 row(행)들이 몇 개가 있는지를 나타냅니다. 예를 들어 결측치가 하나도 없는 행은 전체 데이터에서 총 13개이고, 결측치가
hyp
,bmi
,chl
에 있는 경우는 총 7개의 행이 있다는 것입니다.맨 아래의 숫자 (0, 8, 9, 10)은 각 column별로 존재하는
NA
의 합입니다.
Imputation
이제 mice()
를 이용하여 NA
를 채워넣어보도록 하겠습니다. mice()
에서 인자를 설정해줄 수 있는데, 다음과 같습니다.
method
: 결측치를 채우는 imputation 방법. 지정해주는 값에 따라 single imputation이 될 수도, multiple imputation이 될 수도 있음.single imputation: mean, median, norm.predict 등
multiple imputation: pmm, rf, cart 등
m
:NA
를 채운 multiple imputation 데이터셋의 수maxit
: multiple imputation 값을 지정할 때 iteration 횟수seed
: 동일한 결과 출력을 위한 난수 지정
m
의 경우 imputation 된 데이터의 개수인데, m
이 높을수록 정확성이 올라가지만, imputation 되는 데 시간이 많이 소요됩니다.
maxit
의 경우, MCMC(Markov Chain Monte Carlo) 알고리즘을 이용해 반복을 하게 되는데, 이 때 반복할 횟수를 지정해주게 됩니다. maxit
이 높을수록 알고리즘의 수렴도가 개선되지만, m
과 마찬가지로 계산시간이 오래 걸릴 수 있습니다.
mice 패키지의 창시자 Van Buuren (2018)은 “iteration의 수는 변수 간 상관관계와 변수의 결측 비율에 따라 달라진다”고 이야기했습니다. 그는 또한 5-20번의 반복이면 결과가 제대로 수렴할 것이라고 이야기했습니다.
Monte Carlo
통계적인 수치를 얻기 위해 수행하는 시뮬레이션. 통계학의 특성 상, 무수히 많은 시도를 거쳐야 정답을 파악할 수 있지만, 현실적으로는 불가능하기 때문에 유한한 시도를 통해 정답을 추정하는 것.
Markov Chain
어떤 상태에서 다른 상태로 넘어갈 때, 바로 전 단계의 상태에만 영향을 받는 확률 과정.
예시: 어제 짜장면을 먹은 사람의 경우, 오늘 면 종류의 음식을 먹지 않을 것
MCMC를 수행한다는 것은 첫 샘플을 랜덤하게 선정한 뒤, 그 다음의 샘플링이 추천되는 방식의 시도를 무수하게 해보는 것.
출처: https://angeloyeo.github.io/2020/09/17/MCMC.html
<- mice(nhanes,
imp method = "pmm",
maxit = 5,
m = 5,
seed = 2023,
printFlag = F)
imp
Class: mids
Number of multiple imputations: 5
Imputation methods:
age bmi hyp chl
"" "pmm" "pmm" "pmm"
PredictorMatrix:
age bmi hyp chl
age 0 1 1 1
bmi 1 0 1 1
hyp 1 1 0 1
chl 1 1 1 0
imp
는 mice
객체입니다. multiple imputation 횟수와 함께 imputation methods가 등장합니다.
imp
객체는 NA가 채워진 데이터는 물론, imputation 이전 데이터, 채워진 값, NA의 개수, 반복횟수 등의 값을 갖고 있습니다. 예를 들어 imp$method
를 통해 변수별 imputation 방법을 확인할 수 있습니다.
attributes(imp)
$names
[1] "data" "imp" "m" "where"
[5] "blocks" "call" "nmis" "method"
[9] "predictorMatrix" "visitSequence" "formulas" "post"
[13] "blots" "ignore" "seed" "iteration"
[17] "lastSeedValue" "chainMean" "chainVar" "loggedEvents"
[21] "version" "date"
$class
[1] "mids"
$method imp
age bmi hyp chl
"" "pmm" "pmm" "pmm"
mice의 imputation methods는 다양합니다 (methods(mice)
참고).
mice()
함수에서 method 인자를 통해 imputation 방법을 지정해줄 수도 있습니다.
기본적으로 mice()
는 연속형 변수에 대해서는 pmm
을, 범주형 변수에 대해서는 logreg
를 적용해 NA
를 채워넣습니다.
범주형 변수에 대해 자동으로 logreg
를 적용하기 위해서는 해당 변수를 character
또는 factor
로 변경해주어야 합니다.
$hyp <- as.factor(nhanes$hyp)
nhanes<- mice(nhanes, method = c("","pmm","logreg","pmm"), printFlag = F)
imp2 imp2
Class: mids
Number of multiple imputations: 5
Imputation methods:
age bmi hyp chl
"" "pmm" "logreg" "pmm"
PredictorMatrix:
age bmi hyp chl
age 0 1 1 1
bmi 1 0 1 1
hyp 1 1 0 1
chl 1 1 1 0
pmm
은 hot deck 방법 중 하나입니다. 이 때, hot deck 방법이란, NA
가 아닌 데이터를 다른 변수와 매칭시켜 NA
를 채워넣는 방법입니다. 쉽게 말해서, NA
가 있는 행의 데이터의 다른 열을 바탕으로 NA
의 행을 채워넣는 것을 말합니다.
pmm
알고리즘은 쉽게 말해, 특정 변수의 NA
가 아닌 값과 다른 변수를 활용하여 NA
의 값을 채워넣는 것입니다. 예를 들어 nhanes
데이터의 bmi
변수에 결측치가 있어 이를 채워넣는다고 했을 때, age
와 bmi
의 관계를 고려하여 bmi
의 NA
를 채워넣는 것입니다.
좀더 디테일하게 pmm
알고리즘의 과정을 살펴보겠습니다.
bmi
변수와 age 변수를 활용하여 regression을 통해 age에 대한 회귀계수 \(\hat{\beta}_{bmi}\) 을 계산합니다.베이지안 회귀분석을 통해 age에 대한 회귀계수 \(\bar{\beta}_{bmi}\) 를 계산합니다.
\(\hat{\beta}_{bmi}\)를 바탕으로 결측치가 아닌 bmi 값들에 대한 관측값 \(bmi_{obs}\)을 예측합니다. 또한 결측치 bmi 값들에 대한 \(bmi_{pred}\) 를 계산합니다. 여기서 \(bmi_{pred}\) 값이 각각 21.5, 23.8, 28.3이 나왔다고 가정하겠습니다.
\(bmi_{obs}\) 와 \(bmi_{pred}\) 의 차이를 구하여 가장 낮은 차이를 갖는 값들을 구합니다. 예를 들어 첫 번째 \(bmi_{pred}\) 값인 21.5와의 차이를 계산했을 때, 1.4, 1.5, 1.7 순으로 낮은 값을 갖습니다.
\(age\) \(bmi\) \(bmi_{obs}\) \(difference\) 1 NA NA NA 2 22.7 23.0 1.5 1 NA NA NA 3 NA NA NA 1 20.4 20.7 1.7 1 22.5 22.9 1.4 1 30.1 30.7 9.2 이후, 낮은 값을 갖는 \(bmi_{obs}\) 의 값인 23.0, 20.7, 22.9 등이 랜덤하게 선택되어,
bmi
의NA
를 채우게 됩니다.
이처럼 pmm
알고리즘의 장점은 NA
를 비현실적인 데이터로 채우는 것이 아니라, NA
가 아닌 관측되는 값 중에서 채워넣는다는 것입니다.
logreg
방식도 pmm
과 마찬가지로 진행이 됩니다.
mice로 NA
를 채워준 이후, 원래 데이터들처럼 잘 채워졌는지 확인하기 위해서 stripplot()
을 통해 분포를 확인해볼 수 있습니다. 파란 점이 관측값, 붉은 점이 NA
에서 채워진 값들입니다.
그래프를 봤을 때, imputation된 값들이 일반 관측치들과 거의 유사한 분포를 띄고 있는 것을 확인할 수 있습니다.
stripplot(imp2,
data = chl~.imp,
pch=20,
cex = 2)
Modeling
with
함수를 통해 imputation 객체 내에 있는 결측치 대체 데이터별 모델링을 수행합니다. mice()에서 지정된 imputation 수 (default=5) 별로 각각 모델링이 됩니다.
<- with(imp2, lm(chl ~ bmi + age))
fit fit
call :
with.mids(data = imp2, expr = lm(chl ~ bmi + age))
call1 :
mice(data = nhanes, method = c("", "pmm", "logreg", "pmm"), printFlag = F)
nmis :
age bmi hyp chl
0 9 8 10
analyses :
[[1]]
Call:
lm(formula = chl ~ bmi + age)
Coefficients:
(Intercept) bmi age
-11.89 5.44 35.63
[[2]]
Call:
lm(formula = chl ~ bmi + age)
Coefficients:
(Intercept) bmi age
42.963 3.644 32.914
[[3]]
Call:
lm(formula = chl ~ bmi + age)
Coefficients:
(Intercept) bmi age
-53.261 6.587 36.017
[[4]]
Call:
lm(formula = chl ~ bmi + age)
Coefficients:
(Intercept) bmi age
26.877 5.038 19.503
[[5]]
Call:
lm(formula = chl ~ bmi + age)
Coefficients:
(Intercept) bmi age
15.417 4.626 31.404
Pooling
마지막으로 풀링을 통해, 앞서 만든 5개의 imputation 된 데이터들의 회귀계수, 신뢰 구간, p-value 등을 계산할 수 있습니다.
<- pool(fit)
fit_pooled summary(fit_pooled, conf.int = T)
데이터 추출
complete()
를 통해 imputation 된 데이터를 내보낼 수 있습니다. mice()
시 m
(imputation 횟수)을 5로 주었기 때문에 1~5까지의 imputation 데이터가 존재합니다.
일반적으로 결측치가 대체된 데이터셋은 “long” 을 이용해 데이터를 추출하여 요약통계량을 계산합니다. “long”을 이용하면 5개의 데이터셋이 행 단위로 붙게 됩니다.
complete()
사용 시, 1~5번 중 하나를 선택하여 데이터셋을 사용하는 것은 잘못된 방법입니다.
<- complete(imp2, "long") dt_imp
기술통계량 계산
해당 부분은 아직까지 공부 중입니다. 확인해본 결과, 아래의 방법들로 기술통계량을 계산할 수는 있으나, 생각보다 번거롭습니다. 더 나은 함수나 패키지가 있는지 확인이 되면 수정하도록 하겠습니다!
지금까지는 mice
를 통해 회귀분석 등의 모델링을 하는 방법에 대해 살펴보았습니다.
이제 문제는 multiple imputation된 데이터들을 어떻게 종합하여 baseline table 등을 만들 것인지 입니다. multiple imputation된 데이터에서 각 변수별 기술통계량 또는 요약통계량(descriptive statistics)을 계산하는 방법은 Rubin’s rule을 따라야 합니다.
Rubin’s Rules (RR) 이란 평균, 회귀계수, 표준오차, 신뢰 구간, p-value와 같은 파라미터 측정치들을 풀링하기 위해 고안된 규칙입니다.
한마디로 여러 번 진행된 imputation의 값들을 반영하기 위해, 풀링하여 계산하여야 한다는 뜻입니다.
t-test
multiple imputation 을 위한 t-tests는 MKmisc
패키지의 mi.t.test()
를 이용해 가능합니다. 다만 MKmisc
패키지를 설치하기 위해서는 BiocMananger
를 우선 설치해야 합니다. 그 다음 limma
를 설치해주어야 MKmisc
를 설치할 수 있습니다.
install.packages("BiocManager")
::install("limma")
BiocManagerinstall.packages("MKmisc")
library(MKmisc)
mi.t.test()
에 들어가는 값은 complete("long")
을 이용해 추출한 전체 데이터를 리스트로 변환한 값, 연속형 변수 x
, 범주형 종속형 변수 y
입니다.
library(MKmisc)
<- split(dt_imp, dt_imp$.imp)
dt_imp_list ::mi.t.test(dt_imp_list, x='bmi', y="hyp") MKmisc
Multiple Imputation Welch Two Sample t-test
data: Variable bmi: group 1 vs group 2
t = -0.020371, df = 8.7977, p-value = 0.9842
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
-3.954949 3.884601
sample estimates:
mean (1) SD (1) mean (2) SD (2)
26.758382 4.664684 26.793556 3.600881
chi-square
multiple imputation 데이터에 카이제곱 검정을 수행하기 위해서는 miceadds
패키지의 micombine.chisquare()
를 이용합니다.
install.packages("miceadds")
library(miceadds)
<- unique(dt_imp$.imp)
imps $hyp <- as.character(dt_imp$hyp) |> as.numeric()
dt_imp<- lapply(imps, \(x)
mi_chisq xtabs(hyp ~ age, dt_imp, subset = imps==x)) |>
lapply(chisq.test)
1]]$statistic mi_chisq[[
X-squared
7.258065
sapply(mi_chisq, \(x) x$statistic) |> miceadds::micombine.chisquare(df=2, display = T)
Combination of Chi Square Statistics for Multiply Imputed Data
Using 5 Imputed Data Sets
F(2, 7.94)=-0.111 p=1
ANOVA
ANOVA 또한 miceadds
패키지를 이용합니다. mi.anova()
를 이용합니다.
mi.anova(imp2, formula = "bmi ~ age")
Univariate ANOVA for Multiply Imputed Data (Type 2)
lm Formula: bmi ~ age
R^2=0.2115
..........................................................................
ANOVA Table
SSQ df1 df2 F value Pr(>F) eta2 partial.eta2
age 84.80682 1 558.8433 5.5094 0.01926 0.21146 0.21146
Residual 316.24166 NA NA NA NA NA NA
참고자료
https://data.library.virginia.edu/getting-started-with-multiple-imputation-in-r/
https://angeloyeo.github.io/2020/09/17/MCMC.html
https://bookdown.org/mwheymans/bookmi/data-analysis-after-multiple-imputation.html
https://bookdown.org/mwheymans/bookmi/rubins-rules.html
https://nerler.github.io/EP16_Multiple_Imputation/slide/03_analysis_and_pooling.pdf