Предварительное умножение путем исключения NA в R

#r

#r

Вопрос:

Вот пример данных:

 set.seed(123)
covar1 <- matrix(sample(c(NA, 1:3), 10, replace = TRUE), 10,1)
covar2 <- matrix(sample(c(NA, 1:3), 10, replace = TRUE), 10,1)
covar3 <- matrix(sample(c(NA, 1:3), 10, replace = TRUE), 10,1)
covar4 <- matrix(sample(c(NA, 1:3), 10, replace = TRUE), 10,1)
covar5 <- matrix(sample(c(NA, 1:3), 10, replace = TRUE), 10,1)

df <- as.data.frame(cbind(covar1,covar2,covar3,covar4,covar5))
names(df) <- c("covar1","covar2","covar3","covar4","covar5")
  

И это мои 3 модели с параметрами, каждая из которых соответствует ковариации, как в df

 model0 <- data.frame(covar1=4,covar5=7)
model1 <- data.frame(covar1=2,covar3=5,covar4=3)
model2 <- data.frame(covar1=2,covar2=5,covar3=3,covar5=7)
  

Теперь я хотел бы выбрать model0-2 и предварительно умножить с соответствующей строкой из df . Строки df, которые не соответствуют критериям соответствия, дадут NA .

Предполагается всегда использовать самую длинную модель из 3 доступных. Итак, если строка соответствует 4-ковариационной модели = model2, эта df строка должна быть предварительно умножена на model2, если совпадения нет, следует попробовать model1 или model0 в меньших размерах.

Желаемый результат:

       covar1 covar2 covar3 covar4 covar5 Output Model
 1      NA      2      3     NA     NA     NA
 2       1     NA      2      2      2     18    m1    # (1*2) (2*5) (2*3)=18
 3       3      1      2      1      1     21    m2    # (1*3) (1*5) (3*2) (7*1)=21
 4      NA      1     NA      3      2     NA          # (1*2) (2*5) (2*3)=18
 ..
 .. 
  

Сейчас я не собираюсь писать, что я пробовал, поскольку это включало бы еще больше информации, которая обычно не нравится пользователям SO. Для чего-то подобного там может быть даже package. Любой намек или помощь очень ценятся.

Ответ №1:

Прежде всего, при создании data.frame не используйте эту комбинацию as.data.frame / cbind . Просто используйте

 df <- data.frame(covar1,covar2,covar3,covar4,covar5)
  

Это также приведет к соответствующей настройке имен. Я не уверен, где люди используют cbind метод, но это не очень хорошая привычка.

В любом случае, перейдем к вашей реальной проблеме. Было бы лучше хранить ваши модели в списке (от самого длинного к самому короткому). Это упростит обработку

 models <- list(m2=model2, m1=model1, m0=model0)
  

Теперь мы можем просмотреть фрейм данных и посмотреть, какая модель имеет наибольшее перекрытие с не пропущенными значениями ковариации. Сначала я вычисляю перекрытие, а затем выбираю наилучшую модель для каждой строки

 mmatch <- sapply(models, function(m) rowSums(!is.na(df[,names(m)]))/ncol(m))
wmodel <- apply(mmatch,1,which.max)
  

Теперь, когда я знаю лучшую модель для каждой группы (ну, в частности, ее индекс в списке моделей) Я разделю data.frame на основе наилучшего соответствия, выполню умножение, а затем объединю данные.

 out<-unsplit(Map(function(m,d,n) 
    {cbind(d, Output=rowSums(d[,names(m)]*m[1,,drop=T], na.rm=T),
         Model=n, stringsAsFactors=F)
    }, 
    models, 
    split(df, wmodel), 
    names(models)), 
wmodel)
  

Это вернет

    covar1 covar2 covar3 covar4 covar5 Output Model
1       1      3      3      3     NA     26    m1
2       3      1      2      3      1     24    m2
3       1      2      2      2      1     25    m2
4       3      2      3      3      1     32    m2
5       3     NA      2     NA     NA     NA    m1
6      NA      3      2      1     NA     NA    m1
7       2     NA      2      3     NA     23    m1
8       3     NA      2     NA      1     19    m0
9       2      1      1      1      1     19    m2
10      1      3     NA     NA      3     25    m0
  

Я не уверен, что желаемый результат, который вы показали, на самом деле использовал указанное вами начальное значение, потому что я получил разные значения.