dplyr group_by summarise avec une donnee manquante

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

Magali Teurlai
Messages : 62
Enregistré le : 20 Oct 2009, 14:40

dplyr group_by summarise avec une donnee manquante

Messagepar Magali Teurlai » 14 Oct 2020, 19:25

Bonjour,

j'ai deux tableaux de données, concernant des régions géographiques, ayant chacune un identifiant unique.
- l'un contient, pour certains identifiants/régions, l'identifiant et une date (aléatoire)
- l'autre contient, pour tous les identifiants, les données journalières de température sur 13 jours.

Code : Tout sélectionner

df1 <- data.frame(id       = LETTERS[1:2],
                  Date.max = as.Date(c("2020-02-10","2020-02-13")))
df2 <- data.frame(id   = rep(LETTERS[1:3], each=13),
                  Date = rep(seq.Date(as.Date("2020-02-01"), as.Date("2020-02-13"), by="days"), 3),
                  temp = sample(0:35, 39, replace=T))

> df1
  id   Date.max
1  A 2020-02-10
2  B 2020-02-13

> df2
   id       Date temp
1   A 2020-02-01    1
2   A 2020-02-02    4
3   A 2020-02-03   30
4   A 2020-02-04    7
5   A 2020-02-05   26
6   A 2020-02-06   33
7   A 2020-02-07   13
8   A 2020-02-08   21
9   A 2020-02-09   32
10  A 2020-02-10   11
11  A 2020-02-11   30
12  A 2020-02-12    0
13  A 2020-02-13   12
14  B 2020-02-01    5
15  B 2020-02-02    4
16  B 2020-02-03   33
17  B 2020-02-04    1
18  B 2020-02-05   31
19  B 2020-02-06   32
20  B 2020-02-07    5
21  B 2020-02-08   19
22  B 2020-02-09   19
23  B 2020-02-10   19
24  B 2020-02-11    8
25  B 2020-02-12    6
26  B 2020-02-13   35
27  C 2020-02-01   11
28  C 2020-02-02   15
29  C 2020-02-03   13
30  C 2020-02-04    1
31  C 2020-02-05   18
32  C 2020-02-06    3
33  C 2020-02-07   33
34  C 2020-02-08    9
35  C 2020-02-09   23
36  C 2020-02-10   31
37  C 2020-02-11   17
38  C 2020-02-12   35
39  C 2020-02-13    0




je cherche à obtenir un tableau où, pour chaque identifiant/région, je compte le nombre de jours où la température a dépassé un certain seuil dans les 5 jours précédent la date contenue dans df1.

Code : Tout sélectionner

library(dplyr)
library(lubridate)
nb.days <- 5
dat <- df2 %>%
          left_join(df1, by="id") %>%
          group_by(id) %>%
          summarise(nb.days.temp.30 = length(temp[between(Date, Date.max-nb.days, Date.max) & temp > 30])) %>%
          as.data.frame()

> dat
  id nb.days.temp.30
1  A               2
2  B               1
3  C               3


> df2 %>%
+           left_join(df1, by="id")
   id       Date temp   Date.max
1   A 2020-02-01    1 2020-02-10
2   A 2020-02-02    4 2020-02-10
3   A 2020-02-03   30 2020-02-10
4   A 2020-02-04    7 2020-02-10
5   A 2020-02-05   26 2020-02-10
6   A 2020-02-06   33 2020-02-10
7   A 2020-02-07   13 2020-02-10
8   A 2020-02-08   21 2020-02-10
9   A 2020-02-09   32 2020-02-10
10  A 2020-02-10   11 2020-02-10
11  A 2020-02-11   30 2020-02-10
12  A 2020-02-12    0 2020-02-10
13  A 2020-02-13   12 2020-02-10
14  B 2020-02-01    5 2020-02-13
15  B 2020-02-02    4 2020-02-13
16  B 2020-02-03   33 2020-02-13
17  B 2020-02-04    1 2020-02-13
18  B 2020-02-05   31 2020-02-13
19  B 2020-02-06   32 2020-02-13
20  B 2020-02-07    5 2020-02-13
21  B 2020-02-08   19 2020-02-13
22  B 2020-02-09   19 2020-02-13
23  B 2020-02-10   19 2020-02-13
24  B 2020-02-11    8 2020-02-13
25  B 2020-02-12    6 2020-02-13
26  B 2020-02-13   35 2020-02-13
27  C 2020-02-01   11       <NA>
28  C 2020-02-02   15       <NA>
29  C 2020-02-03   13       <NA>
30  C 2020-02-04    1       <NA>
31  C 2020-02-05   18       <NA>
32  C 2020-02-06    3       <NA>
33  C 2020-02-07   33       <NA>
34  C 2020-02-08    9       <NA>
35  C 2020-02-09   23       <NA>
36  C 2020-02-10   31       <NA>
37  C 2020-02-11   17       <NA>
38  C 2020-02-12   35       <NA>
39  C 2020-02-13    0       <NA>

date.check <- as.Date(NA)
foo <-  between(df2[df2$id %in% "id", "Date"], date.check-5, date.check)

> foo
logical(0)

> foo & T
logical(0)



Si je comprends, le "3" pour la région "C" est le nb de jours où la temp dépasse 30 degrés sur l'ensemble de la période, puisque qu'aucune ligne en particulier n'est sélectionnée.
Comment remédier à ce problème et obtenir un "NA" si l'identifiant du df2 est manquant dans le df1 (je pourrais filtrer avant de calculer, mais ça ne m'arrange pas, j'ai en fait d'autres colonnes pour lesquelles je souhaiterais conserver les id de df2 qui ne sont pas dans df1).
je pourrais aussi remplacer les valeurs de nb de jour par NA lorsque la Date.max est NA. Mais j'ai un paquet de colonnes à traiter.

J'ai essayé dans l'autre sens aussi:

Code : Tout sélectionner

dat <- df1 %>%
         rowwise() %>%
         mutate(nb.days.temp.30 = length(df2$temp[between(df2$Date, Date.max-nb.days, Date.max) & df2$temp > 30 & df2$id %in% id]))


Bon, là sur cet exemple ça fonctionne, mais avec mes tableaux de données qui ont bcp plus de lignes, ça ne marche pas. Je n'arrive pas à spécifier/mettre une condition sur la date et l'id en même temps (ça marche si je mets que l'id, et si je mets que la date, mais pas les deux).

Merci bcp par avance,
Magali

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

Re: dplyr group_by summarise avec une donnee manquante

Messagepar Mickael Canouil » 15 Oct 2020, 09:19

Bonjour,

vous souhaitez quelque-chose comme suit ?

Code : Tout sélectionner

library(dplyr)
library(lubridate)
nb.days <- 5

Code : Tout sélectionner

set.seed(2020101511)
df1 <- data.frame(
  
id LETTERS[1:2],
  
Date.max = as.Date(c("2020-02-10""2020-02-13"))
)
df2 <- data.frame(
  
id rep(LETTERS[1:3], each 13),
  
Date rep(seq.Date(as.Date("2020-02-01"), as.Date("2020-02-13"), by "days"), 3),
  
temp rnorm(mean 25sd 539)

Code : Tout sélectionner

df2 %>%
  
left_join(df1by "id") %>% 
  
group_by(id) %>% 
  
summarise(sum(abs(Date Date.max) <= nb.days temp 30), .groups "drop")
#> # A tibble: 3 x 2
#>   id        N
#>   <chr> <int>
#> 1 A         2
#> 2 B         3
#> 3 C        NA 


PS : Merci pour le jeu de donnée reproductible (modifié un peu pour avoir des résultats).

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

Magali Teurlai
Messages : 62
Enregistré le : 20 Oct 2009, 14:40

Re: dplyr group_by summarise avec une donnee manquante

Messagepar Magali Teurlai » 15 Oct 2020, 12:16

Bonjour,

Oui, ça répond à mon problème. Merci beaucoup !

Je vais essayer de comprendre l'argument .groups. L'aide de dplyr est toujours comme du chinois pour moi..

Magali

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

Re: dplyr group_by summarise avec une donnee manquante

Messagepar Pierre-Yves Berrard » 15 Oct 2020, 12:43

Bonjour,
.groups indique quoi faire des groupes créés par group_by(). Ici, Mickael a choisi de ne pas les garder ("drop").
PY

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

Re: dplyr group_by summarise avec une donnee manquante

Messagepar Mickael Canouil » 15 Oct 2020, 13:07

Pour être précis, c'est les meta-données de groupes que j'ai explicitement dit de ne pas garder.
Essayez, le même code sans cet argument et lisez le message concernant le comportement par défaut de summarise depuis la version 1.0.0 de dplyr.

Une alternative de code avec un résultat sans les valeurs manquantes:

Code : Tout sélectionner

df2 %>%
  left_join(df1, by = "id") %>%
  mutate(id = factor(id)) %>% 
  filter
(abs(Date - Date.max) <= nb.days & temp > 30) %>% 
  count
(id, .drop = FALSE)
#>   id n
#> 1  A 2
#> 2  B 3
#> 3  C 0       


EDIT : la meta-donnée de groupe dans le cas présent est simplement l'information qui dit que la colonne "id" du data.frame/tibble sert pour découper (virtuellement) celui-ci.
Mickaël
mickael.canouil.fr | rlille.fr

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

Re: dplyr group_by summarise avec une donnee manquante

Messagepar Pierre-Yves Berrard » 15 Oct 2020, 13:22

Mickael Canouil a écrit :Pour être précis, c'est les meta-données de groupes que j'ai explicitement dit de ne pas garder.

Il faut parfois savoir sacrifier un peu de rigueur pour un peu de clarté. ;-)
PY

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

Re: dplyr group_by summarise avec une donnee manquante

Messagepar Mickael Canouil » 15 Oct 2020, 13:26

Pierre-Yves Berrard a écrit :
Mickael Canouil a écrit :Pour être précis, c'est les meta-données de groupes que j'ai explicitement dit de ne pas garder.

Il faut parfois savoir sacrifier un peu de rigueur pour un peu de clarté. ;-)

Je suis du même avis^^
Ceci dit, "de ne pas les [groupes] garder" peut porter à confusion puisque que "id" est bien toujours présent, donc "garder".
Mickaël
mickael.canouil.fr | rlille.fr


Retourner vers « Questions en cours »

Qui est en ligne

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