web-dev-qa-db-fra.com

Utiliser LASSO in R avec des variables catégorielles

J'ai un ensemble de données avec 1000 observations et 76 variables, dont une vingtaine sont catégoriques. Je veux utiliser LASSO sur tout cet ensemble de données. Je sais que les variables factorielles ne fonctionnent pas vraiment dans LASSO, que ce soit par lars ou global, mais les variables sont trop nombreuses et il existe trop de valeurs différentes, non ordonnées, qu’elles peuvent prendre pour les recoder raisonnablement numériquement.

Est-ce que LASSO peut être utilisé dans cette situation? Comment puis-je faire cela? La création d'une matrice des prédicteurs donne cette réponse:

hdy<-as.numeric(housingData2[,75])
hdx<-as.matrix(housingData2[,-75])
model.lasso <- lars(hdx, hdy)
Error in one %*% x : requires numeric/complex matrix/vector arguments

Je me rends compte que d'autres méthodes peuvent être plus faciles ou plus appropriées, mais le défi consiste à le faire en utilisant lars ou glmnet, alors si c'est possible, j'apprécierais vos idées ou vos commentaires.

Je vous remercie,

4
Alex

Vous pouvez créer des variables nominales à partir de votre facteur en utilisant model.matrix.

Je crée un data.frame. y est la variable cible.

create_factor <- function(nb_lvl, n= 100 ){
  factor(sample(letters[1:nb_lvl],n, replace = TRUE))}

df <- data.frame(var1 = create_factor(5), 
           var2 = create_factor(5), 
           var3 = create_factor(5), 
           var4 = create_factor(5),
           var5 = rnorm(100),
           y = create_factor(2))


    # var1 var2 var3 var4        var5   y
    # 1    a    c    c    b -0.58655607 b
    # 2    d    a    e    a  0.52151994 a
    # 3    a    b    d    a -0.04792142 b
    # 4    d    a    a    d -0.41754957 b
    # 5    a    d    e    e -0.29887004 a

Sélectionnez toutes les variables factorielles. J'utilise dplyr::select_if, puis j'analyse les noms de variables pour obtenir une expression comme y ~ var1 + var2 +var3 +var4

library(dplyr)
library(stringr)
library(glmnet)
vars_name <- df %>% 
  select(-y) %>% 
  select_if(is.factor) %>% 
  colnames() %>% 
  str_c(collapse = "+") 

model_string <- paste("y  ~",vars_name )

Créez des variables factices avec model.matrix. N'oubliez pas le as.formula pour contraindre un caractère à une formule.

 x_train <- model.matrix(as.formula(model_string), df)

Adapter votre modèle.

 lasso_model <- cv.glmnet(x=x_train,y = df$y, family = "binomial", alpha=1, nfolds=10)

Le code pourrait être simplifié. Mais l'idée est là.

1
Flo.P

Les autres réponses ci-dessous indiquent des moyens de recoder vos facteurs catégoriques en tant que variables nominales. En fonction de votre application, cela ne sera peut-être pas une bonne solution. Si la seule chose qui compte pour vous est la prédiction, alors c'est probablement bien et l'approche fournie par Flo.P devrait convenir. LASSO vous trouvera un ensemble de variables utiles et vous ne serez probablement pas sur-ajusté.

Cependant, si vous souhaitez interpréter votre modèle ou discuter des facteurs qui sont importants après coup, vous êtes dans un endroit étrange. Le code par défaut que model.matrix a des interprétations très spécifiques lorsqu'il est pris par eux-mêmes. model.matrix utilise ce que l'on appelle le "codage factice". (Je me souviens de l’avoir appris en tant que "codage de référence"; voir ici pour un résumé.) Cela signifie que si l’un de ces nuls est inclus, votre modèle a maintenant un paramètre dont l’interprétation est "la différence entre un niveau de cette facteur et un autre niveau arbitrairement choisi de ce facteur ". Et peut-être qu'aucun des autres mannequins pour ce facteur n'a été sélectionné. Vous pouvez également constater que si l'ordre de vos facteurs change, vous vous retrouvez avec un modèle différent.

Il y a moyen de régler ce problème, mais plutôt que d'essayer de concilier quelque chose, je voudrais essayer le lasso de groupe. Construire sur le code de Flo.P ci-dessus:

install.packages("gglasso")
library(gglasso)


create_factor <- function(nb_lvl, n= 100 ){
  factor(sample(letters[1:nb_lvl],n, replace = TRUE))}

df <- data.frame(var1 = create_factor(5), 
                 var2 = create_factor(5), 
                 var3 = create_factor(5), 
                 var4 = create_factor(5),
                 var5 = rnorm(100),
                 y = rnorm(100))

y <- df$y
x <- model.matrix( ~ ., dplyr::select(df, -y))[, -1]
groups <- c(rep(1:4, each = 4), 5)
fit <- gglasso(x = x, y = y, group = groups, lambda = 1)
fit$beta

Donc, comme nous n’avons pas spécifié de relation entre nos facteurs (var1, var2, etc.) et y, LASSO fait du bon travail et définit tous les coefficients sur 0 sauf lorsque le minimum de régularisation est appliqué. Vous pouvez jouer avec les valeurs de lambda (paramètre de réglage) ou simplement laisser l’option vide et la fonction choisira une plage pour vous.

0
mavery