it-swarm.com.de

Alle Stufen eines Faktors in einer Modellmatrix in R

Ich habe einen data.frame, der aus numerischen und Faktorvariablen besteht, wie unten gezeigt.

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

Ich möchte einen matrix erstellen, der dem Faktor Dummy-Variablen zuordnet und die numerischen Variablen allein lässt.

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

Wie erwartet, wird beim Ausführen von lm eine Ebene jedes Faktors als Bezugsebene weggelassen. Ich möchte jedoch für jede Ebene aller Faktoren eine matrix mit einer Dummy-/Indikatorvariablen ausbauen. Ich baue diese Matrix für glmnet, also mache ich mir keine Sorgen um Multikollinearität.

Gibt es eine Möglichkeit, den Dummy für jede Ebene des Faktors durch model.matrix zu erstellen?

56
Jared

Sie müssen die contrasts für die Faktorvariablen zurücksetzen:

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

oder mit etwas weniger Tippen und ohne die richtigen Namen:

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

(Der Versuch, mich selbst zu erlösen ...) Als Antwort auf Jareds Kommentar zur @Fabians-Antwort zur Automatisierung wird darauf hingewiesen, dass Sie nur eine benannte Liste von Kontrastmatrizen angeben müssen. contrasts() nimmt einen Vektor/Faktor und erzeugt daraus die Kontrastmatrix. Zu diesem Zweck können wir lapply() verwenden, um contrasts() für jeden Faktor in unserem Datensatz auszuführen, z. Für das angegebene testFrame-Beispiel:

> 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

Welche Slots passen gut in @fabians:

model.matrix(~ ., data=testFrame, 
             contrasts.arg = lapply(testFrame[,4:5], contrasts, contrasts=FALSE))
58
Gavin Simpson

caret hat eine Nice-Funktion dummyVars implementiert, um dies mit 2 Zeilen zu erreichen:

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

Überprüfung der letzten Spalten: 

colnames(testFrame2)

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

Der schönste Punkt hier ist, dass Sie den ursprünglichen Datenrahmen erhalten und die Dummy-Variablen die für die Transformation verwendeten ursprünglichen ausgeschlossen haben.

Weitere Informationen: http://amunategui.github.io/dummyVar-Walkthrough/

13
pablo_sci

dummyVars von caret könnte auch verwendet werden. http://caret.r-forge.r-project.org/preprocess.html

10
Sagar Jauhari

Verwenden des R-Pakets '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
2
asdf123

OK. Lesen Sie einfach das obige und setzen Sie alles zusammen. Angenommen, Sie wollten die Matrix, z. 'X.Faktoren', die sich mit Ihrem Koeffizientenvektor multiplizieren, um Ihren linearen Prädiktor zu erhalten. Es gibt noch ein paar zusätzliche Schritte:

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

(Beachten Sie, dass Sie X [*] wieder in einen Datenrahmen umwandeln müssen, falls Sie nur eine Faktorspalte haben.)

Dann sagen Sie, Sie bekommen so etwas:

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

Wir möchten die Referenzwerte für jeden Faktor loswerden

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

Ich lerne gerade das Lasso-Modell und glmnet::cv.glmnet(), model.matrix() und Matrix::sparse.model.matrix() (für eine Matrix mit hohen Dimensionen wird model.matrix unsere Zeit töten, wie vom Autor von glmnet vorgeschlagen.).

Nur dort zu teilen hat eine ordentliche Codierung, um die gleiche Antwort wie @fabians und @ Gavins Antwort zu erhalten. Inzwischen hat @ asdf123 ein weiteres Paket library('CatEncoders') eingeführt.

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

Quelle: R für alle: Fortgeschrittene Analytics und Grafiken (Seite 273)

2
RYO ENG Lian Hu
model.matrix(~ First + Second + Third + Fourth + Fifth - 1, data=testFrame)

oder

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

sollte am einfachsten sein

F

1
Federico Rotolo

Eine stats Paketantwort:

new_tr <- model.matrix(~.+0,data = testFrame)

Das Hinzufügen von +0 (oder -1) zu einer Modellformel (z. B. in lm ()) in R unterdrückt den Achsenabschnitt.

siehe bitte

Eine tidyverse Antwort:

library(dplyr)
library(tidyr)
result <- testFrame %>% 
    mutate(one = 1) %>% spread(Fourth, one, fill = 0, sep = "") %>% 
    mutate(one = 1) %>% spread(Fifth, one, fill = 0, sep = "")

liefert das gewünschte Ergebnis (wie @Gavin Simpsons Antwort):

> head(result, 6)
  First Second Third FourthAlice FourthBob FourthCharlie FourthDavid FifthEdward FifthFrank FifthGeorgia FifthHank FifthIsaac
1     1      5     4           0         0             1           0           0          1            0         0          0
2     1     14    10           0         0             0           1           0          0            1         0          0
3     2      2     9           0         1             0           0           1          0            0         0          0
4     2      5     4           0         0             0           1           0          1            0         0          0
5     2     13     5           0         0             1           0           1          0            0         0          0
6     2     15     7           1         0             0           0           1          0            0         0          0
0
shosaco