[RESOLU] filter ou pas filter

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

herve chapuis
Messages : 110
Enregistré le : 05 Déc 2008, 15:26

[RESOLU] filter ou pas filter

Messagepar herve chapuis » 19 Fév 2020, 15:31

Bonjour à tous.

Je m'interroge sur le comportement de filter (package dplyr) au sein d'une boucle.
Voici une boucle.
Partant d'un fichier de généalogie (BAR11) contenant des dates de naissance (dnais), je cherche à compter le nombre de pères (p) et de mères (m) représentés parmi les animaux nés un jour donné :

Code : Tout sélectionner

    i  p  m sexe      dnais         IDANI        IDPERE        IDMERE F GEN annee
1 179  4 53    2 14/04/2016 GRI2016154875 GRI2015284632 GRI2015285783 0   1  2016
2 180  4 10    2 14/04/2016 GRI2016154879 GRI2015284632 GRI2015284760 0   1  2016
3 181 42 51    2 14/04/2016 GRI2016154956 GRI2015285653 GRI2015285761 0   1  2016
4 182 14 26    2 14/04/2016 GRI2016154997 GRI2015285269 GRI2015285449 0   1  2016
5 183 14 26    2 14/04/2016 GRI2016154999 GRI2015285269 GRI2015285449 0   1  2016
6 184 14 26    2 14/04/2016 GRI2016155000 GRI2015285269 GRI2015285449 0   1  2016

Code : Tout sélectionner

library(tidyverse)
library(lubridate)
for (i in unique(BAR11$dnais)) {
  tmp<- BAR11 %>% filter(dnais == i)
  # tmp<-BAR11[BAR11$dnais==i,]
  head(tmp)
  npere <-length(unique(tmp$p))
  nmere <-length(unique(tmp$m))
  cat(" DNAIS =",i,"N =",nrow(tmp)," # PERES = ",npere," # MERES =",nmere," Fmoy =",mean(tmp$F),"\n")
}

Dans l'état actuel cela me donne :

Code : Tout sélectionner

 DNAIS = 04/04/2016 N = 0  # PERES =  0  # MERES = 0  Fmoy = NaN
 DNAIS = 14/04/2016 N = 0  # PERES =  0  # MERES = 0  Fmoy = NaN
 DNAIS = 16/08/2016 N = 0  # PERES =  0  # MERES = 0  Fmoy = NaN
 DNAIS = 25/08/2016 N = 0  # PERES =  0  # MERES = 0  Fmoy = NaN
 ...

Si, au lieu d'utiliser filter, j'utilise l'instruction classique (tmp<-BAR11[BAR11$dnais==i,]) j'obtiens la bonne réponse :

Code : Tout sélectionner

 DNAIS = 04/04/2016 N = 33  # PERES =  20  # MERES = 30  Fmoy = 0
 DNAIS = 14/04/2016 N = 10  # PERES =  5  # MERES = 7  Fmoy = 0
 DNAIS = 16/08/2016 N = 35  # PERES =  23  # MERES = 26  Fmoy = 0
 DNAIS = 25/08/2016 N = 27  # PERES =  18  # MERES = 22  Fmoy = 0


Du coup je me demande qui pourrait m'expliquer pourquoi filter fonctionne ainsi
Je précise que si je tape (hors la boucle for) :

Code : Tout sélectionner

tmp<-BAR11 %>% filter(dnais=="14/04/2016")

j'obtiens bien un tableau de 10 lignes.

Puisque j'y suis, pourquoi ne vois-je pas le résultat du head(tmp) dans la boucle ?
Merci.

Hervé
Ingénieur de recherche INRAE Toulouse

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

Re: filter ou pas filter

Messagepar Pierre-Yves Berrard » 19 Fév 2020, 15:35

herve chapuis a écrit :Puisque j'y suis, pourquoi ne vois-je pas le résultat du head(tmp) dans la boucle ?

Je réponds à la question la plus facile : dans une boucle for, il faut préciser explicitement print(head(...)) pour afficher dans la console.
PY

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

Re: filter ou pas filter

Messagepar Pierre-Yves Berrard » 19 Fév 2020, 15:47

Pour la différence entre filter et crochets :

Le problème vient du fait qu'il y a une variable i dans la base qui porte le même nom que le compteur de la boucle.
dplyr::filter va chercher cette colonne en priorité.
Dans le cas de la syntaxe avec crochets, au contraire, c'est bien le compteur de la boucle qui va être comparé.
PY

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

Re: filter ou pas filter

Messagepar Mickael Canouil » 19 Fév 2020, 15:49

Bonjour,

Tout simplement parce-que la colonne "i" n'est pas égale à la colonne "dnais"

Code : Tout sélectionner

dta <- read.table(text = "    i  p  m sexe      dnais         IDANI        IDPERE        IDMERE F GEN annee
1 179  4 53    2 14/04/2016 GRI2016154875 GRI2015284632 GRI2015285783 0   1  2016
2 180  4 10    2 14/04/2016 GRI2016154879 GRI2015284632 GRI2015284760 0   1  2016
3 181 42 51    2 14/04/2016 GRI2016154956 GRI2015285653 GRI2015285761 0   1  2016
4 182 14 26    2 14/04/2016 GRI2016154997 GRI2015285269 GRI2015285449 0   1  2016
5 183 14 26    2 14/04/2016 GRI2016154999 GRI2015285269 GRI2015285449 0   1  2016
6 184 14 26    2 14/04/2016 GRI2016155000 GRI2015285269 GRI2015285449 0   1  2016"
, header = TRUE)


Code : Tout sélectionner

library(tidyverse)
<- "14/04/2016"


Code : Tout sélectionner

dta$i==dta$dnais
#> [1] FALSE FALSE FALSE FALSE FALSE FALSE  

Code : Tout sélectionner

filter(dta, dnais==i)
#>  [1] i      p      m      sexe   dnais  IDANI  IDPERE IDMERE F      GEN    annee 
#> <0 rows> (or 0-length row.names)  

Code : Tout sélectionner

filter(dta, dnais==!!i)
#>     i  p  m sexe      dnais         IDANI        IDPERE        IDMERE F GEN annee
#> 1 179  4 53    2 14/04/2016 GRI2016154875 GRI2015284632 GRI2015285783 0   1  2016
#> 2 180  4 10    2 14/04/2016 GRI2016154879 GRI2015284632 GRI2015284760 0   1  2016
#> 3 181 42 51    2 14/04/2016 GRI2016154956 GRI2015285653 GRI2015285761 0   1  2016
#> 4 182 14 26    2 14/04/2016 GRI2016154997 GRI2015285269 GRI2015285449 0   1  2016
#> 5 183 14 26    2 14/04/2016 GRI2016154999 GRI2015285269 GRI2015285449 0   1  2016
#> 6 184 14 26    2 14/04/2016 GRI2016155000 GRI2015285269 GRI2015285449 0   1  2016  

Code : Tout sélectionner

filter(dta, dnais=={{ i }})
#>     i  p  m sexe      dnais         IDANI        IDPERE        IDMERE F GEN annee
#> 1 179  4 53    2 14/04/2016 GRI2016154875 GRI2015284632 GRI2015285783 0   1  2016
#> 2 180  4 10    2 14/04/2016 GRI2016154879 GRI2015284632 GRI2015284760 0   1  2016
#> 3 181 42 51    2 14/04/2016 GRI2016154956 GRI2015285653 GRI2015285761 0   1  2016
#> 4 182 14 26    2 14/04/2016 GRI2016154997 GRI2015285269 GRI2015285449 0   1  2016
#> 5 183 14 26    2 14/04/2016 GRI2016154999 GRI2015285269 GRI2015285449 0   1  2016
#> 6 184 14 26    2 14/04/2016 GRI2016155000 GRI2015285269 GRI2015285449 0   1  2016  


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

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

Re: filter ou pas filter

Messagepar Logez Maxime » 19 Fév 2020, 16:06

Bonjour,

Pourquoi ne pas aller plus loin et faire le calcul directement sur tout le tableau ?

Code : Tout sélectionner

tab %>%
  group_by(dnais) %>%
  summarise(N = n(), PERES = n_distinct(p), MERES = n_distinct(m), Fmoy = mean(F))

Cordialement,
Maxime

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

Re: filter ou pas filter

Messagepar Mickael Canouil » 19 Fév 2020, 16:15

Logez Maxime a écrit :Bonjour,

Pourquoi ne pas aller plus loin et faire le calcul directement sur tout le tableau ?

Code : Tout sélectionner

tab %>% 
  group_by
(dnais) %>% 
  summarise
(= n(), PERES = n_distinct(p), MERES = n_distinct(m), Fmoy = mean(F)) 

Cordialement,
Maxime


Sans oublier le ungroup() ;)

Code : Tout sélectionner

library(dplyr

Code : Tout sélectionner

data.frame(Titanic) %>% 
  group_by
(Class, Age) %>% 
  summarise
(Freq = sum(Freq)) %>% 
  mutate
(Class = reorder(Class, Freq))
#> Error: Column `Class` can't be modified because it's a grouping variable     

Code : Tout sélectionner

data.frame(Titanic) %>% 
  group_by
(Class, Age) %>% 
  summarise
(Freq = sum(Freq)) %>% 
  ungroup
() %>% 
  mutate
(Class = reorder(Class, Freq))
#> # A tibble: 8 x 3
#>   Class Age    Freq
#>   <fct> <fct> <dbl>
#> 1 1st   Child     6
#> 2 1st   Adult   319
#> 3 2nd   Child    24
#> 4 2nd   Adult   261
#> 5 3rd   Child    79
#> 6 3rd   Adult   627
#> 7 Crew  Child     0
#> 8 Crew  Adult   885     
Mickaël
mickael.canouil.fr | rlille.fr

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

Re: filter ou pas filter

Messagepar Logez Maxime » 19 Fév 2020, 16:44

Mickael Canouil a écrit :Sans oublier le ungroup() ;)

Prendre de bonnes habitudes de codage c'est très bien, mais dans des cas simples comme celui-ci où il n'y a pas d'autres calculs derrière, je n'en vois pas trop l'utilité.
Tous les codes ici n'ont pas pour vocation à servir à la création de package, où à d'autres choses plus complexes.
A chacun ces marottes :)
Maxime

herve chapuis
Messages : 110
Enregistré le : 05 Déc 2008, 15:26

Re: filter ou pas filter

Messagepar herve chapuis » 19 Fév 2020, 16:49

Mickael Canouil a écrit :Bonjour,

Tout simplement parce-que la colonne "i" n'est pas égale à la colonne "dnais"

Code : Tout sélectionner

filter(dta, dnais==!!i)
#>     i  p  m sexe      dnais         IDANI        IDPERE        IDMERE F GEN annee
#> 1 179  4 53    2 14/04/2016 GRI2016154875 GRI2015284632 GRI2015285783 0   1  2016
#> 2 180  4 10    2 14/04/2016 GRI2016154879 GRI2015284632 GRI2015284760 0   1  2016
#> 3 181 42 51    2 14/04/2016 GRI2016154956 GRI2015285653 GRI2015285761 0   1  2016
#> 4 182 14 26    2 14/04/2016 GRI2016154997 GRI2015285269 GRI2015285449 0   1  2016
#> 5 183 14 26    2 14/04/2016 GRI2016154999 GRI2015285269 GRI2015285449 0   1  2016
#> 6 184 14 26    2 14/04/2016 GRI2016155000 GRI2015285269 GRI2015285449 0   1  2016   

Code : Tout sélectionner

filter(dta, dnais=={{ i }})
#>     i  p  m sexe      dnais         IDANI        IDPERE        IDMERE F GEN annee
#> 1 179  4 53    2 14/04/2016 GRI2016154875 GRI2015284632 GRI2015285783 0   1  2016
#> 2 180  4 10    2 14/04/2016 GRI2016154879 GRI2015284632 GRI2015284760 0   1  2016
#> 3 181 42 51    2 14/04/2016 GRI2016154956 GRI2015285653 GRI2015285761 0   1  2016
#> 4 182 14 26    2 14/04/2016 GRI2016154997 GRI2015285269 GRI2015285449 0   1  2016
#> 5 183 14 26    2 14/04/2016 GRI2016154999 GRI2015285269 GRI2015285449 0   1  2016
#> 6 184 14 26    2 14/04/2016 GRI2016155000 GRI2015285269 GRI2015285449 0   1  2016   


Cordialement,


Merci à tous !
En fait je ne n'ai pas tout saisi. Je ne connaissais pas le {{ }} ni le !! . Et une rapide recherche Google "R + {{ }}" ne me donne pas l'info recherchée.
Je ne doute pas que cela puisse être très utile.

Je retiens en tous cas l'option de Maxime pour tout faire en une seule opération (et sans boucle for !) :)
Ingénieur de recherche INRAE Toulouse

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

Re: filter ou pas filter

Messagepar Mickael Canouil » 20 Fév 2020, 08:47

Logez Maxime a écrit :
Mickael Canouil a écrit :Sans oublier le ungroup() ;)

Prendre de bonnes habitudes de codage c'est très bien, mais dans des cas simples comme celui-ci où il n'y a pas d'autres calculs derrière, je n'en vois pas trop l'utilité.
Tous les codes ici n'ont pas pour vocation à servir à la création de package, où à d'autres choses plus complexes.
A chacun ces marottes :)
Maxime


Je suis tout à fait d'accord. Je n'ai pas systématiquement un ungroup() après le summarise() (seul exception dans mon cas).
Dans le cas présent, ne sachant pas la finalité du bout de code, c'est préférable de l'ajouter pour éviter tout risque.

herve chapuis a écrit :Merci à tous !
En fait je ne n'ai pas tout saisi. Je ne connaissais pas le {{ }} ni le !! . Et une rapide recherche Google "R + {{ }}" ne me donne pas l'info recherchée.
Je ne doute pas que cela puisse être très utile.

Je retiens en tous cas l'option de Maxime pour tout faire en une seule opération (et sans boucle for !) :)

Le "curly-curly" {{ }} et le "bang-bang" !! (il y a aussi le "big bang" !!!) sont des opérateurs du package rlang.
C'est ce qui s'applle la "tidy evaluation" et c'est ce qui est utilisé dans tout le tidyverse.
https://tidyeval.tidyverse.org/

Discuté sur ce fil, il n'y a pas longtemps: viewtopic.php?f=3&t=9882&p=45706#p45706
Mickaël
mickael.canouil.fr | rlille.fr


Retourner vers « Questions en cours »

Qui est en ligne

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