Lorsque vous utiliserez le raccourci =C-c C-e h o=, ce document sera
compilé en html. Tout le code contenu sera ré-exécuté, les résultats
récupérés et inclus dans un document final. Si vous ne souhaitez pas
ré-exécuter tout le code à chaque fois, il vous suffit de supprimer
le # et l'espace qui sont devant le ~#+PROPERTY:~ au début de ce
document.
Comme nous vous l'avons montré dans la vidéo, on inclue du code
python de la façon suivante (et on l'exécute en faisant ~C-c C-c~):
#+begin_src python :results output :exports both
print("Hello world!")
#+end_src
#+PROPERTY: header-args :session :exports both
* Préparation des données
Les données de l'incidence de la varicelle sont disponibles du site Web du [[http://www.sentiweb.fr/][Réseau Sentinelles]]. Nous les récupérons sous forme d'un fichier en format CSV dont chaque ligne correspond à une semaine de la période d'observation. Nous téléchargeons toujours le jeu de données complet (rien d'autre n'est proposé), qui commence en 1984 et se termine avec une semaine récente. L'URL est:
| ~indicator~ | Code de l'indicateur de surveillance |
| ~inc~ | Estimation de l'incidence de consultations en nombre de cas |
| ~inc_low~ | Estimation de la borne inférieure de l'IC95% du nombre de cas de consultation |
| ~inc_up~ | Estimation de la borne supérieure de l'IC95% du nombre de cas de consultation |
| ~inc100~ | Estimation du taux d'incidence du nombre de cas de consultation (en cas pour 100,000 habitants) |
| ~inc100_low~ | Estimation de la borne inférieure de l'IC95% du taux d'incidence du nombre de cas de consultation (en cas pour 100,000 habitants) |
| ~inc100_up~ | Estimation de la borne supérieure de l'IC95% du taux d'incidence du nombre de cas de consultation (en cas pour 100,000 habitants) |
| ~geo_insee~ | Code de la zone géographique concernée (Code INSEE) http://www.insee.fr/fr/methodes/nomenclatures/cog/ |
| ~geo_name~ | Libellé de la zone géographique (ce libellé peut être modifié sans préavis) |
L'indication d'une semaine calendaire en format [[https://en.wikipedia.org/wiki/ISO_8601][ISO-8601]] est populaire en Europe, mais peu utilisée aux Etats-Unis. Ceci explique peut-être que peu de logiciels savent gérer ce format. Le langage Python le fait depuis la version 3.6. Nous utilisons donc ce langage pour la préparation de nos données, ce qui a l'avantage de ne nécessiter aucune bibliothèque supplémentaire. (Note: nous expliquerons dans le module 4 pourquoi il est avantageux pour la réproductibilité de se limiter à un minimum de bibliothèques.)
** Téléchargement
Si le fichier de données local existe, on en extrait les données, sinon, on le créé à partir des données téléchargées depuis l'URL.
Après avoir récupéré les données, nous commençons par l'extraction des données qui nous intéressent. D'abord nous découpons le contenu du fichier en lignes, dont nous jetons la première qui ne contient qu'un commentaire. Les autres lignes sont découpées en colonnes.
Besoin de passer :results de "silent" à "output" sinon rien ne marche !
Il y a malheureusement beaucoup de façon d'indiquer l'absence d'un point de données. Nous testons ici seulement pour la présence de champs vides. Il faudrait aussi rechercher des valeurs non-numériques dans les colonnes à priori numériques. Nous ne le faisons pas ici, mais une vérification ultérieure capterait des telles anomalies.
Nous construisons un nouveau jeu de données sans les lignes qui contiennent des champs vides. Nous affichons ces lignes pour en garder une trace.
#+BEGIN_SRC python :results output
valid_table = []
for row in table:
missing = any([column == '' for column in row])
if missing:
print(row)
else:
valid_table.append(row)
#+END_SRC
** Extraction des colonnes utilisées
Il y a deux colonnes qui nous intéressent: la première (~"week"~) et la troisième (~"inc"~). Nous vérifions leurs noms dans l'en-tête, que nous effaçons par la suite. Enfin, nous créons un tableau avec les deux colonnes pour le traitement suivant.
#+BEGIN_SRC python :results silent
week = [row[0] for row in valid_table]
assert week[0] == 'week'
del week[0]
inc = [row[2] for row in valid_table]
assert inc[0] == 'inc
del inc[0]
data = list(zip(week, inc))
#+END_SRC
Regardons les premières et les dernières lignes. Nous insérons ~None~ pour indiquer à org-mode la séparation entre les trois sections du tableau: en-tête, début des données, fin des données.
Il est toujours prudent de vérifier si les données semblent crédibles. Nous savons que les semaines sont données par six chiffres (quatre pour l'année et deux pour la semaine), et que les incidences sont des nombres entiers positifs.
#+BEGIN_SRC python :results output
for week, inc in data:
if len(week) != 6 or not week.isdigit():
print("Valeur suspecte dans la colonne 'week': ", (week, inc))
if not inc.isdigit():
print("Valeur suspecte dans la colonne 'inc': ", (week, inc))
#+END_SRC
Pas de problème !
** Conversions
Pour faciliter les traitements suivants, nous remplaçons les numéros de semaine ISO par les dates qui correspondent aux lundis. A cette occasion, nous trions aussi les données par la date, et nous transformons les incidences en nombres entiers.
Nous faisons encore une vérification: nos dates doivent être séparées d'exactement une semaine, sauf autour du point manquant.
#+BEGIN_SRC python :results output
dates = [date for date, _ in converted_data]
for date1, date2 in zip(dates[:-1], dates[1:]):
if date2-date1 != datetime.timedelta(weeks=1):
print(f"Il y a {date2-date1} entre {date1} et {date2}")
#+END_SRC
** Passage Python -> R
Nous passons au langage R pour inspecter nos données, parce que l'analyse et la préparation de graphiques sont plus concises en R, sans nécessiter aucune bibliothèque supplémentaire.
Nous utilisons le mécanisme d'échange de données proposé par org-mode, ce qui nécessite un peu de code Python pour transformer les données dans le bon format.
#+NAME: data-for-R
#+BEGIN_SRC python :results silent
[('date', 'inc'), None] + [(str(date), inc) for date, inc in converted_data]
#+END_SRC
En R, les données arrivent sous forme d'un data frame, mais il faut encore convertir les dates, qui arrivent comme chaînes de caractères.
#+BEGIN_SRC R :results output :var data=data-for-R
data$date <- as.Date(data$date)
summary(data)
#+END_SRC
** Inspection
Regardons enfin à quoi ressemblent nos données !
#+BEGIN_SRC R :results output graphics :file inc-plot.png
Enfin, un histogramme montre bien que les épidémies fortes, qui touchent environ 10% de la population française, sont assez rares: il y en eu trois au cours des 35 dernières années.
#+BEGIN_SRC R :results output graphics :file annual-inc-hist.png
Enfin, un histogramme montre bien que les épidémies fortes, qui touchent environ 10% de la population française, sont assez rares: il y en eu trois au cours des 35 dernières années.
#+BEGIN_SRC R :results output graphics :file annual-inc-hist.png