2010-12-30 5 views
46

Ho uno data.frame costituito da variabili numeriche e fattore come illustrato di seguito.Tutti i livelli di un fattore in una matrice modello in R

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)) 

voglio costruire una matrix che assegna variabili dummy al fattore e lascia le variabili numeriche da solo.

model.matrix(~ First + Second + Third + Fourth + Fifth, data=testFrame) 

Come previsto durante l'esecuzione lm questo lascia fuori un livello di ciascun fattore come livello di riferimento. Tuttavia, voglio creare un matrix con una variabile dummy/indicatore per ogni livello di tutti i fattori. Sto costruendo questa matrice per glmnet quindi non sono preoccupato per la multicollinearità.

C'è un modo per avere model.matrix creare il manichino per ogni livello del fattore?

risposta

37

è necessario reimpostare la contrasts per le variabili fattore:

model.matrix(~ Fourth + Fifth, data=testFrame, 
     contrasts.arg=list(Fourth=contrasts(testFrame$Fourth, contrasts=F), 
       Fifth=contrasts(testFrame$Fifth, contrasts=F))) 

o, con un po 'meno di battitura e senza i nomi propri:

model.matrix(~ Fourth + Fifth, data=testFrame, 
    contrasts.arg=list(Fourth=diag(nlevels(testFrame$Fourth)), 
      Fifth=diag(nlevels(testFrame$Fifth)))) 
+8

Che completamente lavorato e mi prendo quella risposta, ma se sto entrando in 20 fattori c'è un modo di fare che universalmente per tutte le variabili in una cornice o sono io destinato a digitare troppo? – Jared

54

(Cercando di redimermi ...) In risposta al commento di Jared sulla risposta di @Fabians sull'automazione, si noti che tutto ciò che è necessario fornire è un elenco con nome di matrici di contrasto. contrasts() prende un vettore/fattore e produce la matrice di contrasti da esso. Per questo quindi possiamo utilizzare lapply() per eseguire contrasts() su ciascun fattore nel nostro set di dati, ad es. per l'esempio fornito testFrame:

> 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 

quali slot bene in @fabians risposta:

model.matrix(~ ., data=testFrame, 
      contrasts.arg = lapply(testFrame[,4:5], contrasts, contrasts=FALSE)) 
+13

+1. simpatico. puoi automatizzarlo ancora di più sostituendo tranquillamente 4: 5 (testFrame, is.factor) – fabians

+0

Ottima soluzione per l'automazione. Tra voi due, la mia domanda ha ricevuto una risposta perfetta, quindi non sono sicuro di quale risposta debba ottenere il marchio come "Risposta accettata". Voglio che entrambi ti facciano credito. – Jared

+3

@Jared: @fabians era la risposta che stavi cercando, quindi dovrebbe ottenere il merito - il mio contributo era solo un po 'di zucchero in più. –

9

dummyVars da caret potrebbe essere utilizzato anche. http://caret.r-forge.r-project.org/preprocess.html

+0

Sembra carino, ma non include un'intercetta e non riesco a forzarlo. – Jared

+2

@jared: Funziona per me. Esempio: 'require (caret); (df <- data.frame (x1 = c ('a', 'b'), x2 = 1: 2)); dummy <- dummyVars (x2 ~., Data = df); prevedere (dummies, newdata = df) ' – Andrew

+1

@Jared nessuna necessità di intercettazione quando si dispone di una variabile fittizia per ogni livello del fattore. –

2

Ok. Basta leggere quanto sopra e mettere tutto insieme. Supponiamo di volere la matrice, ad es. 'X.factors' che moltiplica per il vettore del coefficiente per ottenere il predittore lineare. Ci sono ancora un paio di passaggi aggiuntivi:

X.factors = 
    model.matrix(~ ., data=X, contrasts.arg = 
    lapply(data.frame(X[,sapply(data.frame(X), is.factor)]), 
              contrasts, contrasts = FALSE)) 

(Si noti che è necessario attivare X [*] di nuovo in un frame di dati nel caso in cui si dispone di una sola colonna fattore.)

Poi dicono che si ottiene qualcosa di simile:

attr(X.factors,"assign") 
[1] 0 1 **2** 2 **3** 3 3 **4** 4 4 5 6 7 8 9 10 #emphasis added 

Ci vogliono sbarazzarsi dei ** 'livelli di riferimento d di ciascun fattore

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)) 
+1

BTW perché non è incorporato nella base R? Sembra che ti serva ogni volta che esegui una simulazione. – user36302

1
model.matrix(~ First + Second + Third + Fourth + Fifth - 1, data=testFrame) 

o

model.matrix(~ First + Second + Third + Fourth + Fifth + 0, data=testFrame) 

dovrebbe essere il più diretto

F

2

Usando il pacchetto 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 
7

caret implementato una bella funzione dummyVars per raggiungere questo obiettivo con 2 linee:

library(caret) dmy <- dummyVars(" ~ .", data = testFrame) testFrame2 <- data.frame(predict(dmy, newdata = testFrame))

Controllo delle colonne finali:

colnames(testFrame2) 

"First" "Second"   "Third"   "Fourth.Alice" "Fourth.Bob"  "Fourth.Charlie" "Fourth.David" "Fifth.Edward" "Fifth.Frank" "Fifth.Georgia" "Fifth.Hank"  "Fifth.Isaac" 

Il punto più bello qui è ottenere il frame di dati originale, oltre alle variabili dummy che hanno escluso quelle originali utilizzate per la trasformazione.

Maggiori informazioni: http://amunategui.github.io/dummyVar-Walkthrough/

0

Attualmente sto imparando modello Lasso e glmnet::cv.glmnet(), model.matrix() e Matrix::sparse.model.matrix() (per Matrix alte dimensioni, utilizzando model.matrix sarà uccidendo il nostro tempo come suggerito dall'autore di glmnet.).

Basta condividere c'è un codice in ordine per ottenere la stessa risposta di @fabians e la risposta di @ Gavin. Nel frattempo, @ asdf123 ha introdotto anche un altro pacchetto library('CatEncoders').

> require('useful') 
> # always use all levels 
> build.x(First ~ Second + Fourth + Fifth, textFrame, contrasts = FALSE) 
> 
> # just use all levels for Fourth 
> build.x(First ~ Second + Fourth + Fifth, testFrame, contrasts = c(Fourth = FALSE, Fifth = TRUE)) 

Fonte: R for Everyone: Advanced Analytics and Graphics (page273)