Utilisateurs autorisés, Bureaucrates, Ingénieurs ISIG, Utilisateurs autorisés automatiquement, Masqueurs de modifications
385
modifications
(ajouts de convs questions-r) |
(rajout en vrac) |
||
Ligne 65 : | Ligne 65 : | ||
Regarde ?na.approx pour plus de détails sur son fonctionnement | Regarde ?na.approx pour plus de détails sur son fonctionnement | ||
== Programmation fonctionnelle | |||
Question de martiste | |||
J'ai un jeu de données avec des températures à pas de temps horaire, le tout sur plusieurs années (et plusieurs stations). J'aimerais connaître, pour chaque année et pour chaque station, le nombre de séquences où la température a dépassé les 19°C, ainsi que la durée de la séquence la plus longue. Avec une boucle, j'aurais créé un nouveau champ pour lequel j'incrémente une valeur de séquence à chaque fois que T>19 et que T-1<19. Je regarde la valeur max de ma séquence, et la longueur max de ces séquences également. Mais comment faire sans boucle ? | |||
dat <- readxl::read_excel("~/Téléchargements/BIE0-3_donnees.xlsx") | |||
library(dplyr) | |||
result=dat %>% | |||
mutate(hot=chmes_valeur>19) %>% | |||
mutate(hot_prev=lag(hot,1)) %>% | |||
mutate(change=hot & !hot_prev) %>% | |||
mutate(sequence=cumsum(change)) | |||
faut peaufiner, ça fait pas exactement ce qu'il faut | |||
faudrait aussi faire le changement "inverse", quand il fait pas chaud et qu'il faisait chaud avant | |||
pour isoler toutes les "séquences", chaudes ou froides | |||
Faut aussi bien faire en sorte que tout soit rangé dans l'ordre temporel avant de faire tourner le truc (ce qui n'est pas le cas ici, vu que j'ai pas groupé par station par exemple) | |||
martiste 23/08/2021 | |||
Ouip | |||
Alors, une fois trié et groupé, j'étais parti sur ça : | |||
dat %>% | |||
mutate(seq = case_when(chmes_valeur> 19 & lag(chmes_valeur<= 19) ~ 1, | |||
chmes_valeur> 19 & lag(chmes_valeur> 19) ~ 1, | |||
TRUE ~ 0)) | |||
Ca m'isole mes séquences, mais pas d'incréments | |||
LiseV — 23/08/2021 | |||
et quand tu essaies comme ça, ça fonctionne? | |||
martiste — 23/08/2021 | |||
Non | |||
LiseV — 23/08/2021 | |||
hmmm | |||
tu lui as bien refait "tourner" la déf de la fonction? | |||
martiste — 23/08/2021 | |||
rreur : Problem with mutate() column data. | |||
i data = purrr::map_dfr(data, get_sequences(., Temp = 19)). | |||
x Problem with mutate() column change. | |||
i change = case_when(chmes_valeur > Temp & lag(chmes_valeur <= Temp) ~ 1, TRUE ~ 0). | |||
x objet 'chmes_valeur ' introuvable | |||
LiseV — 23/08/2021 | |||
pour écraser l'ancienne "get_sequences() par la nouvelle?? | |||
martiste — 23/08/2021 | |||
Moui... | |||
LiseV — 23/08/2021 | |||
hihi | |||
ça valait le coup de demander, on sait jamais | |||
je vois pourquoi le map fonctionne pas, pas pourquoi l'appel simple fonctionne pas | |||
Chez moi, ça, ça fonctionne: | |||
get_sequences=function(donnees, Temp){ | |||
result = donnees %>% | |||
mutate(change = case_when(chmes_valeur > Temp & lag(chmes_valeur <= Temp) ~ 1, | |||
TRUE ~ 0)) %>% | |||
mutate(sequence = case_when(chmes_valeur > Temp ~ cumsum(as.numeric(change)), | |||
TRUE ~ NA_real_)) | |||
return(result) | |||
} | |||
result= dat %>% | |||
group_by(chmes_coderhj,chmes_anneebiol) %>% | |||
tidyr::nest() %>% | |||
mutate(data=purrr::map(data,get_sequences,Temp=19)) %>% | |||
tidyr::unnest(cols=c(data)) | |||
ou bien (autre syntaxe possible pour map), comme ça: | |||
result= dat %>% | |||
group_by(chmes_coderhj,chmes_anneebiol) %>% | |||
tidyr::nest() %>% | |||
mutate(data=purrr::map(data,~get_sequences(.,Temp=19))) %>% | |||
tidyr::unnest(cols=c(data)) | |||
martiste — 23/08/2021 | |||
Magique ! | |||
Tu saurais dire la différence entre les deux ?! | |||
LiseV — 23/08/2021 | |||
entre ta version et ma version? | |||
martiste — 23/08/2021 | |||
Entre avec et sans '~' devant la fct | |||
LiseV — 23/08/2021 | |||
ou entre la syntaxe 1 et la syntaxe 2? | |||
ben tu l'as, la différence, c'est le "~", lol | |||
soit map attend le nom d'une fonction | |||
dans ce cas l'argument sur lequel il itère doit être le premier argument de la fonction | |||
soit map attend une formule (précédée d'un "~", donc) | |||
dans ce cas il y a un peu plus de souplesse sur la position de l'argument sur lequel on itère | |||
Tu pourrais dire ~ get_sequences(data, Temp=.) pour itérer sur une variable qui donnerait un seuil de température, par exemple | |||
et non plus itérer sur le premier argument, "data" | |||
(on est d'accord, sur le "fond" du traitement cet exemple n'a guère de sens) | |||
martiste — 23/08/2021 | |||
😊 mais je pense que j'ai saisi l'essentiel... | |||
Merci ! | |||
LiseV — 23/08/2021 | |||
Si tu donnes le nom de la fonction, tu peux quand-même rajouter des arguments "secondaires" | |||
mais tu les rajoutes directement comme arguments optionnels à la fonction "map", pas dans un simulacre d'appel à la fonction que tu itères | |||
C'est un peu compliqué ces histoires de syntaxe mais une fois que c'est acquis c'est bien pratique 😉 | |||
Dans un cas "simple" (comme ici) il vaut mieux utiliser la première syntaxe je trouve | |||
c'est ce qui est prévu "par défaut" pour faire tourner purrr::map | |||
L'utilisation des formules c'est un subtilité introduite pour gérer les fonctions qui n'ont pas les arguments "dans l'ordre le plus pratique au regard de ce qu'on souhaite faire". | |||
martiste — 23/08/2021 | |||
Okay, bien reçu m'dame ! | |||
martiste — 23/08/2021 | |||
Et, pour finir, si je veux en sortir 1) le nombre total de séquences, et 2) la durée de la séquence la plus longue, est-ce que tu me conseilles de l'inclure dans la fct 'get_sequences', ou de repartir des résultats de cette fonction et d'alimenter une nouvelle ? | |||
LiseV — 23/08/2021 | |||
ben pour le coup, le nombre de total de séquences et la durée de la séquence la plus longue, ce sont des "agrégations" de ce que tu as fait avant. | |||
Or, il est possible que tu veuilles utiliser les résultats de get_sequences tels quels (par exemple pour des graphiques) | |||
donc il vaut mieux faire en sorte que cette agrégation ait lieu dans un second temps | |||
=> définition d'une nouvelle fonction par exemple | |||
En revanche, je pense que tu pourrais faire tourner ce calcul avant de "unnest" | |||
car tes séquences n'ont pas des identifiants uniques en l'état | |||
(les identifiants ne sont uniques que au sein des sous-jeux de données imbriqués) | |||
martiste — 23/08/2021 | |||
Yes | |||
martiste — 23/08/2021 | |||
avec n_distinct, je chope le nb total de séquences | |||
Pour choper la durée de la séquence la plus longue, tu suggérerais quoi ? | |||
LiseV — 23/08/2021 | |||
tu calcules les durées pour toutes les séquences, puis tu calcules le max | |||
hihi | |||
bon j'imagine que si tu me poses cette question, c'est que le calcul des durées pose pb? | |||
max(time)-min(time) fait pas le job? | |||
en ayant formatté time avec lubridate? | |||
(je dis "time" mais remplace par le nom de variable ad hoc 😉 ) | |||
martiste — 23/08/2021 | |||
Ah, j'étais parti sur complétement autre chose du coup.... | |||
LiseV — 23/08/2021 | |||
ben, group_by(sequence) %>% summarise(duration=max(time)-min(time)) me semble l'option la plus évidente a priori? | |||
et même group_by(sequence) %>% summarise(duration=max(time)-min(time)) %>% top_n(1,duration), pour aller vraiment au bout du process | |||
martiste — 23/08/2021 | |||
Et tu peux rajouter un 'group_by' au sein d'un 'summarise' ? | |||
LiseV — 23/08/2021 | |||
?? | |||
tu peux faire group_by %>% mutate %>% ungroup() %>% group_by(autre chose) %>% summarise | |||
mais je sais pas si ça répond à ta question | |||
martiste — 23/08/2021 | |||
J'essaie de mettre les deux dans une même fonction, c'est pour ça | |||
summarise(n = n_distinct(sequence, na.rm = TRUE)) | |||
et | |||
group_by(sequence) %>% summarise(duration=max(time)-min(time)) %>% top_n(1,duration) | |||
LiseV — 23/08/2021 | |||
Là tu pourrais faire group_by(sequence) %>% summarise(duration=max(time)-min(time)) %>% ungroup() %>% mutate(n_sequences=n()) %>% top_n(1,duration) | |||
martiste — 23/08/2021 | |||
Qui ne se font pas au même niveau de groupage | |||
Okay, yé test ça tout dé souite | |||
LiseV — 23/08/2021 | |||
le mutate (n_sequences=n()) te rajoute le nombre de séquences sans résumer (ça répète autant de fois que nécessaire la valeur n_sequences) | |||
du coup après quand tu gardes que la top duration t'as quand-même l'info qu'il te faut | |||
martiste — 23/08/2021 | |||
Ahh, okay je vois. Mais il faut que j'enlève tous mes 'NA's, parce que c'est eux les 'top duration' pour le moment... 😉 | |||
LiseV — 23/08/2021 | |||
ah oui effectivement 🙂 | |||
martiste — 23/08/2021 | |||
pfiou ! Je crois que j'ai réussi | |||
LiseV — 23/08/2021 | |||
🎆 | |||
martiste — 23/08/2021 | |||
Okay, la fonction 'top_n()', elle prend le premier élément d'un vecteur ordonné ? Ou elle prend la valeur max, et donc s'il y en a plusieurs identiques, elle va en sortir plusieurs ? | |||
LiseV — 23/08/2021 | |||
non elle prend le max | |||
c'est pour ça que tu lui précises aussi une variable | |||
pour lui dire le max en terme de quoi | |||
martiste — 23/08/2021 | |||
Mmh, okay, c'est pour ça que j'ai des doublons | |||
martiste — 23/08/2021 | |||
Est-ce qu'il existe un moyen plus rapide de joindre plus de 2 tables que de répéter des jointures successives ? | |||
(et plus élégant, au passage) | |||
== Annonces de nouveau packages R == | == Annonces de nouveau packages R == |