List avec boucle for ou fonction

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

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

List avec boucle for ou fonction

Messagepar Elsa Nario » 30 Aoû 2021, 12:45

Bonjour,
Je cherche à répéter une étape en fonction de différentes modalités.
Par ex : j'ai un data frame avec des informations par client.
Je souhaite réccupérer les modalités uniques de certaines colonnes (ici par Sexe). Ensuite je souhaite créer autant de data frame que de modalités. Par exemple ici, je cherche les modalités uniques de Sexe (Femme et Homme) et je souhaite créer ensuite 2 data frame pour les 2 modalités.
J'aimerais créer une boucle ou fonction pour n'avoir qu'à définir au départ juste le nom des colonnes sur lesquelles je souhaite effectuer le traitement.
Mais je ne sais pas du tout comment m'y prendre et ce qui serait le mieux entre boucle ou fonction.
Merci de votre aide

Code : Tout sélectionner

library (dplyr)

pop <- data.frame(client=1:5,
                   tranche_age=c("35-54 ans","18-34 ans","55 ans et +","18-34 ans", "-18 ans"),
                   sexe=c("Homme","Femme","Femme", "Homme", "Femme"),
                   nb_pers_foyers=c(4,2,5,3,1),
                   csp=c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
                  q_1=c("Oui","Non","Non","Oui","Non"),
                  q_2=c("Non","Oui","Oui","Oui","Non"),
                  q_3=c("Oui","Oui","Non","Non","Oui"))

pop$poids <- 1

list <- list(unique(pop$sexe))

pop_femme <- filter(pop, sexe=="Femme")
data_femme <- select(pop_femme, client, poids, starts_with("q"))

for(i in 3:length(data_femme)){
  colonne <- data_femme[,i]
  colonne[colonne == "Oui"] <- '1'
  colonne[colonne == "Non"] <- '0'
  colonne[colonne != '0' & colonne != '1'] <- NA
  colonne <- colonne %>% unlist() %>% as.numeric()
  data_femme[,i] <- colonne
}


pop_homme <- filter(pop, sexe=="Homme")
data_homme <- select(pop_homme, client, poids, starts_with("q"))

for(i in 3:length(data_homme)){
  colonne <- data_homme[,i]
  colonne[colonne == "Oui"] <- '1'
  colonne[colonne == "Non"] <- '0'
  colonne[colonne != '0' & colonne != '1'] <- NA
  colonne <- colonne %>% unlist() %>% as.numeric()
  data_homme[,i] <- colonne
}

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: List avec boucle for ou fonction

Messagepar Mickael Canouil » 30 Aoû 2021, 13:38

Bonjour,

je n'ai pas bien compris le but de la manoeuvre, mais avant de répondre, je me dois de mentionner un principe de base en programmation https://en.wikipedia.org/wiki/Don%27t_repeat_yourself. Ici, vous répétez deux fois le même bloc.

Si c'est la même opération qui doit être effectuée, pourquoi vouloir découper en de multiples objets ? (le group_by/ungroup est parfaitement inutile dans le code ci-dessous, mais fait littéralement ce que vous semblez vouroir faire)

Code : Tout sélectionner

pop <- data.frame(
  client = 1:5,
  tranche_age = c("35-54 ans", "18-34 ans", "55 ans et +", "18-34 ans", "-18 ans"),
  sexe = c("Homme", "Femme", "Femme", "Homme", "Femme"),
  nb_pers_foyers = c(4, 2, 5, 3, 1),
  csp = c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
  q_1 = c("Oui", "Non", "Non", "Oui", "Non"),
  q_2 = c("Non", "Oui", "Oui", "Oui", "Non"),
  q_3 = c("Oui", "Oui", "Non", "Non", "Oui"),
  poids = 1


Code : Tout sélectionner

library(dplyr)
pop %>% 
  group_by
(sexe) %>% 
  mutate
(across(starts_with("q"), ~ c("Oui" = 1, "Non" = 0)[.x])) %>% 
  ungroup
()
#> # A tibble: 5 x 9
#>   client tranche_age sexe  nb_pers_foyers csp        q_1   q_2   q_3 poids
#>    <int> <chr>       <chr>          <dbl> <chr>    <dbl> <dbl> <dbl> <dbl>
#> 1      1 35-54 ans   Homme              4 Ouvrier      1     0     1     1
#> 2      2 18-34 ans   Femme              2 Cadre        0     1     1     1
#> 3      3 55 ans et + Femme              5 Employé      0     1     0     1
#> 4      4 18-34 ans   Homme              3 Ouvrier      1     1     0     1
#> 5      5 -18 ans     Femme              1 Retraité     0     0     1     1     

La même chose avec une fonction nommée :

Code : Tout sélectionner

recode_yes_no <- function(x) c("Oui" = 1, "Non" = 0)[x]
pop %>% 
  group_by
(sexe) %>% 
  mutate
(across(starts_with("q"), recode_yes_no)) %>% 
  ungroup
()
#> # A tibble: 5 x 9
#>   client tranche_age sexe  nb_pers_foyers csp        q_1   q_2   q_3 poids
#>    <int> <chr>       <chr>          <dbl> <chr>    <dbl> <dbl> <dbl> <dbl>
#> 1      1 35-54 ans   Homme              4 Ouvrier      1     0     1     1
#> 2      2 18-34 ans   Femme              2 Cadre        0     1     1     1
#> 3      3 55 ans et + Femme              5 Employé      0     1     0     1
#> 4      4 18-34 ans   Homme              3 Ouvrier      1     1     0     1
#> 5      5 -18 ans     Femme              1 Retraité     0     0     1     1     


Sans group_by/ungroup:

Code : Tout sélectionner

mutate(pop, across(starts_with("q"),~ c("Oui" = 1, "Non" = 0)[.x]))
#> # A tibble: 5 x 9
#>   client tranche_age sexe  nb_pers_foyers csp        q_1   q_2   q_3 poids
#>    <int> <chr>       <chr>          <dbl> <chr>    <dbl> <dbl> <dbl> <dbl>
#> 1      1 35-54 ans   Homme              4 Ouvrier      1     0     1     1
#> 2      2 18-34 ans   Femme              2 Cadre        0     1     1     1
#> 3      3 55 ans et + Femme              5 Employé      0     1     0     1
#> 4      4 18-34 ans   Homme              3 Ouvrier      1     1     0     1
#> 5      5 -18 ans     Femme              1 Retraité     0     0     1     1     


Si on veut vraiment "découper", on peut opter pour deux approches :

Code : Tout sélectionner

library(dplyr)
pop_recoded <- mutate(popacross(starts_with("q"),~ c("Oui" 1"Non" 0)[.x])) 

  • tidyr::nest

    Code : Tout sélectionner

    library(dplyr)
    library(tidyr)
    pop_recoded %>% 
      
    group_by(sexe) %>% 
      
    nest()
    #> # A tibble: 2 x 2
    #> # Groups:   sexe [2]
    #>   sexe  data            
    #>   <chr> <list>          
    #> 1 Homme <tibble [2 x 8]>
    #> 2 Femme <tibble [3 x 8]> 

  • base

    Code : Tout sélectionner

    split(pop_recodedpop_recoded[["sexe"]])
    #> $Femme
    #>   client tranche_age  sexe nb_pers_foyers      csp q_1 q_2 q_3 poids
    #> 2      2   18-34 ans Femme              2    Cadre   0   1   1     1
    #> 3      3 55 ans et + Femme              5  Employé   0   1   0     1
    #> 5      5     -18 ans Femme              1 Retraité   0   0   1     1
    #> 
    #> $Homme
    #>   client tranche_age  sexe nb_pers_foyers     csp q_1 q_2 q_3 poids
    #> 1      1   35-54 ans Homme              4 Ouvrier   1   0   1     1
    #> 4      4   18-34 ans Homme              3 Ouvrier   1   1   0     1 

Cordialement,
Mickaël
mickael.canouil.fr | rlille.fr

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

Re: List avec boucle for ou fonction

Messagepar Elsa Nario » 31 Aoû 2021, 08:35

Bonjour,
Merci pour votre retour. Mais ce n'est pas l'objectif que je recherche. L'idée est de créer plusieurs data frame, en fonction de certaines colonnes choisies et des modalités qu'elles contiennent. Par exemple, si je choisie la colonne Sexe et la colonne CSP, je souhaite récupérer les différentes modalités uniques qu'elles contiennent (Homme, Femme, Ouvrier, Cadre, Employé, ...) de façon automatique. Puis ensuite je souhaite créer des data frame qui sont filtrés sur chaque modalité (un data frame uniquement pour les femmes, un data frame uniquement pour les hommes, etc), pour ensuite analyser chaque data frame et venir remmetter les modalités correspondantes.
Comme dans l'exemple ci-dessous ou j'ai commencé à créer 4 data frame. Mais l'idée serait d'avoir quelque chose d'automatisé pour n'avoir qu'à rentrer dès le départ les noms de colonne.
L'exemple ci-dessous reproduit exactement ce que je veux au final : res_sexe et res_csp mais avec dans l'idée de ne paramétrer dès le départ que sexe et csp.
Merci de votre aide.


Code : Tout sélectionner

library(dplyr)
library(turfR)

pop <- data.frame(client=1:5,
                  poids=1,
                   tranche_age=c("35-54 ans","18-34 ans","55 ans et +","18-34 ans", "-18 ans"),
                   sexe=c("Homme","Femme","Femme", "Homme", "Femme"),
                   nb_pers_foyers=c(4,2,5,3,1),
                   csp=c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
                  q_1=c("Oui","Non","Non","Oui","Non"),
                  q_2=c("Non","Oui","Oui","Oui","Non"),
                  q_3=c("Oui","Oui","Non","Non","Oui"))

list1 <- list(c("sexe", "csp"))

list2 <- list(unique(pop$sexe))

list3 <- list(unique(pop$csp))

# 1er Dataframe

pop_femme <- filter(pop, sexe=="Femme")
pop_femme <- select(pop_femme, client, poids, starts_with("q"))

for(i in 3:length(pop_femme)){
  colonne <- pop_femme[,i]
  colonne[colonne == "Oui"] <- '1'
  colonne[colonne == "Non"] <- '0'
  colonne[colonne != '0' & colonne != '1'] <- NA
  colonne <- colonne %>% unlist() %>% as.numeric()
  pop_femme[,i] <- colonne
}

res1 <- turf(pop_femme, 3, 2)
res1 <- res1[["turf"]][[1]]
res1$sexe <- "Femme"

# 2ème Dataframe

pop_homme <- filter(pop, sexe=="Homme")
pop_homme <- select(pop_homme, client, poids, starts_with("q"))

for(i in 3:length(pop_homme)){
  colonne <- pop_homme[,i]
  colonne[colonne == "Oui"] <- '1'
  colonne[colonne == "Non"] <- '0'
  colonne[colonne != '0' & colonne != '1'] <- NA
  colonne <- colonne %>% unlist() %>% as.numeric()
  pop_homme[,i] <- colonne
}

res2 <- turf(pop_homme, 3, 2)
res2 <- res2[["turf"]][[1]]
res2$sexe <- "Homme"

res_sexe <- rbind(res1, res2)

# 3ème Dataframe

pop_ouvrier <- filter(pop, csp=="Ouvrier")
pop_ouvrier <- select(pop_ouvrier, client, poids, starts_with("q"))

for(i in 3:length(pop_ouvrier)){
  colonne <- pop_ouvrier[,i]
  colonne[colonne == "Oui"] <- '1'
  colonne[colonne == "Non"] <- '0'
  colonne[colonne != '0' & colonne != '1'] <- NA
  colonne <- colonne %>% unlist() %>% as.numeric()
  pop_ouvrier[,i] <- colonne
}

res3 <- turf(pop_ouvrier, 3, 2)
res3 <- res3[["turf"]][[1]]
res3$csp <- "Ouvrier"

# 4ème Dataframe

pop_employe <- filter(pop, csp=="Employé")
pop_employe <- select(pop_employe, client, poids, starts_with("q"))

for(i in 3:length(pop_employe)){
  colonne <- pop_employe[,i]
  colonne[colonne == "Oui"] <- '1'
  colonne[colonne == "Non"] <- '0'
  colonne[colonne != '0' & colonne != '1'] <- NA
  colonne <- colonne %>% unlist() %>% as.numeric()
  pop_employe[,i] <- colonne
}

res4 <- turf(pop_employe, 3, 2)
res4 <- res4[["turf"]][[1]]
res4$csp <- "employé"

res_csp <- rbind(res3, res4)

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: List avec boucle for ou fonction

Messagepar Mickael Canouil » 01 Sep 2021, 08:06

Comme je le disais, c'est véritablement une mauvaise approche à plusieurs niveaux ...
Mais si vous avez envie de faire du mal à la personne qui reprendra votre code et qui est probablement votre future vous, soit, voici comment vous pouvez le faire.

Code : Tout sélectionner

pop <- data.frame(
  client = 1:5,
  tranche_age = c("35-54 ans", "18-34 ans", "55 ans et +", "18-34 ans", "-18 ans"),
  sexe = c("Homme", "Femme", "Femme", "Homme", "Femme"),
  nb_pers_foyers = c(4, 2, 5, 3, 1),
  csp = c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
  q_1 = c("Oui", "Non", "Non", "Oui", "Non"),
  q_2 = c("Non", "Oui", "Oui", "Oui", "Non"),
  q_3 = c("Oui", "Oui", "Non", "Non", "Oui"),
  poids = 1
)

<- function(xdataenv) {
  
ldata <- split(datadata[[x]])
  for (
i in names(ldata)) {
    
assign(
      
sprintf("%s_%s", as.character(substitute(data)), i), 
      
value ldata[[i]],
      
envir env
    
)
  }
}

f("sexe", pop, .GlobalEnv)
ls()
#> [1] "f"         "pop"       "pop_Femme" "pop_Homme"  
Mickaël
mickael.canouil.fr | rlille.fr

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

Re: List avec boucle for ou fonction

Messagepar Elsa Nario » 02 Sep 2021, 07:53

Merci, c'est en effet le résultat recherché même si je ne comprends pas bien les différentes étapes effectuées pour y arriver.
Je ne comprends pas quand vous dites que c'est une mauvaise approche ?
Le mieux serait de fonctionner avec le group by comme indiqué plus haut ?
le problème c'est que je ne sais pas si je peux appliquer la fonction turf dans une seul data frame avec le group by. L'analyse turf s'effectue sur le data frame entier et ici j'ai besoin de faire plusieurs analyses turf.

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: List avec boucle for ou fonction

Messagepar Mickael Canouil » 02 Sep 2021, 09:24

Si vous devez copier-coller du code plusieurs fois, c'est à 100 % une mauvaise approche en R ou n'importe quel langage de programmation.

Je vous invite à vous documenter sur dplyr::group_by()

Code : Tout sélectionner

pop <- data.frame(
  client = 1:5,
  tranche_age = c("35-54 ans", "18-34 ans", "55 ans et +", "18-34 ans", "-18 ans"),
  sexe = c("Homme", "Femme", "Femme", "Homme", "Femme"),
  nb_pers_foyers = c(4, 2, 5, 3, 1),
  csp = c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
  q_1 = c("Oui", "Non", "Non", "Oui", "Non"),
  q_2 = c("Non", "Oui", "Oui", "Oui", "Non"),
  q_3 = c("Oui", "Oui", "Non", "Non", "Oui"),
  poids = 1
)

Une approche possible que je vous invite à executer ligne par ligne tout en consultant la documentation pour comprendre la logique.

Code : Tout sélectionner

library(dplyr)
library(tidyr)
library(turfR)
pop %>%
  
mutate(across(starts_with("q"), ~ c("Oui" 1"Non" 0)[.x])) %>%
  
group_by(sexe) %>%
  
select(clientpoidsstarts_with("q")) %>%
  
nest() %>%
  
rowwise() %>%
  
transmute(turf_results turf(data32)[[1]]) %>%
  
unnest(cols "turf_results") %>%
  
ungroup()
#> Adding missing grouping variables: `sexe`
#> 2 of 3: 0.01399994 sec
#> total time elapsed: 0.01599979 sec 
#> 2 of 3: 0.00899601 sec
#> total time elapsed: 0.01000309 sec
#> # A tibble: 6 x 7
#>   sexe  combo  rchX  frqX   `1`   `2`   `3`
#>   <chr> <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
#> 1 Homme 1     1     1.5       1     1     0
#> 2 Homme 2     1     1.5       1     0     1
#> 3 Homme 3     1     1         0     1     1
#> 4 Femme 3     1     1.33      0     1     1
#> 5 Femme 1     0.667 0.667     1     1     0
#> 6 Femme 2     0.667 0.667     1     0     1 


Même approche via l'extension data.table

Code : Tout sélectionner

library(data.table)
library(turfR)
as.
data.table(pop)[
  j = paste0("q_", 1:3) := lapply(.SD, function(x) c("Oui" = 1, "Non" = 0)[x]),
  .SDcols = paste0("q_", 1:3)
][
  j = as.data.table(turf(.SD, 3, 2)[[1]]),
  by = "sexe",
  .SDcols = c("client", "poids", paste0("q_", 1:3))
]
#> 2 of 3: 0.01299691 sec
#> total time elapsed: 0.01399899 sec 
#> 2 of 3: 0.01202703 sec
#> total time elapsed: 0.01302505 sec
#>     sexe combo      rchX      frqX X1 X2 X3
#> 1: Homme     1 1.0000000 1.5000000  1  1  0
#> 2: Homme     2 1.0000000 1.5000000  1  0  1
#> 3: Homme     3 1.0000000 1.0000000  0  1  1
#> 4: Femme     3 1.0000000 1.3333333  0  1  1
#> 5: Femme     1 0.6666667 0.6666667  1  1  0
#> 6: Femme     2 0.6666667 0.6666667  1  0  1    
Mickaël
mickael.canouil.fr | rlille.fr

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

Re: List avec boucle for ou fonction

Messagepar Elsa Nario » 03 Sep 2021, 08:18

Bonjour,
En effet, je comprends mieux et beaucoup plus simple avec le group by.
Je ne connaissais pas les fonctions across, nest et rowwise, merci !
L'exemple avec data.table est plus difficile à comprendre je trouve.
Pouvez-vous juste me dire à quoi sert [.x] et [x] dans chacun des 2 exemples ?
merci beaucoup pour cette aide.

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: List avec boucle for ou fonction

Messagepar Mickael Canouil » 03 Sep 2021, 10:48

"~ .x" est juste la formulation "tidyeval" du tidyverse pour écrire "function(x) x"
"[" est simplement l'opérateur d'accès des vecteurs, matrices, arrays, utilisé ici pour récupéré une valeur à partir du nom de l'élément dans le vecteur.

Code : Tout sélectionner

c("Oui" = 1, "Non" = 0)["Oui"]
#> Oui 
#>   1 

<- function(x) c("Oui" = 1, "Non" = 0)[x]
f("Oui")
#> Oui 
#>   1 

f(c("Oui", "Non"))
#> Oui Non 
#>   1   0      

data.table a une logique très différente du tidyverse, mais privilégie la performance. Il existe dtplyr (https://dtplyr.tidyverse.org/) pour écrire en mode tidyverse et garder les performances de data.table.
Mickaël
mickael.canouil.fr | rlille.fr

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

Re: List avec boucle for ou fonction

Messagepar Elsa Nario » 03 Sep 2021, 12:17

Ok, merci .
Et avec la fonction turf je peux analyser en 2 ou 3 combinaisons si j'ai plus de variables.

Code : Tout sélectionner

transmute(turf_results = turf(data, 3, 2:3)[[1]]) %>%

Du coup je récupères 2 listes au lieu d'1. Mais comment récupérer les 2 listes dans le même data frame ? car ce que j'essaie ne fonctionne pas

Code : Tout sélectionner

pop <- data.frame(
  client = 1:5,
  tranche_age = c("35-54 ans", "18-34 ans", "55 ans et +", "18-34 ans", "-18 ans"),
  sexe = c("Homme", "Femme", "Femme", "Homme", "Femme"),
  nb_pers_foyers = c(4, 2, 5, 3, 1),
  csp = c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
  q_1 = c("Oui", "Non", "Non", "Oui", "Non"),
  q_2 = c("Non", "Oui", "Oui", "Oui", "Non"),
  q_3 = c("Oui", "Oui", "Non", "Non", "Oui"),
  q_4 = c("Non", "Oui", "Non", "Non", "Oui"),
  q_5 = c("Oui", "Oui", "Oui", "Non", "Oui"),
  poids = 1
)

library(dplyr)
library(tidyr)
library(turfR)
test <- pop %>%
  mutate(across(starts_with("q"), ~ c("Oui" = 1, "Non" = 0)[.x])) %>%
  group_by(sexe) %>%
  select(client, poids, starts_with("q")) %>%
  nest() %>%
  rowwise() %>%
  transmute(turf_results = turf(data, 3, 2:3)[[1]][[2]]) %>%
  unnest(cols = "turf_results") %>%
  ungroup()

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

Re: List avec boucle for ou fonction

Messagepar Elsa Nario » 07 Sep 2021, 11:41

Bonjour,
En fait je réexplique les autres problèmes que j'ai :
- Comme évoqué ci-dessus, l'analyse TURF peut être spécifiée pour faire l'analyse sur 2 ou plusieurs combinaisons

Code : Tout sélectionner

turf_results = turf(data, 5, 2:3)[[1]])
pour récupérer la 1ère liste et

Code : Tout sélectionner

turf_results = turf(data, 5, 2:3)[[2]])
pour récupérer la 2ème liste
J'aimerais pouvoir intégrer cette fonction dans le programme en récupérant les 2 listes (à 2 combinaisons et à 3 combinaisons) dans le même data frame.
Quand je fais ça cela ne fonctionne pas

Code : Tout sélectionner

pop <- data.frame(
  client = 1:5,
  tranche_age = c("35-54 ans", "18-34 ans", "55 ans et +", "18-34 ans", "-18 ans"),
  sexe = c("Homme", "Femme", "Femme", "Homme", "Femme"),
  nb_pers_foyers = c(4, 2, 5, 3, 1),
  csp = c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
  q_1 = c("Oui", "Non", "Non", "Oui", "Non"),
  q_2 = c("Non", "Oui", "Oui", "Oui", "Non"),
  q_3 = c("Oui", "Oui", "Non", "Non", "Oui"),
  q_4 = c("Non", "Oui", "Non", "Non", "Oui"),
  q_5 = c("Oui", "Oui", "Oui", "Non", "Oui"),
  poids = 1
)

col <- pop %>%
  mutate(MODALITE = "MODALITE", COMBINAISON = 1, RCHX = 1, FRQX = 1, MIX = 2) %>%
  select(MODALITE, RCHX, FRQX, starts_with("q"), MIX, COMBINAISON)

results <- pop %>%
  mutate(across(starts_with("q"), ~ c("Oui" = 1, "Non" = 0)[.x])) %>%
  group_by(sexe) %>%
  select(client, poids, starts_with("q")) %>%
  nest() %>%
  rowwise() %>%
  transmute(turf_results = turf(data, 5, 2:3)[[1]][[2]]) %>%
  unnest(cols = "turf_results") %>%
  ungroup()


- Autre problème : je souhaite ajouter/modifier de nouvelles colonnes (dans l'idéal la Colone MIX viendrait chercher la valeur automatiquement 2 ou 3 pour indiquer le nombre de combinaisons) et remplacer de nouveaux les valeurs à 1 ou 0 par X et " " mais cela ne fonctionne pas et je ne comprends pas pourquoi

Code : Tout sélectionner

pop <- data.frame(
  client = 1:5,
  tranche_age = c("35-54 ans", "18-34 ans", "55 ans et +", "18-34 ans", "-18 ans"),
  sexe = c("Homme", "Femme", "Femme", "Homme", "Femme"),
  nb_pers_foyers = c(4, 2, 5, 3, 1),
  csp = c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
  q_1 = c("Oui", "Non", "Non", "Oui", "Non"),
  q_2 = c("Non", "Oui", "Oui", "Oui", "Non"),
  q_3 = c("Oui", "Oui", "Non", "Non", "Oui"),
  q_4 = c("Non", "Oui", "Non", "Non", "Oui"),
  q_5 = c("Oui", "Oui", "Oui", "Non", "Oui"),
  poids = 1
)

col <- pop %>%
  mutate(MODALITE = "MODALITE", COMBINAISON = 1, RCHX = 1, FRQX = 1, MIX = 2) %>%
  select(MODALITE, RCHX, FRQX, starts_with("q"), MIX, COMBINAISON)

results <- pop %>%
  mutate(across(starts_with("q"), ~ c("Oui" = 1, "Non" = 0)[.x])) %>%
  group_by(sexe) %>%
  select(client, poids, starts_with("q")) %>%
  nest() %>%
  rowwise() %>%
  transmute(turf_results = turf(data, 5, 2)[[1]]) %>%
  unnest(cols = "turf_results") %>%
  ungroup() %>%
  mutate(MIX = 2, COMBINAISON = paste("Combinaison", combo, sep = " "), across(starts_with("q"), ~ c(1 = "X", 0 = " ") [.x]))) %>%
  select(-combo) %>%
  set_colnames(colnames(col))


Merci de votre aide

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: List avec boucle for ou fonction

Messagepar Mickael Canouil » 07 Sep 2021, 15:05

Il va falloir voir ou revoir les bases de R, en particulier ce qui concerne les listes et comment on accède aux éléments.

Code : Tout sélectionner

pop %>%
  mutate(across(starts_with("q"), ~ c("Oui" = 1, "Non" = 0)[.x])) %>%
  group_by(sexe) %>%
  select(client, poids, starts_with("q")) %>%
  nest() %>%
  rowwise() %>%
  transmute(
    turf_results = list(bind_rows(
      turf(
        data = data,
        n = sum(grepl("^q", names(data))),
        k = 2:3
      
)[["turf"]],
      .id = "turf_id"
    ))
  ) %>%
  unnest(cols = "turf_results") %>%
  ungroup()

Exemple hors du group_by, parce-que c'est plus simple de développer sur un exemple minimal.

Code : Tout sélectionner

library(dplyr)
library(tidyr)
library(turfR)

pop <- data.frame(
  
client 1:5,
  
tranche_age c("35-54 ans""18-34 ans""55 ans et +""18-34 ans""-18 ans"),
  
sexe c("Homme""Femme""Femme""Homme""Femme"),
  
nb_pers_foyers c(42531),
  
csp c("Ouvrier""Cadre""Employé""Ouvrier""Retraité"),
  
q_1 c("Oui""Non""Non""Oui""Non"),
  
q_2 c("Non""Oui""Oui""Oui""Non"),
  
q_3 c("Oui""Oui""Non""Non""Oui"),
  
q_4 c("Non""Oui""Non""Non""Oui"),
  
q_5 c("Oui""Oui""Oui""Non""Oui"),
  
poids 1

Code : Tout sélectionner

df <- pop %>%
  
filter(sexe == "Homme") %>%
  
mutate(across(starts_with("q"), ~ c("Oui" 1"Non" 0)[.x])) %>%
  
select(clientpoidsstarts_with("q")) 

Code : Tout sélectionner

res <- turf(
  
data df,
  
sum(grepl("^q"names(df))),
  
2:3
)
#> 2 of 5: 0.01900196 sec
#> 3 of 5: 0.006000996 sec
#> total time elapsed: 0.026999 sec 

Code : Tout sélectionner

str(res)
#> List of 2
#>  $ turf:List of 2
#>   ..$ :'data.frame': 10 obs. of  8 variables:
#>   .. ..$ combo: Factor w/ 10 levels "1","2","3","4",..: 1 2 4 3 5 7 9 6 8 10
#>   .. ..$ rchX : num [1:10] 1 1 1 1 1 1 0.5 0.5 0.5 0.5
#>   .. ..$ frqX : num [1:10] 1.5 1.5 1.5 1 1 1 1 0.5 0.5 0.5
#>   .. ..$ 1    : num [1:10] 1 1 1 1 0 0 0 0 0 0
#>   .. ..$ 2    : num [1:10] 1 0 0 0 1 1 0 1 0 0
#>   .. ..$ 3    : num [1:10] 0 1 0 0 1 0 1 0 1 0
#>   .. ..$ 4    : num [1:10] 0 0 0 1 0 0 0 1 1 1
#>   .. ..$ 5    : num [1:10] 0 0 1 0 0 1 1 0 0 1
#>   ..$ :'data.frame': 10 obs. of  8 variables:
#>   .. ..$ combo: Factor w/ 10 levels "1","2","3","4",..: 1 3 5 2 4 6 8 7 9 10
#>   .. ..$ rchX : num [1:10] 1 1 1 1 1 1 1 1 1 0.5
#>   .. ..$ frqX : num [1:10] 2 2 2 1.5 1.5 1.5 1.5 1 1 1
#>   .. ..$ 1    : num [1:10] 1 1 1 1 1 1 0 0 0 0
#>   .. ..$ 2    : num [1:10] 1 1 0 1 0 0 1 1 1 0
#>   .. ..$ 3    : num [1:10] 1 0 1 0 1 0 1 1 0 1
#>   .. ..$ 4    : num [1:10] 0 0 0 1 1 1 0 1 1 1
#>   .. ..$ 5    : num [1:10] 0 1 1 0 0 1 1 0 1 1
#>  $ call: language turf(data = df, n = sum(grepl("^q", names(df))), k = 2:3) 

Code : Tout sélectionner

res[["turf"]]
#> [[1]]
#>    combo rchX frqX 1 2 3 4 5
#> 1      1  1.0  1.5 1 1 0 0 0
#> 2      2  1.0  1.5 1 0 1 0 0
#> 3      4  1.0  1.5 1 0 0 0 1
#> 4      3  1.0  1.0 1 0 0 1 0
#> 5      5  1.0  1.0 0 1 1 0 0
#> 6      7  1.0  1.0 0 1 0 0 1
#> 7      9  0.5  1.0 0 0 1 0 1
#> 8      6  0.5  0.5 0 1 0 1 0
#> 9      8  0.5  0.5 0 0 1 1 0
#> 10    10  0.5  0.5 0 0 0 1 1
#> 
#> [[2]]
#>    combo rchX frqX 1 2 3 4 5
#> 1      1  1.0  2.0 1 1 1 0 0
#> 2      3  1.0  2.0 1 1 0 0 1
#> 3      5  1.0  2.0 1 0 1 0 1
#> 4      2  1.0  1.5 1 1 0 1 0
#> 5      4  1.0  1.5 1 0 1 1 0
#> 6      6  1.0  1.5 1 0 0 1 1
#> 7      8  1.0  1.5 0 1 1 0 1
#> 8      7  1.0  1.0 0 1 1 1 0
#> 9      9  1.0  1.0 0 1 0 1 1
#> 10    10  0.5  1.0 0 0 1 1 1 

Code : Tout sélectionner

do.call("rbind"res[["turf"]])
#>    combo rchX frqX 1 2 3 4 5
#> 1      1  1.0  1.5 1 1 0 0 0
#> 2      2  1.0  1.5 1 0 1 0 0
#> 3      4  1.0  1.5 1 0 0 0 1
#> 4      3  1.0  1.0 1 0 0 1 0
#> 5      5  1.0  1.0 0 1 1 0 0
#> 6      7  1.0  1.0 0 1 0 0 1
#> 7      9  0.5  1.0 0 0 1 0 1
#> 8      6  0.5  0.5 0 1 0 1 0
#> 9      8  0.5  0.5 0 0 1 1 0
#> 10    10  0.5  0.5 0 0 0 1 1
#> 11     1  1.0  2.0 1 1 1 0 0
#> 12     3  1.0  2.0 1 1 0 0 1
#> 13     5  1.0  2.0 1 0 1 0 1
#> 14     2  1.0  1.5 1 1 0 1 0
#> 15     4  1.0  1.5 1 0 1 1 0
#> 16     6  1.0  1.5 1 0 0 1 1
#> 17     8  1.0  1.5 0 1 1 0 1
#> 18     7  1.0  1.0 0 1 1 1 0
#> 19     9  1.0  1.0 0 1 0 1 1
#> 20    10  0.5  1.0 0 0 1 1 1 

Code : Tout sélectionner

bind_rows(res[["turf"]])
#>    combo rchX frqX 1 2 3 4 5
#> 1      1  1.0  1.5 1 1 0 0 0
#> 2      2  1.0  1.5 1 0 1 0 0
#> 3      4  1.0  1.5 1 0 0 0 1
#> 4      3  1.0  1.0 1 0 0 1 0
#> 5      5  1.0  1.0 0 1 1 0 0
#> 6      7  1.0  1.0 0 1 0 0 1
#> 7      9  0.5  1.0 0 0 1 0 1
#> 8      6  0.5  0.5 0 1 0 1 0
#> 9      8  0.5  0.5 0 0 1 1 0
#> 10    10  0.5  0.5 0 0 0 1 1
#> 11     1  1.0  2.0 1 1 1 0 0
#> 12     3  1.0  2.0 1 1 0 0 1
#> 13     5  1.0  2.0 1 0 1 0 1
#> 14     2  1.0  1.5 1 1 0 1 0
#> 15     4  1.0  1.5 1 0 1 1 0
#> 16     6  1.0  1.5 1 0 0 1 1
#> 17     8  1.0  1.5 0 1 1 0 1
#> 18     7  1.0  1.0 0 1 1 1 0
#> 19     9  1.0  1.0 0 1 0 1 1
#> 20    10  0.5  1.0 0 0 1 1 1 

Code : Tout sélectionner

bind_rows(res[["turf"]], .id "turf_id")
#>    turf_id combo rchX frqX 1 2 3 4 5
#> 1        1     1  1.0  1.5 1 1 0 0 0
#> 2        1     2  1.0  1.5 1 0 1 0 0
#> 3        1     4  1.0  1.5 1 0 0 0 1
#> 4        1     3  1.0  1.0 1 0 0 1 0
#> 5        1     5  1.0  1.0 0 1 1 0 0
#> 6        1     7  1.0  1.0 0 1 0 0 1
#> 7        1     9  0.5  1.0 0 0 1 0 1
#> 8        1     6  0.5  0.5 0 1 0 1 0
#> 9        1     8  0.5  0.5 0 0 1 1 0
#> 10       1    10  0.5  0.5 0 0 0 1 1
#> 11       2     1  1.0  2.0 1 1 1 0 0
#> 12       2     3  1.0  2.0 1 1 0 0 1
#> 13       2     5  1.0  2.0 1 0 1 0 1
#> 14       2     2  1.0  1.5 1 1 0 1 0
#> 15       2     4  1.0  1.5 1 0 1 1 0
#> 16       2     6  1.0  1.5 1 0 0 1 1
#> 17       2     8  1.0  1.5 0 1 1 0 1
#> 18       2     7  1.0  1.0 0 1 1 1 0
#> 19       2     9  1.0  1.0 0 1 0 1 1
#> 20       2    10  0.5  1.0 0 0 1 1 1 
Mickaël
mickael.canouil.fr | rlille.fr

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

Re: List avec boucle for ou fonction

Messagepar Elsa Nario » 07 Sep 2021, 15:16

Vous venez de résoudre un de mes problèmes, merci, Je venais justement de refaire mon message avec des compléments.
J'avoue que je n'ai pas utilisé les listes jusqu'ici et que je ne maîtrise pas. Et j'aimerai optismisé ce programme avec des listes. Je vai en faire un autre sujet.

Il y a un autre problème que j'ai évoqué :
je souhaite ajouter/modifier de nouvelles colonnes (dans l'idéal la Colone MIX viendrait chercher la valeur automatiquement 2 ou 3 pour indiquer le nombre de combinaisons) et remplacer de nouveaux les valeurs à 1 ou 0 par X et " " mais cela ne fonctionne pas et je ne comprends pas pourquoi

Code : Tout sélectionner

pop <- data.frame(
  client = 1:5,
  tranche_age = c("35-54 ans", "18-34 ans", "55 ans et +", "18-34 ans", "-18 ans"),
  sexe = c("Homme", "Femme", "Femme", "Homme", "Femme"),
  nb_pers_foyers = c(4, 2, 5, 3, 1),
  csp = c("Ouvrier", "Cadre", "Employé", "Ouvrier", "Retraité"),
  q_1 = c("Oui", "Non", "Non", "Oui", "Non"),
  q_2 = c("Non", "Oui", "Oui", "Oui", "Non"),
  q_3 = c("Oui", "Oui", "Non", "Non", "Oui"),
  q_4 = c("Non", "Oui", "Non", "Non", "Oui"),
  q_5 = c("Oui", "Oui", "Oui", "Non", "Oui"),
  poids = 1
)

col <- pop %>%
  mutate(MODALITE = "MODALITE", COMBINAISON = 1, RCHX = 1, FRQX = 1, MIX = 2) %>%
  select(MODALITE, RCHX, FRQX, starts_with("q"), MIX, COMBINAISON)

results <- pop %>%
  mutate(across(starts_with("q"), ~ c("Oui" = 1, "Non" = 0)[.x])) %>%
  group_by(sexe) %>%
  select(client, poids, starts_with("q")) %>%
  nest() %>%
  rowwise() %>%
  transmute(turf_results = turf(data, 5, 2)[[1]]) %>%
  unnest(cols = "turf_results") %>%
  ungroup() %>%
  mutate(MIX = 2, COMBINAISON = paste("Combinaison", combo, sep = " "), across(starts_with("q"), ~ c(1 = "X", 0 = " ") [.x]))) %>%
  select(-combo) %>%
  set_colnames(colnames(col))


merci

Mickael Canouil
Messages : 1315
Enregistré le : 04 Avr 2011, 08:53
Contact :

Re: List avec boucle for ou fonction

Messagepar Mickael Canouil » 07 Sep 2021, 15:33

Pour vous rendre compte du pourquoi un code ne donne pas le résultat escompté, il convient d'essayer ce code sur un exemple minimaliste.
Ici, il y a plusieurs problème:
* vous ne maitrisez pas les accès par indices/noms des valeurs d'un vecteur ou liste.
* vous utilisez des noms de variables non-syntaxiques (les noms de colonnes, variables, objets, etc. ne peuvent pas commencer par un chiffre, un underscore par exemple.

Suggestion de lecture : https://m.canouil.fr/radvanced/

Code : Tout sélectionner

c(= "X", 0 = " ")
#> Error: unexpected '=' in "c(1 ="  

Exemple :

Code : Tout sélectionner

<- function(x) c("Oui" = 1, "Non" = 0)[x]
(
x1 <- f("Oui"))
#> Oui 
#>   1
(x2 <- f(c("Oui", "Non")))
#> Oui Non 
#>   1   0  

Code : Tout sélectionner

<- function(x) c("1" = "X", "0" = " ")[x]
g(x1)
#>   1 
#> "X"
g(x2)
#>   1 
#> "X"
typeof(x1)
#> [1] "double"
typeof(x2)
#> [1] "double"  

Code : Tout sélectionner

c("1" = "X", "0" = " ")[1]
#>   1 
#> "X"
c("1" = "X", "0" = " ")[0]
#> named character(0)  

Code : Tout sélectionner

c("1" = "X", "0" = " ")["1"]
#>   1 
#> "X"
c("1" = "X", "0" = " ")["0"]
#>   0 
#> " "  
Mickaël
mickael.canouil.fr | rlille.fr

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

Re: List avec boucle for ou fonction

Messagepar Elsa Nario » 09 Sep 2021, 09:16

B

Elsa Nario
Messages : 83
Enregistré le : 22 Mar 2019, 09:06

Re: List avec boucle for ou fonction

Messagepar Elsa Nario » 10 Sep 2021, 13:59

B


Retourner vers « Questions en cours »

Qui est en ligne

Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 1 invité