3 Importer des fichiers externes de données
“Friends don’t let friends use Excel for statistics!” — J. D. Cryer
3.1 Vue d’ensemble
R propose de base tous les outils pour gérer (importer et exporter) des fichiers
textes, comme les fichiers .txt
ou .csv
. Une série de packages permet de
gérer de nombreux autres formats :
- La gestion des fichiers EpiInfo, Minitab, S-PLUS, SAS, SPSS, Stata, Systat,
Octave, etc. via le package
foreign
; - La liaison en lecture/écriture avec des bases de données (relationnelles ou non), que ce soit MySQL, MariaDB, PostgreSQL, Oracle, SQLite, MongoDB, etc. ainsi que MS Access (voir la CRAN Task View dédiée aux bases de données) ;
- Et bien sûr la gestion complète des fichiers Excel, par exemple via les
packages
xlsx
etWriteXLS
.
Dans ce court module, nous allons utiliser deux packages en particulier,
readr
et readxl
qui proposent une approche simple et cohérente pour
importer/exporter des fichiers textes et (seulement) importer des fichiers
Excel.
3.2 Fichiers texte (.txt
et .csv
)
L’importation de fichiers de données est généralement simple et directe, et R automatise la conversion des données dans les formats natifs de R au maximum. En revanche, plus le jeu de données est complexe, et plus le risque d’erreurs dans les choix automatiques est grand.
À noter : R n’est en principe pas vraiment limité par la taille des jeux de données. Par exemple, le nombre de lignes maximum par défaut pour un tableau est de (2^{31} - 1) (on peut regarder sous R combien de lignes cela fait). Tout est en revanche stocké dans la mémoire vive, on peut donc atteindre les limites de traitement plus rapidement, surtout sur des machines peu équipées en RAM.
3.2.1 Le package readr
On commence par charger le package :
library("readr")
Le package readr
propose 7 fonctions d’importation de fichiers textes, de la
forme read_*()
selon leur format. Les plus importantes sont :
read_csv()
etread_csv2()
: fichiers de valeurs séparées par des virgules ou point-virgules (CSV, comma-separated values) ;read_tsv()
: fichiers de valeurs séparées par des tabulations (TSV, tab-separated values) ;read_fwf()
: fichiers de colonnes à largeurs fixées (fixed width files).
Concernant les fichiers CSV, la fonction read_csv()
utilise le point (.
)
comme séparateur décimal, et la virgule (,
) comme délimiteur de champ. Elle
s’adresse de fait plutôt au monde anglo-saxon. En France, où la virgule est
réservée comme séparateur décimal, on utilise plus souvent le point-virgule
(;
) pour délimiter les champs. La variante read_csv2()
s’occupe précisément
de ça (,
comme séparateur décimal, ;
comme délimiteur de champ).
Les mêmes fonctions existent en écriture pour exporter des fichiers textes à
partir de R, sous la forme write_*()
. Ce module ne couvre pas leur
utilisation, qui est cependant relativement simple (consulter les fiches d’aide
devrait être suffisant en cas de besoin).
3.2.2 Spécifications du format et des colonnes
Le plus simple quand on veut importer un fichier texte est de regarder ce qu’il
y a dans les premières lignes du fichier. On peut avoir un aperçu grâce à la
fonction readLines()
, en spécifiant bien que l’on ne veut que les 5 premières
lignes (sans quoi il affichera l’intégralité du fichier) :
readLines("data/ins_culture_18_ano.csv", n = 5)
[1] "NUMINS;IDETU;COMPOS;REGIME;SITUPRE;PARIPA;DIPLOM;TYPREPA;DIPDER;NIVEAU;ETABLI;ACAETA;DEPETA;TYP_DIPL;SECTDIS;DISCIPLI;CYCLE;DEGETU;CURPAR;NBACH;NET;EFFECTIF;GROUPE;CURSUS_LMD;VOIE;NUMED"
[2] "180001;1;0040562P;10;T;100;8000246;;A;01;0040562P;02;004;NA;21;04;0;0;;0;0;1;3;L;;"
[3] "180002;2;0040562P;10;A;100;8000246;;A;01;0040562P;02;004;NA;21;04;0;0;;0;0;1;3;L;;"
[4] "180003;3;0040562P;10;A;100;8000246;;A;01;0040562P;02;004;NA;21;04;0;0;;0;0;1;3;L;;"
[5] "180004;4;0040562P;10;A;100;8000246;;A;01;0040562P;02;004;NA;21;04;0;0;;0;0;1;3;L;;"
Cela nous permet de nous assurer qu’il s’agit d’un fichier CSV à la française
(avec le point-virgule utilisé comme délimiteur de champ), que l’on pourra donc
importer avec la fonction read_csv2()
. Au-delà du format de fichier, readr
fait ce qu’il peut pour détecter automatiquement le format de chacune des
colonnes du tableau de données, en analysant les 1000 premières lignes (par
défaut). Pour de gros jeux de données, il est toutefois préférable de voir ce
que cela donnerait avant d’importer le fichier :
spec_csv2("data/ins_culture_18_ano.csv")
ℹ Using '\',\'' as decimal and '\'.\'' as grouping mark. Use `read_delim()` for more control.
── Column specification ────────────────────────────────────────────────────────
cols(
.default = col_character(),
IDETU = col_double(),
REGIME = col_double(),
PARIPA = col_double(),
TYPREPA = col_double(),
SECTDIS = col_double(),
CYCLE = col_double(),
DEGETU = col_double(),
CURPAR = col_logical(),
NBACH = col_double(),
NET = col_double(),
EFFECTIF = col_double(),
GROUPE = col_double(),
VOIE = col_logical(),
NUMED = col_logical()
)
ℹ Use `spec()` for the full column specifications.
cols(
NUMINS = col_character(),
IDETU = col_double(),
COMPOS = col_character(),
REGIME = col_double(),
SITUPRE = col_character(),
PARIPA = col_double(),
DIPLOM = col_character(),
TYPREPA = col_double(),
DIPDER = col_character(),
NIVEAU = col_character(),
ETABLI = col_character(),
ACAETA = col_character(),
DEPETA = col_character(),
TYP_DIPL = col_character(),
SECTDIS = col_double(),
DISCIPLI = col_character(),
CYCLE = col_double(),
DEGETU = col_double(),
CURPAR = col_logical(),
NBACH = col_double(),
NET = col_double(),
EFFECTIF = col_double(),
GROUPE = col_double(),
CURSUS_LMD = col_character(),
VOIE = col_logical(),
NUMED = col_logical()
)
L’on peut y voir que les colonnes ont été interprétées soit comme suite de
nombres (“double”), suite de caractères (“character”) ou bien suite d’opérateurs
logiques TRUE
/FALSE
(“logical”). En épluchant la documentation du jeu de
données SISE, on peut se rendre compte que ce n’est pas forcément juste… et
qu’il faut donc corriger manuellement la spécification des colonnes à
l’importation. On utilisera les spécifications suivantes pour toutes les
colonnes présentes dans les différents fichiers SISE, avec mes annotations
explicatives en commentaires (attention, certaines variables apparaissent
parfois en minuscules) :
cols(
ACAETA = col_character(), # Variable caractère de longueur 2 : 01:41
BAC = col_character(), # Variable caractère de longueur 4.
BAC_RGRP = col_double(), # Variable caractère de longueur 1 : 1:7
COMPOS = col_character(), # Variable caractère de longueur 8.
COMPOSR = col_character(), # Variable caractère de longueur 8.
CONV = col_character(), # Variable caractère de longueur 1 : C/P
CURPAR = col_character(), # Variable caractère de longueur 2 : 00:18
CURSUS_LMD = col_character(), # Variable caractère de longueur 1 : L/M/D
CURSUS_LMDR = col_character(), # Variable caractère de longueur 1 : L/M/D
CYCLE = col_double(), # Variable caractère de longueur 1 : 0:3
CYCLEr = col_double(), # Variable caractère de longueur 1 : 0:3
DEGETU = col_double(), # Variable caractère de longueur 3 (dont 1 utile) : 0:6
DEPETA = col_character(), # Variable caractère de longueur 3.
DIPDER = col_character(), # Variable caractère de longueur 1 : A:Z/1:3
DIPLOM = col_character(), # Variable caractère de longueur 7.
DIPLOMR = col_character(), # Variable caractère de longueur 7.
DISCIPLI = col_character(), # Variable caractère de longueur 2 : 01:40
DISCIPLIr = col_character(), # Variable caractère de longueur 2 : 01:40
EFFECTIF = col_double(), # Variable caractère de longueur 3 (dont 1 utile) : 0/1
ETABLI = col_character(), # Variable caractère de longueur 8.
ETABLI_DIFFUSION = col_character(), # Variable caractère de longueur 36.
FLAG_MEEF = col_double(), # Variable numérique de longueur 1 : 0/1
GROUPE = col_character(), # Variable caractère de longueur 1 : 1:8/A
GROUPEr = col_character(), # Variable caractère de longueur 1 : 1:8/A
IDETU = col_character(), # Variable caractère de longueur 11.
NBACH = col_double(), # Variable numérique de longueur 1 : 0/1
NET = col_double(), # Variable numérique de longueur 1 : 0/1
NIVEAU = col_character(), # Variable caractère de longueur 2 : 01:13
nonappar = col_character(), # Variable caractère de longueur 1 : A:E
NUMED = col_character(), # Variable caractère de longueur 4.
NUMINS = col_character(), # Variable caractère de longueur 8.
NUMINSR = col_character(), # Variable caractère de longueur 8.
PARIPA = col_character(), # Variable caractère de longueur 3 : 100 pour la France ; code alphanumérique pour les autres
REGIME = col_double(), # Variable caractère de longueur 2 : 10:22
SECTDIS = col_character(), # Variable caractère de longueur 2 : 01:71 + quelques alphanumériques
SECTDISr = col_character(), # Variable caractère de longueur 2 : 01:71 + quelques alphanumériques
SITUPRE = col_character(), # Variable caractère de longueur 1 : A:U
SPECIA = col_character(), # Variable caractère de longueur 4 (dont 3 utiles) : code numérique
SPECIB = col_character(), # Variable caractère de longueur 4 (dont 3 utiles) : code numérique
TYPREPA = col_character(), # Variable caractère de longueur 5 : code sur 5 chiffres.
TYP_DIPL = col_character(), # Variable caractère de longueur 2.
TYP_DIPr = col_character(), # Variable caractère de longueur 2.
UNIV = col_character(), # Variable caractère de longueur 1 : O/N
VOIE = col_double(), # Variable caractère de longueur 1 : 0:2
voier = col_double() # Variable caractère de longueur 1 : 0:2
)
Au sujet des dates : readr
détecte automatiquement les dates aux formats “2021-03-19” et “2021/03/19”, et les dates-heures au format ISO_8601 par exemple “2021-03-19T18:22:10+00:00”). Pour tout autre format, (par exemple “25/12/2020” ou “25/12/2020 15:18”), il faudra spécifier manuellement la colonne avec (dans ces deux cas) col_date(format = “%d/%m/%Y”)
ou col_datetime(format = “%d/%m/%Y %H:%M”)
. On se réferrera à l’aide de la fonction parse_datetime()
, et notamment les exemples, pour plus de détails sur le format. le package lubridate
propose des outils simples pour aller plus loin dans la gestion des dates.
3.2.3 Importation d’un fichier CSV
La dernière chose à savoir est la manière dont sont codées les données
manquantes. Sous R (entre autres), on parle de NA
, pour Not Available. Il
n’y a pas vraiment de règle pour trouver la bonne formule. La fonction
read_csv2()
prend par défaut "NA"
et ""
(cellule vide). Les fichiers SISE
en revanche s’appuient sur les cellules vides… ainsi que le point ("."
), que
j’ai pu identifier après plusieurs essais infructueux.
Ceci étant posé, on peut donc passer à l’étape de l’importation proprement dite, en précisant bien ce qui fournit les données manquantes, et les spécifications de colonnes :
<- read_csv2("data/ins_culture_18_ano.csv", na = c("", "."), col_types =
ins18_culture cols(
ACAETA = col_character(),
COMPOS = col_character(),
CURPAR = col_character(), # col_logical()
CURSUS_LMD = col_character(),
CYCLE = col_double(),
DEGETU = col_character(),
DEPETA = col_character(),
DIPDER = col_character(),
DIPLOM = col_character(),
DISCIPLI = col_character(),
EFFECTIF = col_double(),
ETABLI = col_character(),
GROUPE = col_character(), # col_double(),
IDETU = col_character(),
NBACH = col_double(),
NET = col_double(),
NIVEAU = col_character(),
NUMED = col_character(), # col_logical()
NUMINS = col_character(),
PARIPA = col_character(), # col_double(),
REGIME = col_double(),
SECTDIS = col_character(), # col_double(),
SITUPRE = col_character(),
TYPREPA = col_character(), # col_double(),
TYP_DIPL = col_character(),
VOIE = col_double() # col_logical(),
))
ℹ Using '\',\'' as decimal and '\'.\'' as grouping mark. Use `read_delim()` for more control.
On s’assure que tout s’est bien passé en regardant la structure du tableau de données :
ins18_culture
# A tibble: 81,063 x 26
NUMINS IDETU COMPOS REGIME SITUPRE PARIPA DIPLOM TYPREPA DIPDER NIVEAU ETABLI
<chr> <chr> <chr> <dbl> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
1 180001 1 00405… 10 T 100 80002… <NA> A 01 00405…
2 180002 2 00405… 10 A 100 80002… <NA> A 01 00405…
3 180003 3 00405… 10 A 100 80002… <NA> A 01 00405…
4 180004 4 00405… 10 A 100 80002… <NA> A 01 00405…
5 180005 5 00405… 10 A 100 80002… <NA> A 01 00405…
6 180006 6 00405… 10 A 100 80002… <NA> A 01 00405…
7 180007 7 00405… 10 A 100 80002… <NA> A 01 00405…
8 180008 8 00405… 10 A 100 80002… <NA> A 01 00405…
9 180009 9 00405… 10 A 100 80002… <NA> A 01 00405…
10 180010 10 00405… 10 A 100 80002… <NA> A 01 00405…
# … with 81,053 more rows, and 15 more variables: ACAETA <chr>, DEPETA <chr>,
# TYP_DIPL <chr>, SECTDIS <chr>, DISCIPLI <chr>, CYCLE <dbl>, DEGETU <chr>,
# CURPAR <chr>, NBACH <dbl>, NET <dbl>, EFFECTIF <dbl>, GROUPE <chr>,
# CURSUS_LMD <chr>, VOIE <dbl>, NUMED <chr>
Exercice 1 : Dans cet exercice, l’objectif est simplement de reproduire les étapes précédentes afin d’importer le fichier concernant les inscriptions à l’université ins_univ_18_ano.csv
, présent dans le même dossier.
3.3 Fichiers Excel (.xls
et .xlsx
)
3.3.1 Le package readxl
Le package readxl
permet tout simplement, comme son nom l’indique, d’importer
des classeurs Excel, que ce soit au format .xls
ou bien .xlsx
. On commence
donc par charger le package :
library("readxl")
À noter que ce package fournit très peu de fonctions, et permet uniquement d’importer des classeurs Excel, et pas d’exporter des données R dans un classeur Excel.
3.3.2 Importation d’un classeur Excel
De manière surprenante, l’importation de fichiers Excel est finalement beaucoup
plus simple, puisque R peut directement utiliser l’information du classeur Excel
pour définir les spécifications de colonnes. On peut en revanche vérifier la
présence d’un ou plusieurs onglets, ainsi que leurs noms, avec la fonction
excel_sheets
:
excel_sheets("data/2018 2019 Apogée anonymisée.xlsx")
[1] "Apogee"
L’importation se fait ensuite directement via la fonction générique
read_excel
, ou bien directement les fonctions read_xls
et read_xlsx
si
l’on veut spécifier précisément le format XLS
vs. XLSX
:
<- read_excel("data/2018 2019 Apogée anonymisée.xlsx") apogee_18
À nouveau, l’on s’assure que tout s’est bien passé en regardant la structure du tableau de données :
apogee_18
# A tibble: 57,699 x 41
Decede Annee_univ idetu Civilite Date_naiss Code Departement_pays
<chr> <dbl> <dbl> <chr> <dttm> <chr> <chr>
1 non 2018 1035789 Mme 2000-10-05 00:00:00 84 VAUCLUSE
2 non 2018 2211839 M 1997-06-16 00:00:00 6 ALPES MARITIMES
3 non 2018 2211840 M 2000-04-13 00:00:00 84 VAUCLUSE
4 non 2018 921768 Mme 1993-10-08 00:00:00 205 LIBAN
5 non 2018 921685 Mme 1994-10-02 00:00:00 352 ALGERIE
6 non 2018 2211841 M 1992-03-27 00:00:00 127 ITALIE
7 non 2018 921909 Mme 1995-10-06 00:00:00 205 LIBAN
8 non 2018 921827 M 1995-05-05 00:00:00 134 ESPAGNE
9 non 2018 2211842 Mme 1990-01-08 00:00:00 331 BURKINA FASO
10 non 2018 921775 M 1988-05-01 00:00:00 352 ALGERIE
# … with 57,689 more rows, and 34 more variables: Code_nationalite <dbl>,
# Libelle_nationalite <chr>, Bac <chr>, Bac_regroup <chr>, Annee_bac <dbl>,
# Departement_bac <chr>, Regime <chr>, Bourse <chr>, Echelon_bourse <chr>,
# Pcs_parent <chr>, Pcs_parent_autre <chr>, Lic_tpd <chr>, Composante <chr>,
# Domaine_disciplinaire <chr>, Mention <chr>, Code_sise_diplome <dbl>,
# Diplome <chr>, Code_diplome <chr>, Intitule1_sise <chr>, Code_etape <chr>,
# Lib_etape <chr>, Intitule2_sise <chr>, Version_de_diplome <chr>,
# Inscription_premiere <chr>, Nature_diplome <chr>, Temoin_dip <chr>,
# Cp_annuel <dbl>, Pays_annuel <chr>, Cp_fixe <dbl>, Pays_fixe <chr>,
# Date_inscription_iae <dttm>, Prem_insc_univ_fr <dbl>,
# Date_premiere_ins_ens_sup <dbl>, Prem_insc_etab <dbl>