Bir çözüm, mice
paket için kendi özel imputation işlevlerinizi yazmaktır . Paket bunun için hazırlanmıştır ve kurulum şaşırtıcı derecede acısızdır.
Öncelikle verileri önerildiği gibi ayarlıyoruz:
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))
Sonra mice
paketi yükler ve varsayılan olarak hangi yöntemleri seçtiğini görürüz:
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
Açılımı öngörü ortalama eşleştirme sürekli değişkenler imputing için muhtemelen en popüler töhmet algoritması -. Bir regresyon modeli kullanarak tahmin edilen değeri hesaplar ve tahmin edilen değere en yakın 5 elemanı seçer ( Öklid mesafesine göre ). Bu seçilen elemanlara donör havuzu denir ve nihai değer bu donör havuzundan rastgele seçilir.
Tahmin matrisinden, yöntemlerin kısıtlamalar için ilgi çekici değişkenleri aldığını görüyoruz. Satırın hedef değişken ve sütun öngörücüler olduğunu unutmayın. X1'in x3 sütununda 1 yoksa, bunu matriste eklememiz gerekir:imp_base$predictorMatrix["x1","x3"] <- 1
Şimdi eğlenceli kısma, çarpma yöntemlerini üretiyoruz. Burada, kriterleri karşılamayan tüm değerleri attığım oldukça kaba bir yöntem seçtim. Bu, uzun döngü süresine neden olabilir ve geçerli impütasyonları korumak ve sadece geri kalanları yeniden yapmak potansiyel olarak daha verimli olabilir, ancak biraz daha tweaking gerektirir.
# 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)
}
Yöntemleri tanımladıktan sonra, önceki yöntemleri basitçe değiştiriyoruz. Sadece tek bir değişkeni değiştirmek istiyorsanız, sadece kullanabilirsiniz, imp_base$method["x2"] <- "pmm_x2"
ancak bu örnek için hepsini değiştireceğiz (adlandırma gerekli değildir):
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)
Şimdi üçüncü gizli veri kümesine bir göz atalım:
> 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
Tamam, iş bu. Bu çözümü beğendim, çünkü ana işlevlerin üstüne geri dönebilir ve sadece anlamlı bulduğunuz kısıtlamaları ekleyebilirsiniz.
Güncelleme
Yorumlarda belirtilen titiz kısıtlamaları @ t0x1n zorlamak için, sarma işlevine aşağıdaki yetenekleri eklemek isteyebiliriz:
- Önceki, kısmen başarılı çalışmalardan alınan verilerin atılmaması için döngüler sırasında geçerli değerleri kaydedin
- Sonsuz döngülerden kaçınmak için bir kaçış mekanizması
- Uygun bir eşleşme bulmadan x kez denedikten sonra donör havuzunu şişirin (bu öncelikle pmm için geçerlidir)
Bu, biraz daha karmaşık bir sarma işleviyle sonuçlanır:
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)
}
Büyük olasılıkla, önerilen veri kümesinin tüm durumlar için kısıtlamaları kaybolmadan başarısız olması nedeniyle, bu kadar iyi çalışmadığını unutmayın . Davranmaya başlamadan önce döngü uzunluğunu 400-500'e çıkarmam gerekiyor. Bunun kasıtsız olduğunu varsayıyorum, dürüstlüğünüz gerçek verilerin nasıl üretildiğini taklit etmelidir.
Optimizasyon
Argüman ry
eksik olmayan değerleri içerir ve uygun imputasyonlar bulduğumuz öğeleri kaldırarak döngüyü hızlandırabiliriz, ancak iç işlevlere aşina olduğum için bundan kaçındım.
Bence, tam doldurmaya zaman ayıran güçlü kısıtlamalarınız olduğunda en önemli şey , impütasyonlarınızı paralel hale getirmektir ( CrossValidated hakkındaki cevabıma bakın ). Çoğu bugün 4-8 çekirdekli bilgisayarlara sahiptir ve R varsayılan olarak bunlardan birini kullanır. Çekirdek sayısı iki katına çıkarılarak zaman (neredeyse) yarıya bölünebilir.
İmpütasyonda eksik parametreler
Sorununu İlişkin x2
isnadın anda eksik olan - fareler aslında içine eksik değerleri besleyen asla x
- data.frame
. Farenin yöntemi başlangıcında rastgele değeri dolgu içerir. Empütasyonun zincir kısmı, bu ilk değerden gelen etkiyi sınırlar. mice
-Function'a bakarsanız bunu imputing çağrısından önce ( mice:::sampler
-function) bulabilirsiniz:
...
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))
}
}
...
Bu data.init
fonksiyona verilebilir mice
ve fareler.imput.sample , temel bir örnekleme prosedürüdür.
Ziyaret sırası
Ziyaret dizisi önemliyse, mice
-fonksiyonunun impütasyonları yürütme sırasını belirleyebilirsiniz . Varsayılan, 1:ncol(data)
ancak istediğiniz gibi olacak şekilde ayarlayabilirsiniz visitSequence
.
0 or 16 or >= 16
için0 or >= 16
çünkü>=16
değeri içerir16
. Umarım anlamını bozmaz. Aynı için0 or 14 or >= 14