Initiation à R - Prise en main du logiciel

Avant-propos

L’objectif de ce support est de présenter R dans les grandes lignes. Cette intiation vous permettra ensuite de réaliser des analyses statistiques simples (statistiques descriptives et régressions). Plus précisément, vous allez apprendre ici :

  • à prendre en main le logiciel R et à manipuler des objets;
  • à importer et nettoyer des données externes;

Ce document (rédigé en R !) vous servira donc de support.

R est un logiciel et un langage de programmation dédié aux traitements statistiques, inventé en 1993 et aujourd’hui géré par la R Development Core Team. Il est libre (licence GNU).

La première chose à faire, si ce n’est déjà fait, est d’installer R puis RStudio (un sous-environnement de R particulièrement pratique). Vous pouvez pour cela suivre la procédure décrite sur cette page : https://larmarange.github.io/analyse-R/installation-de-R-et-RStudio.html

Ensuite, il vous faut créer un projet et définir un working directory.


1 Prise en main du logiciel

1.1 Généralités

R peut tout d’abord servir de calculatrice. Par exemple, on peut exécuter des opérations simples comme :

1+1
[1] 2

ou encore :

(2*4+1)/3
[1] 3
3^2
[1] 9

Il existe des fonctions (cf. section suivante pour une définition précise) simples pour calculer des opérations simples, comme la racine carrée :

sqrt(9)
[1] 3

ou l’exponentielle, le log, etc. :

exp(3)
[1] 20.08554
log(10)
[1] 2.302585
log(10, base = 2) # on peut spécifier la base du logarithme
[1] 3.321928

La fonction round() permet de définir le nombre de décimales en sortie d’une opération, ce qui est pratique :

round(exp(3), digits = 2) # le 2 correspond au nombre de décimales voulu
[1] 20.09

On peut également créer des séries de valeurs en utilisant ::

1:10 # toutes les valeurs entre 1 et 10
 [1]  1  2  3  4  5  6  7  8  9 10

1.2 Packages et fonctions

R fonctionne avec des packages, qui regroupent eux-mêmes des fonctions. Il y a un certain nombre de packages installés par défaut (par exemple le package base), mais la plupart doit être ajoutée par l’utilisateur selon ses besoins. De nouveaux packages apparaissent ou sont updatés en permanence par la communauté.

Pour installer un package, utilisez la fonction install.packages():

install.packages("questionr", dependencies = TRUE)
# On ajoute `dependencies = TRUE` pour que les packages dépendants soient aussi installés

Il faut ensuite activer le package avec la fonction library():

library(questionr)

Pour visualiser la liste des fonctions inclues dans un package, utilisez le code suivant :

ls("package:questionr")
 [1] "addNAstr"          "chisq.residuals"   "clipcopy"         
 [4] "copie"             "cprop"             "cramer.v"         
 [7] "cross.multi.table" "describe"          "duplicated2"      
[10] "freq"              "freq.na"           "freqtable"        
[13] "ggsurvey"          "icut"              "iorder"           
[16] "irec"              "look_for"          "lookfor"          
[19] "lprop"             "ltabs"             "multi.split"      
[22] "multi.table"       "na.rm"             "odds.ratio"       
[25] "prop"              "prop_table"        "qload"            
[28] "qscan"             "quant.cut"         "recode.na"        
[31] "rename.variable"   "renomme.variable"  "residus"          
[34] "rm.unused.levels"  "rprop"             "tabs"             
[37] "wtd.mean"          "wtd.table"         "wtd.var"          

ou :

library(help = "questionr")

Pour obtenir de l’aide sur une fonction, placez le curseur sur le nom de la nom de la fonction et appuyez sur la touche F1.
Pour obtenir le code de la fonction, sélectionnez entièrement le nom de la fonction et exécutez.
Les fonctions contiennent une série d’arguments, qu’il convient de renseigner. Vous trouverez la liste de ces arguments dans l’aide de la fonction, au ainsi :

args("prop_table")
function (tab, digits = 1, total = TRUE, percent = FALSE, drop = TRUE, 
    n = FALSE, ...) 
NULL

1.3 Les objets dans R

R est un langage orienté objet. On créé systématiquement des objets. Il en existe plusieurs, en fonction de leur nature. Voici les principaux :

  • les vecteurs
  • les data frames
  • les matrices
  • les listes

1.3.1 Les vecteurs

Un vecteur est une série de valeurs ou de caractères, qui doivent être de même nature. Pour créer un vecteur, on utiliser la fonction c():

vec1 <- c(1,3,2,8,14,22)
vec1
[1]  1  3  2  8 14 22

ou la fonction seq() pour créer une série de valeurs également distribuées :

vec2 <- seq(1,2,0.2)
vec2
[1] 1.0 1.2 1.4 1.6 1.8 2.0

Ces deux vecteurs sont numériques :

class(vec2)
[1] "numeric"

Mais on peut aussi créer des vecteurs de caractères. Par exemple :

vec3 <- c("Hélène","Claire","Alice","Anissa","Cédric","Céline")
# les guillemets sont indispensables pour les caractères
vec3
[1] "Hélène" "Claire" "Alice"  "Anissa" "Cédric" "Céline"
class(vec3)
[1] "character"

Les facteurs sont un type particulier de vecteurs. Ce sont des objets très utiles dans R pour stocker les variables qualitatives. Ils sont notamment caractérisés par le fait qu’ils contienent des levels (nous verrons cela plus tard). Pour convertir un vecteur de caractères en facteur, il faut utiliser la fonction factor() :

vec3 <- factor(vec3)
class(vec3)
[1] "factor"

1.3.2 Les data frames

Les data frames sont des tableaux de données. Les colonnes peuvent être constituées de différents objets (numérique, facteurs, etc.), mais doivent toutes avoir la même longueur. Less data frames sont donc des listes de vecteurs. C’est l’objet que vous utiliserez la plupart du temps.

Créons par exemple un data frame regroupant les trois vecteurs précédents :

df <- data.frame(vec1,vec2,vec3)
df
  vec1 vec2   vec3
1    1  1.0 Hélène
2    3  1.2 Claire
3    2  1.4  Alice
4    8  1.6 Anissa
5   14  1.8 Cédric
6   22  2.0 Céline

Les vecteurs deviennent ainsi des variables. On peut d’ailleurs changer leur nom ainsi :

names(df) <- c("var1","var2","var3")
df
  var1 var2   var3
1    1  1.0 Hélène
2    3  1.2 Claire
3    2  1.4  Alice
4    8  1.6 Anissa
5   14  1.8 Cédric
6   22  2.0 Céline

Pour appeler une variable d’un data frame, il faut utiliser le signe $ :

df$var2
[1] 1.0 1.2 1.4 1.6 1.8 2.0

La logique est la même pour appliquer des fonctions sur ces variables :

class(df$var2) # nature de la variable var2
[1] "numeric"
mean(df$var2) # moyenne de la variable var2, etc.
[1] 1.5

Certaines fonctions sont utiles pour caractériser la taille des tables (nombre de lignes/colonnes) :

dim(df) # nombre de lignes et de colonnes, respectivement
[1] 6 3
ncol(df) # nombre de colonne
[1] 3
nrow(df) # nombre de lignes
[1] 6

On peut également créer de nouvelles variables dans le data frame, issues de calculs entre variables existantes :

df$var4 <- df$var1 + df$var2
df$var4 # var4 est la somme des deux premières variables
[1]  2.0  4.2  3.4  9.6 15.8 24.0

Quand on explore un grand tableau, il est souvent utile de se servir de la fonction head(), qui permet de visualiser les n premières lignes de la table :

head(df, n=3) # fait apparaitre les 3 premières lignes de df
  var1 var2   var3 var4
1    1  1.0 Hélène  2.0
2    3  1.2 Claire  4.2
3    2  1.4  Alice  3.4

Il y a une synthaxe précise pour manipuler les tables, basée sur les crochets []. Par exemple, on peut extraire des éléments, des lignes ou des colonnes de cette manière :

df[1,] # extraction de la première ligne
  var1 var2   var3 var4
1    1    1 Hélène    2
df[,1] # extraction de la première colonne
[1]  1  3  2  8 14 22
df[1,1] # extraction du premier élément de la table
[1] 1
df[,1:3] # extraction des 3 premières colonnes
  var1 var2   var3
1    1  1.0 Hélène
2    3  1.2 Claire
3    2  1.4  Alice
4    8  1.6 Anissa
5   14  1.8 Cédric
6   22  2.0 Céline
df[c(1,4),4] # extraction des lignes 1 et 4 et de la 5e colonne
[1] 2.0 9.6

La fonction subset() est équivalente :

subset(df, select = var1:var3) # extraction des 3 premières colonnes
  var1 var2   var3
1    1  1.0 Hélène
2    3  1.2 Claire
3    2  1.4  Alice
4    8  1.6 Anissa
5   14  1.8 Cédric
6   22  2.0 Céline
subset(df, var1>5) # extraction des lignes où var1 > 5
  var1 var2   var3 var4
4    8  1.6 Anissa  9.6
5   14  1.8 Cédric 15.8
6   22  2.0 Céline 24.0
subset(df, select = -var2) # extraction de toutes les colonnes sauf la 2ème
  var1   var3 var4
1    1 Hélène  2.0
2    3 Claire  4.2
3    2  Alice  3.4
4    8 Anissa  9.6
5   14 Cédric 15.8
6   22 Céline 24.0

1.3.3 Les matrices

Les matrices sont des data frames un peu particulières : ce sont des tableaux dont les colonnes doivent être de même nature. Elles présentent un intérêt sur certains types de traitements, que nous verrons plus tard.

1.3.4 Les listes

Les listes sont des “méta-objets” qui regroupent des objets de nature hétérogène (un peu comme un fichier xls à plusieurs onglets). Par exemple, on peut créer une liste qui va regrouper un vecteur et un data frame :

list <- list(vec=vec1,df=df)

On appelle ensuite un objet de la liste avec le signe $, comme pour les data frames :

list$vec
[1]  1  3  2  8 14 22
list$df
  var1 var2   var3 var4
1    1  1.0 Hélène  2.0
2    3  1.2 Claire  4.2
3    2  1.4  Alice  3.4
4    8  1.6 Anissa  9.6
5   14  1.8 Cédric 15.8
6   22  2.0 Céline 24.0

Dans R, les objets résultant de tests statistiques ou de modèles de régression sont des listes, qui intègrent les statistiques du test, les p-values, les coefficients de régression, etc., en autant d’objets distincts. On y aura donc affaire régulièrement dans la formation.

 

2 Import de données externes et data management

Vous allez bien entendu avoir à importer vos données externes (par exemple des fichiers excel ou csv) dans R, puis à les nettoyer correctement (vérifier leur qualité, les NAs, la nature des variables, créer de nouvelles variables, etc.) pour pouvoir finalement procéder à vos analyses statistiques.

2.1 Import de données externes

Il existe plusieurs packages dédiés à l’import de fichiers de données externes. Pour importer des fichiers xls ou xlsx, le package readxl et sa fonction readxl() feront parfaitement l’affaire. Si votre fichier excel est bien placé dans votre répertoire de travail (correspondant à votre projet), alors seul le nom du fichier est précisé dans le code, sans le chemin en entier. Nous allons ainsi importer le fichier “” :

library(readxl)
# Téléchargez la table ici : https://gitlab.huma-num.fr/tfeuillet/cours/-/blob/main/data/table_climato.xlsx?ref_type=heads
df <- read_excel("data/table_climato.xlsx")

Pour ouvrir un fichier csv, on utilise de la même façon la fonction read.csv2().

Le premier réflexe après avoir importé une table est de vérifier le type d’objet importé et les premières lignes pour détecter d’éventuels problèmes (inversion de lignes ou de colonnes par exemple) :

class(df)
[1] "tbl_df"     "tbl"        "data.frame"
head(df, n = 10)
# A tibble: 10 × 9
   nom         precip   alt  temp  ampl jrs_neige dist_litt       X        Y
   <chr>        <dbl> <dbl> <dbl> <dbl>     <dbl>     <dbl>   <dbl>    <dbl>
 1 Amiens         634    27  10.4  14.5      NA          54 649667. 6978427.
 2 Auxerre        647    93  11.2  16.4      13.5       298 743083. 6743892.
 3 Besançon       992   235  10.5  17.6      27.2       458 927914. 6684860.
 4 Bordeaux       931    15  12.7  14.5       3.9        40 417717. 6421887.
 5 Bourges        718   120  11.2  16        13.8       283 654258. 6664936.
 6 Caen           676     2  10.8  12.7      12.2        15 454093. 6902413.
 7 Cherbourg      896    15  11.3  10.8       5.1         1 366208. 6958525.
 8 Dijon          768   220  10.5  17.9      23.2       402 855116. 6694086.
 9 Gap            860   625   9.6  18.2      19.1       562 944476. 6390051.
10 La Rochelle    762    15  12.6  13.9       2.7         1 379827. 6569805.

2.2 Exploration de la table et nettoyage

On commence par afficher la liste des variables, avant de les étudier plus en détail :

names(df)
[1] "nom"       "precip"    "alt"       "temp"      "ampl"      "jrs_neige"
[7] "dist_litt" "X"         "Y"        

2.2.1 Nature des variables

Dans la sortie de la commande précédente (head()), on a une vue générale de la nature de chaque variable. On peut le voir aussi avec l’aide la fonction str, qui affiche la structure d’un objet R :

str(df)
tibble [33 × 9] (S3: tbl_df/tbl/data.frame)
 $ nom      : chr [1:33] "Amiens" "Auxerre" "Besançon" "Bordeaux" ...
 $ precip   : num [1:33] 634 647 992 931 718 676 896 768 860 762 ...
 $ alt      : num [1:33] 27 93 235 15 120 2 15 220 625 15 ...
 $ temp     : num [1:33] 10.4 11.2 10.5 12.7 11.2 10.8 11.3 10.5 9.6 12.6 ...
 $ ampl     : num [1:33] 14.5 16.4 17.6 14.5 16 12.7 10.8 17.9 18.2 13.9 ...
 $ jrs_neige: num [1:33] NA 13.5 27.2 3.9 13.8 12.2 5.1 23.2 19.1 2.7 ...
 $ dist_litt: num [1:33] 54 298 458 40 283 15 1 402 562 1 ...
 $ X        : num [1:33] 649667 743083 927914 417717 654258 ...
 $ Y        : num [1:33] 6978427 6743892 6684860 6421887 6664936 ...

2.2.2 Gestion des données manquantes

Les données manquantes sont très fréquentes. Il faut d’une part connaitre leur nombre, et d’autre part établir de règles sur la façon de les traiter. Pour les compter, la fonction table() associée à is.na est utile :

table(is.na(df))

FALSE  TRUE 
  296     1 

Il y a donc une données manquante. Parfois, on peut vouloir changer les NAs en 0 (c’est juste un exemple ici, qu’on n’appliquera pas en réalité) :

df$jrs_neige[is.na(df$jrs_neige)] <- 0

On peut aussi décider de ne garder que les inidividus qui ne contiennent pas de NAs :

df2 <- df[complete.cases(df),]
nrow(df)
[1] 33
nrow(df2)
[1] 32

2.2.3 Renommer des variables

On veut par exemple changer “temp” par “température” (la 4ème colonne). Une solution possible est :

names(df)[4] <- "température"

2.2.4 Discrétiser une variable quantitative

Le package gtools a une fonction très pratique pour discrétiser une variable :

library(gtools)
df$amplDisc <- quantcut(df$ampl, 3) # Discrétise la variable en terciles
table(df$amplDisc) # vérification du résultat

[10.8,15.2] (15.2,16.4] (16.4,18.4] 
         12          12           9 

2.2.5 Renommer des modalités de facteurs

levels(df$amplDisc) <- c("faible","moyenne","forte") # on renomme de façon intelligible
table(df$amplDisc) # vérification du résultat

 faible moyenne   forte 
     12      12       9 

 

2.3 Création de nouvelles variables

2.3.1 Opérations entre variables

La concaténation de caractères se fait via la fonction paste(), tandis que l’extraction de caractères se fait via substr() :

df$sub <- substr(df$nom,1,3) # extraction des 3 premiers caractères de la variable 'nom'
head(df$sub)
[1] "Ami" "Aux" "Bes" "Bor" "Bou" "Cae"

Les opérations entre variables ont été vues précédemment.

2.3.2 Créer des tables de contingence et des aggrégations

Commençons par créer une seconde variable qualitative :

df$neigeDisc <- quantcut(df$jrs_neige, 4) # Discrétise la variable en quartiles
levels(df$neigeDisc) <- c("faible","moyenne","forte","très forte") # on renomme de façon intelligible

La table de contingence croisant jours de neige et amplitude (en version qualitative) se programme ainsi :

table(df$amplDisc, df$neigeDisc) # Tableau de contigence
         
          faible moyenne forte très forte
  faible       5       4     2          0
  moyenne      2       4     5          1
  forte        1       0     1          7

Si on le veut en proportions :

proportions(table(df$amplDisc, df$neigeDisc)) # Tableau de contigence en proportions
         
           faible moyenne   forte très forte
  faible  0.15625 0.12500 0.06250    0.00000
  moyenne 0.06250 0.12500 0.15625    0.03125
  forte   0.03125 0.00000 0.03125    0.21875

Et si on veut contrôler le nombre de décimales, on utilise la fonction round() :

round(proportions(table(df$amplDisc, df$neigeDisc)),2) 
         
          faible moyenne forte très forte
  faible    0.16    0.12  0.06       0.00
  moyenne   0.06    0.12  0.16       0.03
  forte     0.03    0.00  0.03       0.22

 

2.4 La manipulation de tables avec dplyr

dplyr fait partie du tidyverse, un univers d’extensions présentant un syntaxe nouvelle et commune facilitant les scripts de tout genre (voir https://juba.github.io/tidyverse/06-tidyverse.html).

Cette syntaxe est structurée autour du pipe %>%, qui rend les scripts beaucoup plus instinctifs. En particulier, cette syntaxe est utilisée pour rendre plus lisibles les emboitements de fonctions.

Ainsi, on va passer de

round(proportions(table(df$amplDisc, df$neigeDisc)),2) 

à

library(dplyr)
table(df$amplDisc, df$neigeDisc) %>% proportions() %>% round(2)
         
          faible moyenne forte très forte
  faible    0.16    0.12  0.06       0.00
  moyenne   0.06    0.12  0.16       0.03
  forte     0.03    0.00  0.03       0.22

2.4.1 Les verbes de dplyr

dplyr est basé sur des verbes. Voici les principaux que vous aurez à utiliser pour manipuler des tables :

  • filter et slice : pour filter des lignes
  • select : pour sélectionner des colonnes
  • mutate : pour créer de nouvelles colonnes
  • rename : pour renommer des colonnes

Il existe aussi plein de fonctions de requêtes ou de jointures, comme :

  • case_when() : requête conditionnelle
  • left_joint(), right_joint(), bind_rows(), etc. : jointures

Voir la cheat sheet suivante pour un aperçu plus complet : https://raw.githubusercontent.com/rstudio/cheatsheets/main/data-transformation.pdf

2.4.2 Exemples d’utilisation de dplyr

Par exemple, on veut sélectionner les villes où la température moyenne est > 12°C :

df %>% filter(temp > 12)
# A tibble: 8 × 12
  nom        precip   alt  temp  ampl jrs_neige dist_litt      X      Y amplDisc
  <chr>       <dbl> <dbl> <dbl> <dbl>     <dbl>     <dbl>  <dbl>  <dbl> <fct>   
1 Bordeaux      931    15  12.7  14.5       3.9        40 4.18e5 6.42e6 faible  
2 La Rochel…    762    15  12.6  13.9       2.7         1 3.80e5 6.57e6 faible  
3 Marseille     588    50  14.2  16.8       1.3       532 8.91e5 6.25e6 forte   
4 Montpelli…    745    42  13.9  16.4       1.1       406 7.70e5 6.28e6 moyenne 
5 Pau           886   165  12.3  14.3       5.1        95 4.26e5 6.25e6 faible  
6 Périgueux     884    75  12.3  15.2       6         142 5.23e5 6.46e6 faible  
7 Perpignan     586    37  15.4  16         2.2       369 6.91e5 6.18e6 moyenne 
8 Toulouse      698   144  12.7  16.2       6.3       228 5.75e5 6.28e6 moyenne 
# ℹ 2 more variables: sub <chr>, neigeDisc <fct>

Pour sélectionner les villes > 12°C avec une amplitude < 15°C, puis extraire uniquement la colonne “precip” de cette sélection :

df %>% filter(temp > 12 & ampl < 15) %>% select(precip)
# A tibble: 3 × 1
  precip
   <dbl>
1    931
2    762
3    886

Pour renommer une variable, puis créer une nouvelle variable dérivée d’une autre (ici les pp° en cm au lieu des mm) :

df %>% rename(tempMoy = temp) %>% mutate(precipCm = precip/10)
# A tibble: 33 × 13
   nom     precip   alt tempMoy  ampl jrs_neige dist_litt      X      Y amplDisc
   <chr>    <dbl> <dbl>   <dbl> <dbl>     <dbl>     <dbl>  <dbl>  <dbl> <fct>   
 1 Amiens     634    27    10.4  14.5      NA          54 6.50e5 6.98e6 faible  
 2 Auxerre    647    93    11.2  16.4      13.5       298 7.43e5 6.74e6 moyenne 
 3 Besanç…    992   235    10.5  17.6      27.2       458 9.28e5 6.68e6 forte   
 4 Bordea…    931    15    12.7  14.5       3.9        40 4.18e5 6.42e6 faible  
 5 Bourges    718   120    11.2  16        13.8       283 6.54e5 6.66e6 moyenne 
 6 Caen       676     2    10.8  12.7      12.2        15 4.54e5 6.90e6 faible  
 7 Cherbo…    896    15    11.3  10.8       5.1         1 3.66e5 6.96e6 faible  
 8 Dijon      768   220    10.5  17.9      23.2       402 8.55e5 6.69e6 forte   
 9 Gap        860   625     9.6  18.2      19.1       562 9.44e5 6.39e6 forte   
10 La Roc…    762    15    12.6  13.9       2.7         1 3.80e5 6.57e6 faible  
# ℹ 23 more rows
# ℹ 3 more variables: sub <chr>, neigeDisc <fct>, precipCm <dbl>

Pour calculer des statistiques selon les modalités d’un facteur, il faut associer les fonctions group_by() et summarise(). Par exemple, si on souhaite calculer la température moyenne des villes dans chaque classe de la variable neigeDisc :

df %>% group_by(neigeDisc) %>% 
  summarise(meanTemp = mean(temp))
# A tibble: 5 × 2
  neigeDisc  meanTemp
  <fct>         <dbl>
1 faible         13  
2 moyenne        11.5
3 forte          10.8
4 très forte     10.2
5 <NA>           10.4

2.4.3 Exercices

  1. Créer une nouvelle table qui s’appelera ‘subDf’ comprenant les villes situées à moins de 200 km du littoral dans lesquelles il neige au moins 5 jours par an.
  2. Identifiez les villes humides (pp > 700 mm) situées à plus de 300 m d’altitude, et renommer ‘alt’ en ‘altitude’, le tout en une ligne de code.
  3. Quelle est la moyenne des températures des villes situées à plus de 400 km du littoral ? vous devez répondre en une seule ligne de code, mais avec deux pipes et la fonction summarise().
# A tibble: 1 × 1
  meanTemp
     <dbl>
1     11.3
  1. Quelle est la distance moyenne au littoral des groupes de villes compris dans les modalités de la variable neigeDisc ?
# A tibble: 5 × 2
  neigeDisc  meanDist
  <fct>         <dbl>
1 faible         185.
2 moyenne        140.
3 forte          244.
4 très forte     428.
5 <NA>            54