2016-01-18 3 views
4

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

Пример:

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) 
} 
+2

Объекты 'matrix' являются векторами с размерами. 'lapply' будет перебирать каждое значение в матрице вместо столбцов. – thelatemail

+3

Если вы чувствуете себя супер ленивым и не хотите писать свою собственную функцию, вы можете использовать 'na.roughfix' из библиотеки' randomForest'. Он автоматически заменяет все значения NA медианным/режимом в зависимости от того, является ли он числовым/множителем. – ytk

+0

@ Jonno Bourne, если вы спрашиваете о том, что данные не являются матрицами, отредактируйте свой воспроизводимый пример, чтобы предоставить фрейм данных. Имейте в виду, что это сделало бы недействительным принятое решение ... – smci

ответ

7

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

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

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

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

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

Я действительно осознал, что хочу сделать это на фрейме данных, но я мог бы преобразовать его в матрицу и выполнить эту операцию, а затем выполнить обратный возврат, спасибо. –

+1

В большинстве случаев у вас есть числовой набор данных, гораздо эффективнее работать с матрицей, а не с data.frame. Даже если вы используете простой цикл. –

1

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

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

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

0

Вы могли бы получить там проще с помощью преобразования в 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)) 
) 
2

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

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

EDIT: Вы также можете заглянуть в STATS=matrixStats::colMedians(mat, na.rm=TRUE) для получения большей производительности.

Смежные вопросы