Tengo un data.frame
consta de variables numéricas y de factor como se ve a continuación.
testFrame <- data.frame(First=sample(1:10, 20, replace=T), Second=sample(1:20, 20, replace=T), Third=sample(1:10, 20, replace=T), Fourth=rep(c("Alice","Bob","Charlie","David"), 5), Fifth=rep(c("Edward","Frank","Georgia","Hank","Isaac"),4))
Quiero construir una matrix
que asigne variables ficticias al factor y deje solo las variables numéricas.
model.matrix(~ First + Second + Third + Fourth + Fifth, data=testFrame)
Como se esperaba al ejecutar lm
esto deja fuera un nivel de cada factor como nivel de referencia. Sin embargo, quiero construir una matrix
con una variable ficticia / indicadora para cada nivel de todos los factores. Estoy construyendo esta matriz para glmnet
así que no estoy preocupado por la multicolinealidad.
¿Hay alguna manera de tener model.matrix
crear el dummy para cada nivel del factor?
Debe restablecer los contrasts
para las variables de factor:
model.matrix(~ Fourth + Fifth, data=testFrame, contrasts.arg=list(Fourth=contrasts(testFrame$Fourth, contrasts=F), Fifth=contrasts(testFrame$Fifth, contrasts=F)))
o, con un poco menos de tipeo y sin los nombres propios:
model.matrix(~ Fourth + Fifth, data=testFrame, contrasts.arg=list(Fourth=diag(nlevels(testFrame$Fourth)), Fifth=diag(nlevels(testFrame$Fifth))))
(Intentando redimirme …) En respuesta al comentario de Jared sobre la respuesta de @Fabians sobre la automatización, tenga en cuenta que todo lo que necesita proporcionar es una lista con nombre de matrices de contraste. contrasts()
toma un vector / factor y produce la matriz de contrastes a partir de él. Para esto, podemos usar lapply()
para ejecutar contrasts()
en cada factor en nuestro conjunto de datos, por ejemplo, para el ejemplo testFrame
proporcionado:
> lapply(testFrame[,4:5], contrasts, contrasts = FALSE) $Fourth Alice Bob Charlie David Alice 1 0 0 0 Bob 0 1 0 0 Charlie 0 0 1 0 David 0 0 0 1 $Fifth Edward Frank Georgia Hank Isaac Edward 1 0 0 0 0 Frank 0 1 0 0 0 Georgia 0 0 1 0 0 Hank 0 0 0 1 0 Isaac 0 0 0 0 1
Que las ranuras muy bien en @fabianos responden:
model.matrix(~ ., data=testFrame, contrasts.arg = lapply(testFrame[,4:5], contrasts, contrasts=FALSE))
dummyVars
de caret
también podría ser utilizado. http://caret.r-forge.r-project.org/preprocess.html
caret
implementó una buena función dummyVars
para lograr esto con 2 líneas:
library(caret) dmy <- dummyVars(" ~ .", data = testFrame) testFrame2 <- data.frame(predict(dmy, newdata = testFrame))
Verificando las columnas finales:
colnames(testFrame2) "First" "Second" "Third" "Fourth.Alice" "Fourth.Bob" "Fourth.Charlie" "Fourth.David" "Fifth.Edward" "Fifth.Frank" "Fifth.Georgia" "Fifth.Hank" "Fifth.Isaac"
El mejor punto aquí es obtener el dataframe original, más las variables ficticias que excluyeron las originales usadas para la transformación.
Más información: http://amunategui.github.io/dummyVar-Walkthrough/
De acuerdo. Acabo de leer lo anterior y ponerlo todo junto. Supongamos que quiere la matriz, por ejemplo, ‘X.factores’ que se multiplica por su vector de coeficientes para obtener su predictor lineal. Todavía hay un par de pasos adicionales:
X.factors = model.matrix( ~ ., data=X, contrasts.arg = lapply(data.frame(X[,sapply(data.frame(X), is.factor)]), contrasts, contrasts = FALSE))
(Tenga en cuenta que debe volver a X [*] en un dataframe en caso de que tenga solo una columna de factores).
Entonces di que obtienes algo como esto:
attr(X.factors,"assign") [1] 0 1 **2** 2 **3** 3 3 **4** 4 4 5 6 7 8 9 10 #emphasis added
Queremos deshacernos de los niveles de referencia ** ‘d de cada factor
att = attr(X.factors,"assign") factor.columns = unique(att[duplicated(att)]) unwanted.columns = match(factor.columns,att) X.factors = X.factors[,-unwanted.columns] X.factors = (data.matrix(X.factors))
Usando el paquete R ‘CatEncoders’
library(CatEncoders) testFrame <- data.frame(First=sample(1:10, 20, replace=T), Second=sample(1:20, 20, replace=T), Third=sample(1:10, 20, replace=T), Fourth=rep(c("Alice","Bob","Charlie","David"), 5), Fifth=rep(c("Edward","Frank","Georgia","Hank","Isaac"),4)) fit <- OneHotEncoder.fit(testFrame) z <- transform(fit,testFrame,sparse=TRUE) # give the sparse output z <- transform(fit,testFrame,sparse=FALSE) # give the dense output
model.matrix(~ First + Second + Third + Fourth + Fifth - 1, data=testFrame)
o
model.matrix(~ First + Second + Third + Fourth + Fifth + 0, data=testFrame)
debería ser el más sencillo
F
Actualmente estoy aprendiendo el modelo Lasso y glmnet::cv.glmnet()
, model.matrix()
y Matrix::sparse.model.matrix()
(para matriz de altas dimensiones, usando model.matrix
nuestro tiempo como lo sugiere el autor de glmnet
.).
Solo compartir allí tiene una encoding ordenada para obtener la misma respuesta que @fabians y la respuesta de @Gavin. Mientras tanto, @ asdf123 introdujo otra library('CatEncoders')
paquetes library('CatEncoders')
también.
> require('useful') > # always use all levels > build.x(First ~ Second + Fourth + Fifth, data = testFrame, contrasts = FALSE) > > # just use all levels for Fourth > build.x(First ~ Second + Fourth + Fifth, data = testFrame, contrasts = c(Fourth = FALSE, Fifth = TRUE))
Fuente: R para todos: Análisis avanzado y gráficos (página273)