« Questions-r » : différence entre les versions

De Wiki ISIG
Aller à la navigation Aller à la recherche
(rajout en vrac)
Aucun résumé des modifications
 
(9 versions intermédiaires par 2 utilisateurs non affichées)
Ligne 3 : Ligne 3 :
== Manipulation d'un nom de fichier ==
== Manipulation d'un nom de fichier ==


'''Question posée par martiste'''
🙋 '''Question posée par martiste'''


Comment récupérer un morceau du nom du fichier ? Par exemple à partir de '''"zarsqdfqsfd33vezre20618402.csv''' on veut récupérer '''20618402'''.
Comment récupérer un morceau du nom du fichier ? Par exemple à partir de '''"zarsqdfqsfd33vezre20618402.csv''' on veut récupérer '''20618402'''.


'''Réponse de lvaudor et sdunesme'''
🧑‍🏫 '''Réponse de lvaudor et sdunesme'''


Combi des '''expressions régulières''' et de la fonction '''basename()''':
Combi des '''expressions régulières''' et de la fonction '''basename()''':
Ligne 20 : Ligne 20 :
== Reformattage d'un fichier en "longueur" ==
== Reformattage d'un fichier en "longueur" ==


'''Question de mcottet'''
🙋 '''Question de mcottet'''


J'ai une bdd avec plusieurs variables catégorielles qui portent une info similaire (est ce que les gens ont vu l'espèce A un peu, bcp, passionnément, à la folie ; idem pour l'espèce B, C...). Et j'aimerais faire une somme pour savoir combien de fois l'individu 1 a répondu un peu à l'ensemble des espèces proposées, bcp à l'ensemble des espèces...
J'ai une bdd avec plusieurs variables catégorielles qui portent une info similaire (est ce que les gens ont vu l'espèce A un peu, bcp, passionnément, à la folie ; idem pour l'espèce B, C...). Et j'aimerais faire une somme pour savoir combien de fois l'individu 1 a répondu un peu à l'ensemble des espèces proposées, bcp à l'ensemble des espèces...
il y a 18 espèces (donc 18 variables)
il y a 18 espèces (donc 18 variables)


'''Réponse de lvaudor'''
🧑‍🏫 '''Réponse de lvaudor'''


'''tidyr::pivot_longer()'''
'''tidyr::pivot_longer()'''
Ligne 39 : Ligne 39 :
A une époque, ça s'appelait pas pivot_wider() et pivot_longer() mais spread() et gather()
A une époque, ça s'appelait pas pivot_wider() et pivot_longer() mais spread() et gather()
(mais c'était moins explicite comme nom)
(mais c'était moins explicite comme nom)
🙋  '''Question de martiste'''
J'arrive à aller chercher différents fichiers excel et à les "rbind" avec ça :
temp_data <- list.files(path_to_files, pattern = '*.xlsx') %>%
  purrr::map_dfr(~readxl::read_xlsx(paste0(path_to_files, .x)))
Maintenant, chaque fichier contient un champ "date"... Comment pourrais-je faire pour qu'au lieu de les ajouter à la suite les uns des autres, je les joignent par date ?
J'ai 15 fichiers excels, que, jusqu'ici, je lis à la suite et colle les uns après les autres. Ce qu'il me faudrait, à présent, c'est une sorte de 'recast' en fait, mais avec comme identifiant commun une variable lubridate. Pour qu'au lieux d'avoir une colonne qui m'indique le nom du site (= le nom du fichier en entrée) et une autre une valeur de température, je me retrouve avec un tableau 'large' avec comme nom de colonne chacune des stations contenant sa valeur de température.
'''Réponse de defuneste et sduneme'''
do.call et/ou pivot_wider [[https://tidyr.tidyverse.org/articles/pivot.html#wider]]
C'est qu'est ce que j'avais essayé au départ, mais ça n'marchait pas...
Parce que j'avais une variable 'id' qui empêchait le regroupement de se faire correctement
<syntaxhighlight lang="r">
df %>%
  select(timestamp, station, temperature) %>%
  pivot_wider(names_from=station, values_from=temperature)
</syntaxhighlight>
'''Solution non-purrr'''
Chargement des library / installation
<syntaxhighlight lang="r">
# install.packages("tidyverse")
# install.packages("readxl")
# les données sont dans un répertoire enfant:
file_path <- list.files(path = "data",
                        pattern = "*.xlsx",
                        full.names =  TRUE) # pas mal pour t'economiser un paste0
# une fonction qui lis un xlss
lis_un_fichier_excel <- function(un_chemin_de_fichier) {
                                  readxl::read_xlsx(un_chemin_de_fichier)
}
# on teste
lis_un_fichier_excel(file_path[1])
# une liste de df
une_liste_de_tableau <- lapply(file_path, "lis_un_fichier_excel")
# on ajoute les lignes
mon_tableau_en_tidy <- do.call("rbind", une_liste_de_tableau)
mon_tableau_en_tidy
</syntaxhighlight>


== Complétion des données d'une série temporelle ==
== Complétion des données d'une série temporelle ==


'''Question de Théo'''
🙋 '''Question de Théo'''


j'ai une série temporelle de hauteurs d'eau à pas de temps 15 min, mais il y a plein de trous dedans et je voudrais la compléter, en ajoutant l'heure manquante, et la hauteur d'eau manquante (moyenne de t-15 et t+15 si t est la valeur manquante).  
j'ai une série temporelle de hauteurs d'eau à pas de temps 15 min, mais il y a plein de trous dedans et je voudrais la compléter, en ajoutant l'heure manquante, et la hauteur d'eau manquante (moyenne de t-15 et t+15 si t est la valeur manquante).  


'''Réponse de martiste'''
🧑‍🏫 '''Réponse de martiste'''


il faut que tu commences par te créer un index de temps à l'intervalle voulu, depuis ta première valeur jusqu'à la dernière, à laquelle tu joins ton jeu de données réel. Les trous vont alors apparaître en 'NA'. Et si tu n'as que quelques trous de jamais plus de 2 intervalles, tu peux utiliser la fonction zoo::na_approx() qui fera l'affaire...
il faut que tu commences par te créer un index de temps à l'intervalle voulu, depuis ta première valeur jusqu'à la dernière, à laquelle tu joins ton jeu de données réel. Les trous vont alors apparaître en 'NA'. Et si tu n'as que quelques trous de jamais plus de 2 intervalles, tu peux utiliser la fonction zoo::na_approx() qui fera l'affaire...
Ligne 66 : Ligne 119 :
Regarde ?na.approx pour plus de détails sur son fonctionnement
Regarde ?na.approx pour plus de détails sur son fonctionnement


== Programmation fonctionnelle
== Programmation fonctionnelle ==


Question de martiste
🙋 '''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 ?
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")
🧑‍🏫 '''Réponse de lvaudor'''
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
<syntaxhighlight lang="r">
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){
get_sequences=function(donnees, Temp){
   result = donnees %>%  
   result = donnees %>%  
Ligne 127 : Ligne 141 :
   mutate(data=purrr::map(data,get_sequences,Temp=19)) %>%  
   mutate(data=purrr::map(data,get_sequences,Temp=19)) %>%  
   tidyr::unnest(cols=c(data))
   tidyr::unnest(cols=c(data))
</syntaxhighlight>
ou bien (autre syntaxe possible pour map), comme ça:
ou bien (autre syntaxe possible pour map), comme ça:
<syntaxhighlight lang="r">
result= dat %>%  
result= dat %>%  
   group_by(chmes_coderhj,chmes_anneebiol) %>%  
   group_by(chmes_coderhj,chmes_anneebiol) %>%  
Ligne 133 : Ligne 151 :
   mutate(data=purrr::map(data,~get_sequences(.,Temp=19))) %>%  
   mutate(data=purrr::map(data,~get_sequences(.,Temp=19))) %>%  
   tidyr::unnest(cols=c(data))
   tidyr::unnest(cols=c(data))
martiste — 23/08/2021
</syntaxhighlight>
Magique !
 
Tu saurais dire la différence entre les deux ?!
Différence entre avec et sans '~' devant la fonction:
LiseV — 23/08/2021
 
entre ta version et ma version?
* soit map attend le nom d'une fonction
martiste — 23/08/2021
: Dans ce cas l'argument sur lequel il itère doit être le premier argument de la fonction
Entre avec et sans '~' devant la fct
* soit map attend une formule (précédée d'un "~", donc)
LiseV — 23/08/2021
: Dans ce cas il y a un peu plus de souplesse sur la position de l'argument sur lequel on itère
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
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"
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"
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
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".  
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 !
🙋 '''Question complémentaire'''
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 ?
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.  
'''🧑‍🏫 Réponse '''
Or, il est possible que tu veuilles utiliser les résultats de get_sequences tels quels (par exemple pour des graphiques)  
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.
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)
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
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 ?
Pour choper la durée de la séquence la plus longue, tu suggérerais quoi ?
LiseV — 23/08/2021
<syntaxhighlight lang="r">
tu calcules les durées pour toutes les séquences, puis tu calcules le max
... %>%  
hihi
  group_by(sequence) %>%
bon j'imagine que si tu me poses cette question, c'est que le calcul des durées pose pb?
  summarise(duration=max(time)-min(time)) %>%
max(time)-min(time) fait pas le job?
  ungroup() %>%
en ayant formatté time avec lubridate?
  mutate(n_sequences=n()) %>%
(je dis "time" mais remplace par le nom de variable ad hoc  😉 )
  top_n(1,duration)
martiste — 23/08/2021
</syntaxhighlight>
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)
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
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 ==
Ligne 238 : Ligne 201 :
== Annonces de formations/tutos/conf ==
== Annonces de formations/tutos/conf ==


supports SIGR [[https://sigr2021.github.io/site/index.html]] par defuneste
* [[https://sigr2021.github.io/site/index.html|supports SIGR]] recommandé par defuneste
* [[https://blog.sellorm.com/2017/12/18/learn-to-write-command-line-utilities-in-r/|billet command line utilities in R]] recommandé par defuneste
* [[https://geocompr.robinlovelace.net/| geocomputation with R]] recommandé par defuneste
 
== Continuer l'édition ==
 
sur Discord, channel questions-r:
 
!saveconv 882172361246396427 883000807585374258
[[Catégorie:R]]

Version actuelle datée du 18 janvier 2022 à 11:24

Cette page reprend la "substantifique moelle" des échanges ayant eu lieu sur le channel questions-r du Discord d'ISIG.

Manipulation d'un nom de fichier

🙋 Question posée par martiste

Comment récupérer un morceau du nom du fichier ? Par exemple à partir de "zarsqdfqsfd33vezre20618402.csv on veut récupérer 20618402.

🧑‍🏫 Réponse de lvaudor et sdunesme

Combi des expressions régulières et de la fonction basename():

"za/rsqd/fqsfd33vezre20618402.csv" %>%
  basename() %>% # donne "fqsfd33vezre20618402.csv"
  stringr::str_replace(".csv","") %>% # donne "fqsfd33vezre20618402"
  stringr::str_extract(pattern=".{8}(?=\\.$)") # donne "20618402"

Reformattage d'un fichier en "longueur"

🙋 Question de mcottet

J'ai une bdd avec plusieurs variables catégorielles qui portent une info similaire (est ce que les gens ont vu l'espèce A un peu, bcp, passionnément, à la folie ; idem pour l'espèce B, C...). Et j'aimerais faire une somme pour savoir combien de fois l'individu 1 a répondu un peu à l'ensemble des espèces proposées, bcp à l'ensemble des espèces... il y a 18 espèces (donc 18 variables)

🧑‍🏫 Réponse de lvaudor

tidyr::pivot_longer()

Dans ta version de BDD, tu as 18 variables différentes Mais en fait, tu pourrais considérer que ces 18 colonnes correspondent en fait à 2 colonnes (une colonne "espece" et une colonne "valeur") Tu cherches de ce fait à répéter l'ensemble des autres colonnes (toutes celles qui ne font pas partie des 18 sus-mentionnées) 18 fois, mais "en hauteur". Du coup, ton tableau qui est "plutôt large" devient un tableau "plutôt long"

Dans l'appel à la fonction, tu précises quelles sont les variables que tu récupères pour les mettre "en long" et toutes les autres, il les répète à l'identique autant de fois que nécessaire

A une époque, ça s'appelait pas pivot_wider() et pivot_longer() mais spread() et gather() (mais c'était moins explicite comme nom)

🙋 Question de martiste

J'arrive à aller chercher différents fichiers excel et à les "rbind" avec ça : temp_data <- list.files(path_to_files, pattern = '*.xlsx') %>%

 purrr::map_dfr(~readxl::read_xlsx(paste0(path_to_files, .x)))

Maintenant, chaque fichier contient un champ "date"... Comment pourrais-je faire pour qu'au lieu de les ajouter à la suite les uns des autres, je les joignent par date ?

J'ai 15 fichiers excels, que, jusqu'ici, je lis à la suite et colle les uns après les autres. Ce qu'il me faudrait, à présent, c'est une sorte de 'recast' en fait, mais avec comme identifiant commun une variable lubridate. Pour qu'au lieux d'avoir une colonne qui m'indique le nom du site (= le nom du fichier en entrée) et une autre une valeur de température, je me retrouve avec un tableau 'large' avec comme nom de colonne chacune des stations contenant sa valeur de température.

Réponse de defuneste et sduneme

do.call et/ou pivot_wider [[1]]

C'est qu'est ce que j'avais essayé au départ, mais ça n'marchait pas... Parce que j'avais une variable 'id' qui empêchait le regroupement de se faire correctement

df %>% 
  select(timestamp, station, temperature) %>%
  pivot_wider(names_from=station, values_from=temperature)

Solution non-purrr

Chargement des library / installation

# install.packages("tidyverse")
# install.packages("readxl")

# les données sont dans un répertoire enfant:

file_path <- list.files(path = "data",
                        pattern = "*.xlsx",
                        full.names =  TRUE) # pas mal pour t'economiser un paste0

# une fonction qui lis un xlss
lis_un_fichier_excel <- function(un_chemin_de_fichier) { 
                                  readxl::read_xlsx(un_chemin_de_fichier)
}

# on teste
lis_un_fichier_excel(file_path[1])

# une liste de df
une_liste_de_tableau <- lapply(file_path, "lis_un_fichier_excel")

# on ajoute les lignes
mon_tableau_en_tidy <- do.call("rbind", une_liste_de_tableau)
mon_tableau_en_tidy

Complétion des données d'une série temporelle

🙋 Question de Théo

j'ai une série temporelle de hauteurs d'eau à pas de temps 15 min, mais il y a plein de trous dedans et je voudrais la compléter, en ajoutant l'heure manquante, et la hauteur d'eau manquante (moyenne de t-15 et t+15 si t est la valeur manquante).

🧑‍🏫 Réponse de martiste

il faut que tu commences par te créer un index de temps à l'intervalle voulu, depuis ta première valeur jusqu'à la dernière, à laquelle tu joins ton jeu de données réel. Les trous vont alors apparaître en 'NA'. Et si tu n'as que quelques trous de jamais plus de 2 intervalles, tu peux utiliser la fonction zoo::na_approx() qui fera l'affaire...

library(dplyr)
H_15_raw = readr::read_delim("H_15MIN_SB_CSV.csv", delim = ";") %>% 
  mutate(Date = lubridate::dmy_hm(Date))

timestamp = seq(from = min(H_15_raw$Date), to = max(H_15_raw$Date), by = "15 min") %>% 
  as_tibble() %>% 
  select(Date = value)

H_15_corr =
  left_join(timestamp, H_15_raw, by ="Date") %>% 
  mutate(H_CM_SB_BH = zoo::na.approx(H_CM_SB_BH))

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 ?

🧑‍🏫 Réponse de lvaudor

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))

Différence entre avec et sans '~' devant la fonction:

  • 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"

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

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".

🙋 Question complémentaire

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 ?

🧑‍🏫 Réponse 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)

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 ?

... %>% 
  group_by(sequence) %>%
  summarise(duration=max(time)-min(time)) %>%
  ungroup() %>%
  mutate(n_sequences=n()) %>%
  top_n(1,duration)

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.

Annonces de nouveau packages R

banqueHydro

[[2]]

Pour "scraper" les données du site banqueHydro (en attendant l'API Hubeau [[3]]).

Annonces de formations/tutos/conf

* [SIGR] recommandé par defuneste
* [command line utilities in R] recommandé par defuneste
* [geocomputation with R] recommandé par defuneste

Continuer l'édition

sur Discord, channel questions-r:

!saveconv 882172361246396427 883000807585374258