web-dev-qa-db-fra.com

Tous les niveaux d'un facteur dans une matrice de modèle en R

J'ai un data.frame composé de variables numériques et factorielles, comme indiqué ci-dessous.

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

Je veux construire une matrix qui assigne des variables factices au facteur et laisse les variables numériques seules.

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

Comme prévu lors de l'exécution de lm, un niveau de chaque facteur est omis comme niveau de référence. Cependant, je veux construire une matrix avec une variable indicatrice/indicatrice pour chaque niveau de tous les facteurs. Je construis cette matrice pour glmnet afin que je ne m'inquiète pas de multicolinéarité.

Existe-t-il un moyen de permettre à model.matrix de créer le mannequin pour chaque niveau du facteur?

56
Jared

Vous devez réinitialiser la contrasts pour les variables de facteur:

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

ou, avec un peu moins de frappe et sans les noms propres:

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

(J'essaie de me racheter ...) En réponse au commentaire de Jared sur la réponse de @Fabians à propos de son automatisation, notez que tout ce dont vous avez besoin de fournir est une liste nommée de matrices de contraste. contrasts() prend un vecteur/facteur et en produit la matrice de contrastes. Pour cela, nous pouvons utiliser lapply() pour exécuter contrasts() sur chaque facteur de notre ensemble de données, par exemple. pour l'exemple testFrame fourni:

> 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

Quels créneaux bien dans @fabians répondent:

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

caret a implémenté une fonction de Nice dummyVars à cette fin avec 2 lignes:

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

Vérification des dernières colonnes: 

colnames(testFrame2)

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

Le point le plus intéressant ici est que vous obtenez le cadre de données d'origine, plus les variables nominales ayant exclu les variables d'origine utilisées pour la transformation.

Plus d'infos: http://amunategui.github.io/dummyVar-Walkthrough/

13
pablo_sci

dummyVars de caret peut également être utilisé. http://caret.r-forge.r-project.org/preprocess.html

10
Sagar Jauhari

Utilisation du package 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
2
asdf123

D'accord. Il suffit de lire ce qui précède et de tout mettre en place. Supposons que vous vouliez la matrice, par exemple. 'X.factors' qui multiplient par votre vecteur de coefficient pour obtenir votre prédicteur linéaire. Il y a encore quelques étapes supplémentaires:

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

(Notez que vous devez reconvertir X [*] en un bloc de données si vous n’avez qu’une colonne de facteur.)

Ensuite, dites que vous obtenez quelque chose comme ceci:

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

Nous voulons nous débarrasser des ** 'd niveaux de référence de chaque facteur

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

J'apprends actuellement le modèle Lasso et glmnet::cv.glmnet(), model.matrix() et Matrix::sparse.model.matrix() (pour la matrice de grandes dimensions, utiliser model.matrix tuera notre temps comme suggéré par l'auteur de glmnet.).

Le simple partage de ces informations permet d’obtenir la même réponse que celle de @fabians et celle de @ Gavin. Entre-temps, @ asdf123 a également introduit un autre paquet, library('CatEncoders').

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

Source: R pour tous: analyses et graphiques avancés (page 273)

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

ou

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

devrait être le plus simple

F

1
Federico Rotolo

Une réponse du paquet stats:

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

L'ajout de +0 (ou -1) à une formule modèle (par exemple, dans lm ()) dans R supprime l'interception.

S'il vous plaît voir

0

Une réponse tidyverse:

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

donne le résultat souhaité (identique à la réponse de @Gavin Simpson):

> 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