Model.matrix() с na.action = NULL?
У меня есть формула и кадр данных, и я хочу извлечь model.matrix()
. Однако мне нужна результирующая матрица, чтобы включить NA, которые были найдены в исходном наборе данных. Если бы я использовал model.frame()
для этого, я бы просто передал его na.action=NULL
. Однако мне нужен выходной формат model.matrix()
. В частности, мне нужны только правые переменные, мне нужен вывод как матрица (а не кадр данных), и мне нужны факторы, которые нужно преобразовать в ряд фиктивных переменных.
Я уверен, что я мог бы что-то взломать, используя петли или что-то в этом роде, но мне было интересно, может ли кто-нибудь предложить более чистый и эффективный способ обхода проблемы. Большое спасибо за ваше время!
И вот пример:
dat <- data.frame(matrix(rnorm(20),5,4), gl(5,2))
dat[3,5] <- NA
names(dat) <- c(letters[1:4], 'fact')
ff <- a ~ b + fact
# This omits the row with a missing observation on the factor
model.matrix(ff, dat)
# This keeps the NA, but it gives me a data frame and does not dichotomize the factor
model.frame(ff, dat, na.action=NULL)
Вот что я хотел бы получить:
(Intercept) b fact2 fact3 fact4 fact5
1 1 0.7266086 0 0 0 0
2 1 -0.6088697 0 0 0 0
3 NA 0.4643360 NA NA NA NA
4 1 -1.1666248 1 0 0 0
5 1 -0.7577394 0 1 0 0
6 1 0.7266086 0 1 0 0
7 1 -0.6088697 0 0 1 0
8 1 0.4643360 0 0 1 0
9 1 -1.1666248 0 0 0 1
10 1 -0.7577394 0 0 0 1
Ответы
Ответ 1
Вы можете немного поработать с объектом model.matrix
, основанным на именах ростов:
MM <- model.matrix(ff,dat)
MM <- MM[match(rownames(dat),rownames(MM)),]
MM[,"b"] <- dat$b
rownames(MM) <- rownames(dat)
который дает:
> MM
(Intercept) b fact2 fact3 fact4 fact5
1 1 0.9583010 0 0 0 0
2 1 0.3266986 0 0 0 0
3 NA 1.4992358 NA NA NA NA
4 1 1.2867461 1 0 0 0
5 1 0.5024700 0 1 0 0
6 1 0.9583010 0 1 0 0
7 1 0.3266986 0 0 1 0
8 1 1.4992358 0 0 1 0
9 1 1.2867461 0 0 0 1
10 1 0.5024700 0 0 0 1
В качестве альтернативы вы можете использовать contrasts()
для выполнения вашей работы. Построить матрицу вручную:
cont <- contrasts(dat$fact)[as.numeric(dat$fact),]
colnames(cont) <- paste("fact",colnames(cont),sep="")
out <- cbind(1,dat$b,cont)
out[is.na(dat$fact),1] <- NA
colnames(out)[1:2]<- c("Intercept","b")
rownames(out) <- rownames(dat)
который дает:
> out
Intercept b fact2 fact3 fact4 fact5
1 1 0.2534288 0 0 0 0
2 1 0.2697760 0 0 0 0
3 NA -0.8236879 NA NA NA NA
4 1 -0.6053445 1 0 0 0
5 1 0.4608907 0 1 0 0
6 1 0.2534288 0 1 0 0
7 1 0.2697760 0 0 1 0
8 1 -0.8236879 0 0 1 0
9 1 -0.6053445 0 0 0 1
10 1 0.4608907 0 0 0 1
В любом случае оба метода могут быть включены в функцию, которая может обрабатывать более сложные формулы. Я оставляю упражнение читателю (что я ненавижу это предложение, когда я встречаю его в бумаге;-))
Ответ 2
Предложение Joris работает, но более быстрый и чистый способ сделать это - через глобальную настройку na.action. Опция 'Pass' позволяет нам сохранить NA из исходного набора данных.
Вариант 1: Пропустить
Результирующая матрица будет содержать NA в строках, соответствующих исходному набору данных.
options(na.action='na.pass')
model.matrix(ff, dat)
Вариант 2: Опустить
Результирующая матрица будет пропускать строки, содержащие NA.
options(na.action='na.omit')
model.matrix(ff, dat)
Вариант 3: Сбой
Ошибка, если исходные данные содержат NA.
options(na.action='na.fail')
model.matrix(ff, dat)
Конечно, всегда будьте осторожны при изменении глобальных параметров, потому что они могут изменять поведение других частей вашего кода. Осторожный человек может сохранить исходный параметр с чем-то вроде current.na.action <- options('na.action')
, а затем изменить его после создания model.matrix.
Ответ 3
Другой способ - использовать функцию model.frame
с аргументом na.action=na.pass
как ваш второй аргумент model.matrix
:
> model.matrix(ff, model.frame(~ ., dat, na.action=na.pass))
(Intercept) b fact2 fact3 fact4 fact5
1 1 -1.3560754 0 0 0 0
2 1 2.5476965 0 0 0 0
3 1 0.4635628 NA NA NA NA
4 1 -0.2871379 1 0 0 0
5 1 2.2684958 0 1 0 0
6 1 -1.3560754 0 1 0 0
7 1 2.5476965 0 0 1 0
8 1 0.4635628 0 0 1 0
9 1 -0.2871379 0 0 0 1
10 1 2.2684958 0 0 0 1
model.frame
позволяет вам установить соответствующее действие для na.action
, которое поддерживается при вызове model.matrix
.