La suppression d'une variable dans la formule lm déclenche toujours une erreur de contraste

9

J'essaie d'exécuter lm () uniquement sur un sous-ensemble de mes données et je rencontre un problème.

dt = data.table(y = rnorm(100), x1 = rnorm(100), x2 = rnorm(100), x3 = as.factor(c(rep('men',50), rep('women',50)))) # sample data

lm( y ~ ., dt) # Use all x: Works
lm( y ~ ., dt[x3 == 'men']) # Use all x, limit to men: doesn't work (as expected)

Ce qui précède ne fonctionne pas car l'ensemble de données ne contient plus que des hommes, et nous ne pouvons donc pas inclure x3, la variable de genre, dans le modèle. MAIS...

lm( y ~ . -x3, dt[x3 == 'men']) # Exclude x3, limit to men: STILL doesn't work
lm( y ~ x1 + x2, dt[x3 == 'men']) # Exclude x3, with different notation: works great

C'est un problème avec la notation "signe moins" dans la formule? Veuillez conseiller. Remarque: bien sûr, je peux le faire d'une manière différente; par exemple, je pourrais exclure les variables avant de les mettre dans lm (). Mais j'enseigne une classe sur ce genre de choses, et je ne veux pas dérouter les élèves, leur ayant déjà dit qu'ils pouvaient exclure une variable en utilisant un signe moins dans la formule.

Zhaochen He
la source
3
Il est intéressant que les deux model.matrix(y ~ . - x3, data = dt[x3 == "men"])et le model.matrix(y ~ x1 + x2, data = dt[x3 == "men"])travail ( lmappels model.matrixinternes). La seule différence entre les deux matrices de modèle est un "contrasts"attribut (qui contient toujours x3) et qui est récupéré plus tard dans la lmroutine, provoquant probablement l'erreur que vous voyez. Mon sentiment est donc que le problème est lié à la façon de model.matrixcréer et de stocker la matrice de conception lors de la suppression des termes.
Maurits Evers
J'essayais de "développer" la .pour obtenir une formule simplifiée avec terms(y ~ . -x3, data=dt, simplify=TRUE)mais curieusement, elle conserve toujours x3l'attribut variables qui se déclenchelm
MrFlick
1
@MrFlick - il semble que l' neg.out=option non implémentée en R puisse être liée. A partir des fichiers d'aide S pour terms, où neg.out=est implémenté: indicateur contrôlant le traitement des termes entrant avec le signe "-". Si VRAI, les conditions seront vérifiées pour annulation et sinon ignorées. Si FAUX, les termes négatifs seront conservés (avec ordre négatif).
thelatemail
1
@MauritsEvers: fait lmappel model.matrixà une version modifiée des données. Au tout début, lmCOMPOSES et évalue l'expression suivante: mf <- stats::model.frame( y ~ . -x3, dt[x3=="men"], drop.unused.levels=TRUE ). Cela x3devient un facteur à un niveau. model.matrix()est ensuite appelé mf, pas les données d'origine, ce qui entraîne l'erreur que nous observons.
Artem Sokolov

Réponses:

2

L'erreur que vous obtenez est parce que x3 est dans le modèle avec une seule valeur = "men"(voir le commentaire ci-dessous de @Artem Sokolov)

Une façon de le résoudre consiste à sous-définir à l'avance:

dt = data.table(y = rnorm(100), x1 = rnorm(100), x2 = rnorm(100), x3 = as.factor(c(rep('men',50), rep('women',50)))) # sample data

dmen<-dt[x3 == 'men'] # create a new subsetted dataset with just men

lm( y ~ ., dmen[,-"x3"]) # now drop the x3 column from the dataset (just for the model)

Ou vous pouvez faire les deux dans la même étape:

lm( y ~ ., dt[x3 == 'men',-"x3"])
Dylan_Gomes
la source
Dans l'ensemble, c'est une bonne solution. Une chose à corriger est que -x3dans une formule ne pas causer lmde penser que vous essayez de soustraire la colonne. L'intention "ne pas utiliser x3 dans le modèle" est communiquée correctement, mais le problème est que les lmappels model.frame( ..., drop.unused.levels=TRUE )provoquant la x3transformation en un facteur de niveau unique, conduisant à des problèmes en aval dans model.matrix().
Artem Sokolov
Merci pour la clarification Artem Sokolov, j'ai retiré cette explication incorrecte de ma réponse.
Dylan_Gomes