한 가지 해결책은 mice
패키지에 대한 사용자 정의 대치 기능을 작성하는 것 입니다. 패키지는이를 위해 준비되었으며 설정은 놀라 울 정도로 고통이 없습니다.
먼저 제안 된대로 데이터를 설정합니다.
dat=data.frame(x1=c(21, 50, 31, 15, 36, 82, 14, 14, 19, 18, 16, 36, 583, NA,NA,NA, 50, 52, 26, 24),
x2=c(0, NA, 18,0, 19, 0, NA, 0, 0, 0, 0, 0, 0,NA,NA, NA, 22, NA, 0, 0),
x3=c(0, 0, 0, 0, 0, 54, 0 ,0, 0, 0, 0, 0, 0, NA, NA, NA, NA, 0, 0, 0))
다음으로 mice
패키지 를로드하고 기본적으로 어떤 방법을 선택하는지 확인하십시오.
library(mice)
# Do a non-imputation
imp_base <- mice(dat, m=0, maxit = 0)
# Find the methods that mice chooses
imp_base$method
# Returns: "pmm" "pmm" "pmm"
# Look at the imputation matrix
imp_base$predictorMatrix
# Returns:
# x1 x2 x3
#x1 0 1 1
#x2 1 0 1
#x3 1 1 0
는 pmm
의미 예측 평균 일치 연속 변수를 전가하기위한 아마도 가장 인기 전가 알고리즘 -. 회귀 모형을 사용하여 예측값을 계산하고 예측값에 가장 가까운 5 개의 요소를 선택합니다 ( 유클리드 거리 기준 ). 이러한 선택된 요소를 공여자 풀이라고하며 최종 값은이 공여자 풀에서 무작위로 선택됩니다.
예측 행렬에서 우리는 메소드가 제한에 관심있는 변수를 전달 받는다는 것을 알았습니다. 행은 목표 변수이고 열은 예측 변수입니다. x1에 x3 열에 1이 없으면 행렬에 이것을 추가해야합니다.imp_base$predictorMatrix["x1","x3"] <- 1
이제 재미있는 부분으로 대치 방법을 생성합니다. 여기에서 기준을 충족하지 않으면 모든 값을 버리는 다소 조잡한 방법을 선택했습니다. 이로 인해 루프 시간이 길어지고 유효한 대치를 유지하고 나머지 대치 만 다시 실행하는 것이 잠재적으로 더 효율적일 수 있지만 조금 더 조정해야합니다.
# Generate our custom methods
mice.impute.pmm_x1 <-
function (y, ry, x, donors = 5, type = 1, ridge = 1e-05, version = "",
...)
{
max_sum <- sum(max(x[,"x2"], na.rm=TRUE),
max(x[,"x3"], na.rm=TRUE))
repeat{
vals <- mice.impute.pmm(y, ry, x, donors = 5, type = 1, ridge = 1e-05,
version = "", ...)
if (all(vals < max_sum)){
break
}
}
return(vals)
}
mice.impute.pmm_x2 <-
function (y, ry, x, donors = 5, type = 1, ridge = 1e-05, version = "",
...)
{
repeat{
vals <- mice.impute.pmm(y, ry, x, donors = 5, type = 1, ridge = 1e-05,
version = "", ...)
if (all(vals == 0 | vals >= 14)){
break
}
}
return(vals)
}
mice.impute.pmm_x3 <-
function (y, ry, x, donors = 5, type = 1, ridge = 1e-05, version = "",
...)
{
repeat{
vals <- mice.impute.pmm(y, ry, x, donors = 5, type = 1, ridge = 1e-05,
version = "", ...)
if (all(vals == 0 | vals >= 16)){
break
}
}
return(vals)
}
메소드 정의가 완료되면 이전 메소드를 간단히 변경합니다. 단일 변수 만 변경하려면 간단히 사용할 수 imp_base$method["x2"] <- "pmm_x2"
있지만이 예제에서는 모두 변경합니다 (이름은 필요하지 않음).
imp_base$method <- c(x1 = "pmm_x1", x2 = "pmm_x2", x3 = "pmm_x3")
# The predictor matrix is not really necessary for this example
# but I use it just to illustrate in case you would like to
# modify it
imp_ds <-
mice(dat,
method = imp_base$method,
predictorMatrix = imp_base$predictorMatrix)
이제 세 번째 대치 된 데이터 세트를 살펴 보겠습니다.
> complete(imp_ds, action = 3)
x1 x2 x3
1 21 0 0
2 50 19 0
3 31 18 0
4 15 0 0
5 36 19 0
6 82 0 54
7 14 0 0
8 14 0 0
9 19 0 0
10 18 0 0
11 16 0 0
12 36 0 0
13 583 0 0
14 50 22 0
15 52 19 0
16 14 0 0
17 50 22 0
18 52 0 0
19 26 0 0
20 24 0 0
좋아, 그 일을 해. 주류 함수를 피기 백하고 의미있는 제한을 추가 할 수 있기 때문에이 솔루션을 좋아합니다.
최신 정보
주석에 언급 된 엄격한 제한 @ t0x1n을 적용하기 위해 래퍼 함수에 다음 기능을 추가 할 수 있습니다.
- 이전에 부분적으로 성공적인 실행의 데이터가 삭제되지 않도록 루프 중에 유효한 값을 저장하십시오.
- 무한 루프를 피하기위한 이스케이프 메커니즘
- 적합한 성냥을 찾지 않고 x 번 시도한 후에 기증자 풀을 팽창시킵니다 (이는 주로 pmm에 적용됨)
이로 인해 약간 더 복잡한 래퍼 함수가 생성됩니다.
mice.impute.pmm_x1_adv <- function (y, ry,
x, donors = 5,
type = 1, ridge = 1e-05,
version = "", ...) {
# The mice:::remove.lindep may remove the parts required for
# the test - in those cases we should escape the test
if (!all(c("x2", "x3") %in% colnames(x))){
warning("Could not enforce pmm_x1 due to missing column(s):",
c("x2", "x3")[!c("x2", "x3") %in% colnames(x)])
return(mice.impute.pmm(y, ry, x, donors = 5, type = 1, ridge = 1e-05,
version = "", ...))
}
# Select those missing
max_vals <- rowSums(x[!ry, c("x2", "x3")])
# We will keep saving the valid values in the valid_vals
valid_vals <- rep(NA, length.out = sum(!ry))
# We need a counter in order to avoid an eternal loop
# and for inflating the donor pool if no match is found
cntr <- 0
repeat{
# We should be prepared to increase the donor pool, otherwise
# the criteria may become imposs
donor_inflation <- floor(cntr/10)
vals <- mice.impute.pmm(y, ry, x,
donors = min(5 + donor_inflation, sum(ry)),
type = 1, ridge = 1e-05,
version = "", ...)
# Our criteria check
correct <- vals < max_vals
if (all(!is.na(valid_vals) |
correct)){
valid_vals[correct] <-
vals[correct]
break
}else if (any(is.na(valid_vals) &
correct)){
# Save the new valid values
valid_vals[correct] <-
vals[correct]
}
# An emergency exit to avoid endless loop
cntr <- cntr + 1
if (cntr > 200){
warning("Could not completely enforce constraints for ",
sum(is.na(valid_vals)),
" out of ",
length(valid_vals),
" missing elements")
if (all(is.na(valid_vals))){
valid_vals <- vals
}else{
valid_vals[is.na(valid_vals)] <-
vals[is.na(valid_vals)]
}
break
}
}
return(valid_vals)
}
제안 된 데이터 세트가 모든 경우에 대한 제한 조건을 누락하지 않고 실패했을 가능성이 높습니다 . 동작을 시작하기 전에 루프 길이를 400-500으로 늘려야합니다. 나는 이것이 의도하지 않은 것으로 가정하고, 대치가 실제 데이터 생성 방법을 모방해야합니다.
최적화
인수 ry
에는 비결 측 값이 포함되어 있으며 적절한 대치로 찾은 요소를 제거하여 루프 속도를 높일 수는 있지만 내부 함수에 익숙하지 않기 때문에 이것을 삼가했습니다.
완전히 채우는 데 시간이 걸리는 강력한 제약 조건이있을 때 가장 중요한 것은 대치 를 병렬화하는 것입니다 ( CrossValidated에 대한 내 답변 참조 ). 오늘날 대부분의 컴퓨터에는 4-8 개의 코어가 있으며 R은 기본적으로 그 중 하나만 사용합니다. 코어 수를 두 배로 늘림으로써 시간을 절반으로 줄일 수 있습니다.
대치시 누락 된 매개 변수
x2
대치 시점에서 누락되는 문제와 관련하여 마우스는 실제로 누락 된 값을 x
-에 공급하지 않습니다 data.frame
. 쥐 방법은 시작시 어떤 임의의 값으로 채우는 포함한다. 대치의 체인 부분은이 초기 값의 영향을 제한합니다. mice
-function 을 보면 대치 호출 ( mice:::sampler
-function) 이전에이를 찾을 수 있습니다 .
...
if (method[j] != "") {
for (i in 1:m) {
if (nmis[j] < nrow(data)) {
if (is.null(data.init)) {
imp[[j]][, i] <- mice.impute.sample(y,
ry, ...)
}
else {
imp[[j]][, i] <- data.init[!ry, j]
}
}
else imp[[j]][, i] <- rnorm(nrow(data))
}
}
...
은 data.init
에 공급 될 수있는 mice
기능 및 mice.imput.sample는 기본 샘플링 절차이다.
방문 순서
방문 순서가 중요한 경우 mice
-function이 대치를 실행하는 순서를 지정할 수 있습니다 . 기본값은 1:ncol(data)
이지만 원하는 visitSequence
것을으로 설정할 수 있습니다 .
0 or 16 or >= 16
로0 or >= 16
부터>=16
값을 포함한다16
. 그것이 당신의 의미를 망치지 않기를 바랍니다. 동일0 or 14 or >= 14