Замена NA в каждом столбце матрицы на медиану этого столбца

Я пытаюсь заменить NA в каждом столбце матрицы медианой этого столбца, однако, когда я пытаюсь использовать lapply или же sapply Я получаю ошибку; код работает, когда я использую цикл for и когда я изменяю один столбец за раз, что я делаю неправильно?

Пример:

set.seed(1928)
mat <- matrix(rnorm(100*110), ncol = 110)
mat[sample(1:length(mat), 700, replace = FALSE)] <- NA
mat1 <- mat2 <- mat

mat1 <- lapply(mat1,
  function(n) {
     mat1[is.na(mat1[,n]),n] <- median(mat1[,n], na.rm = TRUE)
  }
)   

for (n in 1:ncol(mat2)) {
  mat2[is.na(mat2[,n]),n] <- median(mat2[,n], na.rm = TRUE)
}

4 ответа

Решение

Я хотел бы предложить векторизацию этого с помощью matrixStats пакет вместо вычисления медианы на столбец, используя один из циклов (sapply также является циклом в том смысле, что он оценивает функцию в каждой итерации).

Во-первых, мы создадим NAиндекс s

indx <- which(is.na(mat), arr.ind = TRUE)

Затем замените NAс использованием предварительно рассчитанных медиан столбцов и в соответствии с индексом

mat[indx] <- matrixStats::colMedians(mat, na.rm = TRUE)[indx[, 2]]

Ты можешь использовать sweep:

sweep(mat, MARGIN = 2, 
      STATS = apply(mat, 2, median, na.rm=TRUE),
      FUN =  function(x,s) ifelse(is.na(x), s, x)
    )

РЕДАКТИРОВАТЬ: Вы также можете зайти в STATS=matrixStats::colMedians(mat, na.rm=TRUE) для немного большей производительности.

lapply циклы по списку. Вы хотите перебрать столбцы?

matx <- sapply(seq_len(ncol(mat1)), function(n) {
  mat1[is.na(mat1[,n]),n] <- median(mat1[,n], na.rm = TRUE)
})

хотя по сути это просто делает то, что делает ваш пример цикла (но, вероятно, быстрее).

Вы могли бы получить там легче путем преобразования в data.frame и обратно к matrix в результате, используя vapply:

vapply(as.data.frame(mat1), function(x)
   replace(x, is.na(x), median(x,na.rm=TRUE)), FUN.VALUE=numeric(nrow(mat1)) 
)
Другие вопросы по тегам