Custom fonction, dplyr et problem d'argument

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

Tomas leon
Messages : 51
Enregistré le : 09 Jan 2018, 16:12

Custom fonction, dplyr et problem d'argument

Messagepar Tomas leon » 28 Mai 2019, 17:41

Bonjour à tous,

C'est la première fois que je veux faire une fonction mais avec du code dplyr dedans (%>%) mais j'ai un souci avec l'argument de la fonction, s'il vous plait.

Pour faire simple, j'ai des données d'observations d'oiseaux : 1 ligne = 1 observation avec une colonne "observé/pas_observé" et une colonne "superficie_essence". Je veux savoir si avec l'augmentation de la superficie il y a une augmentation de la proportion "d'observé" dans chaque catégorie de surface. Pour cela j'ai fait le code :

Code : Tout sélectionner


test_tab_ggplot <- data_observation %>% select(superficie_essence , obs ) %>% mutate(Class_prop = factor(case_when(
  superficie_essence  == 0 ~ "[0]",
  superficie_essence  > 0.0001 & superficie_essence  < 10.0001 ~ "]0-10]",
  superficie_essence  > 10.0001 & superficie_essence  < 25.0001 ~ "]10-25]",
  superficie_essence  > 25.0001 & superficie_essence  < 50.0001 ~ "]25-50]",
  superficie_essence  > 50.0001 & superficie_essence  < 75.0001 ~ "]50-75]",
  superficie_essence  > 75.0001 ~ "]75- 100]",
)))


test_tab_ggplotII <- ddply(test_tab_ggplot,.(Class_prop),
                           function(x) with(x,
                                            data.frame(100*round(table(obs )/length(obs ),3))))


ggplot(data=test_tab_ggplotII, aes(x=Class_prop, y=Freq, fill=obs )) +
  geom_bar(stat="identity")+
  scale_fill_brewer(palette="Greens")+
  theme_minimal()



Cela me donne exactement ce que je veux, cependant, j'ai pleins d'essences à tester et donc j'aimerais faire une fonction.


Code : Tout sélectionner


plot_forest <- function(data_observation, superficie_essence){
 
   superficie_essence <- enquo(superficie_essence)
  print(superficie_essence)
 
  test_tab_ggplot <- data_observation %>% select(!!superficie_essence , obs ) %>% mutate(Class_prop = factor(case_when(
    !!col  == 0 ~ "[0]",
    !!superficie_essence  > 0.0001 & !!superficie_essence  < 10.0001 ~ "]0-10]",
    !!superficie_essence  > 10.0001 & !!superficie_essence  < 25.0001 ~ "]10-25]",
    !!superficie_essence  > 25.0001 & !!superficie_essence  < 50.0001 ~ "]25-50]",
    !!superficie_essence  > 50.0001 & !!superficie_essence  < 75.0001 ~ "]50-75]",
    !!superficie_essence  > 75.0001 ~ "]75- 100]",
  )))
 


test_tab_ggplotII <- ddply(test_tab_ggplot,.(Class_prop),
                           function(x) with(x,
                                            data.frame(100*round(table(obs )/length(obs ),3))))


out <- ggplot(data=test_tab_ggplotII, aes(x=Class_prop, y=Freq, fill=obs )) +
  geom_bar(stat="identity")+
  scale_fill_brewer(palette="Greens")+
  theme_minimal()
 
 return(out)
}

plot_forest(data_observation, superficie_essence)



Et la ça coince, je veux qu'il comprenne l'expression "Pc_foret" dans mon cas de figure. Après quelques recherches sur internet j'ai cru que simplement mettre

Code : Tout sélectionner

 superficie_essence <- enquo(superficie_essence)
et des

Code : Tout sélectionner

!!superficie_essence
allait suffire, mais j'ai des messages d'erreurs :

Code : Tout sélectionner

Erreur : Base operators are not defined for quosures.
Do you need to unquote the quosure?

  # Bad:
  myquosure == rhs

  # Good:
  !!myquosure == rhs
que je ne comprend pas.

Auriez-vous une idée s'il vous plait ?

Merci à tous !

Données repro :

Code : Tout sélectionner


superficie_essence <- c(0,0,0,0,10,10,30,30,30,45,65,65,65,80,80,80,90,95,100)

obs <- as.factor(c("oui", "non", "non", "non", "oui", "non", "non", "non", "non", "oui", "oui", "oui", "oui", "oui", "oui", "non", "oui", "oui", "oui"))

data_observation <- cbind.data.frame(superficie_essence, obs)

library(dplyr)
library(plyr)


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

Re: Custom fonction, dplyr et problem d'argument

Messagepar Mickael Canouil » 29 Mai 2019, 08:06

Bonjour,

case_when() n'est pas une fonction encore parfaitement aboutie, surtout dans le cadre de son intégration dans un mutate().
Le plus simple, si vous souhaitez vraiment utiliser des évaluations non-standard (i.e., tidyeval), c'est de renommer les variables au moment de la sélection des colonnes et utilisé des noms fixes pour la manipulation.

1/ les packages avec uniquement dplyr, ggplot2 et scales pour transformer l'axe y en pourcentage

Code : Tout sélectionner

library(dplyr)
library(ggplot2)
library(scales)

2/ Le jeu de donnée, pas besoin de faire plain d'affectation et un cbind.

Code : Tout sélectionner

data_observation <- data.frame(
  superficie_essence = c(
    0, 0, 0, 0, 10,
    10, 30, 30, 30, 45,
    65, 65, 65, 80, 80,
    80, 90, 95, 100
  ),
  obs = c(
    "oui", "non", "non", "non", "oui",
    "non", "non", "non", "non", "oui",
    "oui", "oui", "oui", "oui", "oui",
    "non", "oui", "oui", "oui"
  )
)

3/ La fonction avec évaluation non-standard des arguments

Code : Tout sélectionner

plot_forest <- function(data = NULL, variable = NULL, colour = NULL) {
  x <- enquo(variable)
  fill <- enquo(colour)
 
  ggdata <- data %>%
    select(x = !!x, fill = !!fill) %>%
    mutate(
      group = case_when(
        x == 0 ~ "[0]",
        x > 0.0001 & x < 10.0001 ~ "]0-10]",
        x > 10.0001 & x < 25.0001 ~ "]10-25]",
        x > 25.0001 & x < 50.0001 ~ "]25-50]",
        x > 50.0001 & x < 75.0001 ~ "]50-75]",
        x > 75.0001 ~ "]75- 100]"
      )
    ) %>%
    select(-x) %>%
    group_by(group, fill) %>%
    count() %>%
    group_by(group) %>%
    group_modify(~ mutate(.data = .x, freq = n / sum(n)))

  ggplot(data = ggdata, mapping = aes(x = group, y = freq, fill = fill)) +
    geom_bar(stat = "identity") +
    scale_fill_brewer(palette = "Greens") +
    scale_y_continuous(labels = scales::percent) +
    theme_minimal() +
    labs(x = expr(!!x), fill = expr(!!fill))
}

4/ Le résultat

Code : Tout sélectionner

plot_forest(data = data_observation, variable = superficie_essence, colour = obs)

Image
5/ ou avec les guillemets

Code : Tout sélectionner

plot_forest(data = data_observation, variable = "superficie_essence", colour = "obs")

Image

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

Tomas leon
Messages : 51
Enregistré le : 09 Jan 2018, 16:12

Re: Custom fonction, dplyr et problem d'argument

Messagepar Tomas leon » 29 Mai 2019, 09:47

Bonjour Mikael,

Merci pour votre réponse !

Cependant de mon côté, mon R ne comprend pas la fonction "group_modify()",

Code : Tout sélectionner

Error in group_modify(., ~mutate(.data = .x, freq = n/sum(n))) :
  impossible de trouver la fonction "group_modify"
de quel package est-il issu svp ?
Il va me falloir quelques instants pour bien comprendre ce code :)

Encore merci

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

Re: Custom fonction, dplyr et problem d'argument

Messagepar Mickael Canouil » 29 Mai 2019, 10:50

Toutes les fonctions proviennent de dplyr, ggplot2 et scales, mais probablement pas la version que vous avez.

Code : Tout sélectionner

sessioninfo::package_info(pkgs = c("dplyr", "ggplot2", "scales"), dependencies = FALSE)
#>  package * version date       lib source       
#>  dplyr     0.8.1   2019-05-14 [1] CRAN (R 3.6.0)
#>  ggplot2   3.1.1   2019-04-07 [1] CRAN (R 3.6.0)
#>  scales    1.0.0   2018-08-09 [1] CRAN (R 3.6.0)
#>
#> [1] /usr/local/lib/R/site-library
#> [2] /usr/local/lib/R/library


Vous pouvez remplacer le group_modify() par do():

Code : Tout sélectionner

plot_forest <- function(data = NULL, variable = NULL, colour = NULL) {
  x <- enquo(variable)
  fill <- enquo(colour)
 
  ggdata <- data %>%
    select(x = !!x, fill = !!fill) %>% # selectionne et renome les variables via tidy evaluation
    mutate(
      group = case_when(
        x == 0 ~ "[0]",
        x > 0.0001 & x < 10.0001 ~ "]0-10]",
        x > 10.0001 & x < 25.0001 ~ "]10-25]",
        x > 25.0001 & x < 50.0001 ~ "]25-50]",
        x > 50.0001 & x < 75.0001 ~ "]50-75]",
        x > 75.0001 ~ "]75- 100]"
      )
    ) %>%
    select(-x) %>% # exclu la colonne x
    group_by(group, fill) %>% # "decoupe" le jeu de donnée selon les modalités de group et fill
    count() %>% # compte les lignes du jeu de donnée et "résume" l'information
    group_by(group) %>% # découpe selon la variable group uniquement
    do(mutate(.data = ., freq = n / sum(n))) # calcule la fréquence en pourcentage pour chaque valeur de group

  ggplot(data = ggdata, mapping = aes(x = group, y = freq, fill = fill)) +
    geom_bar(stat = "identity") +
    scale_fill_brewer(palette = "Greens") +
    scale_y_continuous(labels = scales::percent) +
    theme_minimal() +
    labs(x = expr(!!x), fill = expr(!!fill))
}
Mickaël
mickael.canouil.fr | rlille.fr

Tomas leon
Messages : 51
Enregistré le : 09 Jan 2018, 16:12

Re: Custom fonction, dplyr et problem d'argument

Messagepar Tomas leon » 29 Mai 2019, 12:52

Super cela fonctionne !

Le premier code comme l'alternatif. Le problème venait effectivement de mes packages qui n'étaient pas à jour - et - qui pouvaient rentrer en conflit !

Encore merci !


Retourner vers « Questions en cours »

Qui est en ligne

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