Transformer une variable "enumeré" en plusieurs variables binaires

Postez ici vos questions, réponses, commentaires ou suggestions - Les sujets seront ultérieurement répartis dans les archives par les modérateurs

Modérateur : Groupe des modérateurs

Christophe Genolini
Messages : 698
Enregistré le : 12 Juin 2006, 21:37
Contact :

Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Christophe Genolini » 29 Aoû 2017, 16:17

Bonjour le GuR,

Dans un data.frame, j'ai une variable "EXPOSITION" dans laquelle j'ai des caractéristiques comme "belle vue", "sans vis-à-vis"', "exposé sud" mais aussi des combinaisons comme "belle vue, sans vis-à-vis".
Je souhaite créer trois variables "BELLE_VUE","SANS_VIS_A_VIS" et "EXPOSE_SUD" qui prendraient pour valeur TRUE ou FALSE en fonction de la valeur de EXPOSITION.

Savez-vous s'il existe un moyen simple de faire cette transformation ?

Merci
Christophe
--
Christophe
https://rplusplus.com

Gabriel Terraz
Messages : 591
Enregistré le : 26 Sep 2011, 15:11

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Gabriel Terraz » 29 Aoû 2017, 18:50

Salut,
Voici une proposition :

data bidon :

Code : Tout sélectionner

df <- data.frame(expo = c("belle vue,sans vis-à-vis","belle vue","sans vis-à-vis","exposé sud","exposé sud,belle vue","belle vue,sans vis-à-vis,exposé sud"),stringsAsFactors = F)
df
                                 expo
1            belle vue,sans vis-à-vis
2                           belle vue
3                      sans vis-à-vis
4                          exposé sud
5                exposé sud,belle vue
6 belle vue,sans vis-à-vis,exposé sud


Puis on split les chaînes sur la virgule et on match dans un vecteur contenant les 3 possibilités :
Split :

Code : Tout sélectionner

items <- c("belle vue","sans vis-à-vis","exposé sud")
str <- strsplit(df$expo, ",")
str
[[1]]
[1] "belle vue"      "sans vis-à-vis"

[[2]]
[1] "belle vue"

[[3]]
[1] "sans vis-à-vis"

[[4]]
[1] "exposé sud"

[[5]]
[1] "exposé sud" "belle vue"

[[6]]
[1] "belle vue"      "sans vis-à-vis" "exposé sud"


Match :

Code : Tout sélectionner

str_in <- sapply(str, function(x)  items %in% x)
str_in
      [,1]  [,2]  [,3]  [,4]  [,5] [,6]
[1,]  TRUE  TRUE FALSE FALSE  TRUE TRUE
[2,]  TRUE FALSE  TRUE FALSE FALSE TRUE
[3,] FALSE FALSE FALSE  TRUE  TRUE TRUE


Et on raccroche le tout :

Code : Tout sélectionner

df <- data.frame(df, t(str_in))
names(df) <- c("expo", items)
df
                                 expo belle vue sans vis-à-vis exposé sud
1            belle vue,sans vis-à-vis      TRUE           TRUE      FALSE
2                           belle vue      TRUE          FALSE      FALSE
3                      sans vis-à-vis     FALSE           TRUE      FALSE
4                          exposé sud     FALSE          FALSE       TRUE
5                exposé sud,belle vue      TRUE          FALSE       TRUE
6 belle vue,sans vis-à-vis,exposé sud      TRUE           TRUE       TRUE

Eric Casellas
Messages : 767
Enregistré le : 06 Jan 2009, 14:59

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Eric Casellas » 30 Aoû 2017, 08:00

Bonjour,

Il est aussi possible de se remplacer les étapes du strsplit et %in% en utilisant grepl

Code : Tout sélectionner

df$belle_vue <- grepl("belle vue", df$expo)


Eric
Eric

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Logez Maxime » 30 Aoû 2017, 09:53

Bonjour,

avec un bon vieux sapply ou lapply tout dépend de ce que tu en fais derrière :

Code : Tout sélectionner

mods <- unique(unlist(strsplit(df$expo, ",")))
sapply(mods, grepl, df$expo)
Après j'ai déjà vu des codes encore plus efficaces sur le net mais impossible de remettre la main dessus.

Cordialement,
Maxime

Serge Rapenne
Messages : 1426
Enregistré le : 20 Aoû 2007, 15:17
Contact :

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Serge Rapenne » 30 Aoû 2017, 11:52

Bonjour,

juste pour l'exercice, voici une solution avec dplyr et tidyr

Code : Tout sélectionner

library(tidyr)
library(dplyr)

df <- data.frame(expo = c("belle vue,sans vis-à-vis","belle vue","sans vis-à-vis","exposé sud","exposé sud,belle vue","belle vue,sans vis-à-vis,exposé sud"),stringsAsFactors = F)

tmp<-df %>%  unnest(expo2 = strsplit(expo, ","))
spread(count(tmp, expo, expo2), expo2, n, fill = 0) %>% mutate_if(is.numeric,as.logical)

# A tibble: 6 x 4
                                 expo `belle vue` `exposé sud` `sans vis-à-vis`
                                <chr>       <lgl>        <lgl>            <lgl>
1                           belle vue        TRUE        FALSE            FALSE
2            belle vue,sans vis-à-vis        TRUE        FALSE             TRUE
3 belle vue,sans vis-à-vis,exposé sud        TRUE         TRUE             TRUE
4                          exposé sud       FALSE         TRUE            FALSE
5                exposé sud,belle vue        TRUE         TRUE            FALSE
6                      sans vis-à-vis       FALSE        FALSE             TRUE


Serge

Christophe Genolini
Messages : 698
Enregistré le : 12 Juin 2006, 21:37
Contact :

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Christophe Genolini » 31 Aoû 2017, 11:29

Merci pour toutes vos réponses, ca marche !
--
Christophe
https://rplusplus.com

Michaël Delorme
Messages : 67
Enregistré le : 04 Avr 2016, 10:21

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Michaël Delorme » 31 Aoû 2017, 11:58

Code : Tout sélectionner

library(tidyverse)
tibble(expo = c("belle vue,sans vis-à-vis","belle vue","sans vis-à-vis","exposé sud","exposé sud,belle vue","belle vue,sans vis-à-vis,exposé sud")) %>%
  rownames_to_column() %>%
  unnest(expo2 = strsplit(expo, ",")) %>%
  spread(expo2, rowname) %>%
  mutate_at(-1, function(x) !is.na(x))

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Pierre-Yves Berrard » 08 Sep 2017, 07:49

À noter l'existence de la fonction tidyr::separate_rows qui est un raccourci pour unnest et strsplit.

Code : Tout sélectionner

library(dplyr)
library(tidyr)

items <- c("belle vue", "exposé sud", "sans vis-à-vis")

df %>%
  mutate(expo_copy = expo) %>%             # (étape facultative)
  separate_rows(expo, sep = ", *") %>%
  spread(expo, expo) %>%
  mutate_at(items, Negate(is.na))

PS : j'ai modifié l'expression régulière "sep" pour qu'elle reconnaisse un ou plusieurs espaces après la virgule.
PY

Logez Maxime
Messages : 3138
Enregistré le : 26 Sep 2006, 11:35

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Logez Maxime » 08 Sep 2017, 08:26

Bonjour,

Je trouve l'utilisation des librairies de tidyverse assez passionnante mais pas toujours aisée. De temps en temps avec ces librairies je trouve qu'on est tellement dans leurs utilisations qu'on perd de vue la simplicité d'autres fonctions de base qui font le même job.
Quand je reprends les exemples donnés ici, le code ne fonctionne pas toujours par exemple chez moi :

Code : Tout sélectionner

df <- data.frame(expo = c("belle vue,sans vis-à-vis","belle vue","sans vis-à-vis","exposé sud","exposé sud,belle vue","belle vue,sans vis-à-vis,exposé sud"),stringsAsFactors = F)

df %>%
  mutate(expo_copy = expo) %>%
  separate_rows(expo_copy, sep = ", *") %>%
  spread(expo_copy, expo_copy) %>%
  mutate_at(items, Negate(is.na))
  Error in parse(text = x) : <text>:1:7: unexpected symbol
1: belle vue
J'imagine que les espaces posent problèmes parce que si je remplace mutate_at par mutate_all tout fonctionne.
Certains de ces codes fonctionnent bien aussi parce que df ne contient que des chaînes de caractères uniques mais dès qu'on a des doublons, ce qui semble réaliste, alors ces scripts s'arrêtent :

Code : Tout sélectionner

df2 <- df[sample(1:nrow(df), 1e4, rep = T),]

df %>%
  mutate(expo_copy = expo) %>%
  separate_rows(expo_copy, sep = ", *") %>%
  spread(expo_copy, expo_copy) %>%
  select(-expo) %>% mutate_all(Negate(is.na))
# ok

df2 %>%
  mutate(expo_copy = expo) %>%
  separate_rows(expo_copy, sep = ", *") %>%
  spread(expo_copy, expo_copy) %>%
  select(-expo) %>% mutate_all(Negate(is.na))
  Erreur : Duplicate identifiers for rows (23, 30, ...
 
df3 <- as.tibble(df2)
df3 %>%
  rownames_to_column() %>%
  unnest(expo2 = strsplit(expo, ",")) %>%
  spread(expo2, rowname) %>%
  mutate_at(-1, function(x) !is.na(x))
Il semblerait que le problème soit dans la fonction spread. Je ne suis pas très familier avec ces fonctions mais une solution serait de rajouter une colonne ID :

Code : Tout sélectionner

df2 %>%
  mutate(expo_copy = expo) %>%
  separate_rows(expo_copy, sep = ", *") %>%
  mutate(ID = 1:n()) %>%
  spread(expo_copy, expo_copy) %>%
  select(-expo, -ID) %>% mutate_all(Negate(is.na))
Après en terme d'efficacité, dans des cas simples comme celui-là je n'en suis pas convaincu parce qu'on fait appel à pas mal de fonctions différentes pour arriver au résultat :

Code : Tout sélectionner

mic1 <- microbenchmark(Sapply = sapply(items, grepl, df2$expo),
Tidyr = {
df2 %>%
  mutate(expo_copy = expo) %>%
  separate_rows(expo_copy, sep = ", *") %>%
  mutate(ID = 1:n()) %>%
  spread(expo_copy, expo_copy) %>%
  select(-expo, -ID) %>% mutate_all(Negate(is.na))
})

mic1
Unit: milliseconds
   expr        min         lq       mean     median         uq       max neval
 Sapply   7.540157   7.590186   8.820972   7.674762   9.775775  16.79412   100
  Tidyr 156.896432 159.980835 177.452730 164.693905 178.504249 310.81531   100
Cordialement,
Maxime

Pierre-Yves Berrard
Messages : 1029
Enregistré le : 12 Jan 2016, 23:30

Re: Transformer une variable "enumeré" en plusieurs variables binaires

Messagepar Pierre-Yves Berrard » 08 Sep 2017, 08:45

Entièrement d'accord sur le fait de ne jamais perdre de vue les bons vieux fondamentaux.
La démonstration de benchmarking est de plus assez éloquente.

(suis tombé par hasard ce matin sur la fonction separate_rows et ça m'a fait penser à ce sujet)
PY


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Google [Bot] et 1 invité