4  Les fondamentaux de R

4.1 Introduction

Ce chapitre pose le socle de la programmation en R : syntaxe, types, structures (vecteurs, matrices, listes, data frames), conditions, boucles, fonctions et packages. Maîtriser ces bases rend tout le reste — tidyverse, statistiques, graphiques — beaucoup plus fluide.

4.2 Objectifs pédagogiques

  • Utiliser la syntaxe et l’affectation
  • Distinguer les types atomic et les structures
  • Indexer et sélectionner des éléments
  • Écrire des conditions, boucles et fonctions
  • Charger des packages et gérer les erreurs simples

4.3 Prérequis

Avoir installé R (Section 3.7) et exécuté un premier calcul (Section 3.8).

4.4 Syntaxe générale de R

# Commentaire
x <- 10          # affectation
y <- x + 5       # expression
print(y)         # affichage explicite
#> [1] 15
y                # affichage implicite en console
#> [1] 15

R est sensible à la casse : Notes ≠ notes. Les noms d’objets commencent par une lettre et peuvent contenir chiffres, . et _.

Vocabulaire
  • Objet : toute valeur nommée en mémoire.
  • Fonction : bloc réutilisable (mean(), sum()…).
  • Argument : paramètre passé à une fonction.
  • Valeur de retour : résultat produit par une fonction.

4.5 Variables et affectation

prix <- 12.5
quantite <- 4L          # L = entier (integer)
produit <- "Cahier"
disponible <- TRUE

Préférez <- à =. Pour inspecter : class(), typeof(), str().

class(prix)
#> [1] "numeric"
class(quantite)
#> [1] "integer"
class(produit)
#> [1] "character"
class(disponible)
#> [1] "logical"

4.6 Types de données

Type Exemple Test
numeric 3.14 is.numeric()
integer 3L is.integer()
character "bonjour" is.character()
logical TRUE / FALSE is.logical()
factor catégories ordonnées ou non is.factor()
niveau <- factor(
  c("Bac", "Licence", "Master", "Licence", "Bac"),
  levels = c("Bac", "Licence", "Master", "Doctorat"),
  ordered = TRUE
)
niveau
#> [1] Bac     Licence Master  Licence Bac    
#> Levels: Bac < Licence < Master < Doctorat
table(niveau)
#> niveau
#>      Bac  Licence   Master Doctorat 
#>        2        2        1        0

Les facteurs stockent des catégories. Attention : certaines opérations numériques sur facteurs donnent des résultats surprenants — convertissez d’abord avec as.character() ou as.numeric(as.character(...)) selon le cas.

4.7 Opérateurs

# Arithmétiques
10 + 3; 10 - 3; 10 * 3; 10 / 3; 10 %/% 3; 10 %% 3; 2^5
#> [1] 13
#> [1] 7
#> [1] 30
#> [1] 3.333333
#> [1] 3
#> [1] 1
#> [1] 32
# Comparaison (résultat logique)
5 > 3
#> [1] TRUE
5 == 5
#> [1] TRUE
5 != 4
#> [1] TRUE
# Logiques
TRUE & FALSE   # ET élément par élément
#> [1] FALSE
TRUE | FALSE   # OU
#> [1] TRUE
!TRUE          # NON
#> [1] FALSE
&& vs &

& et | travaillent vecteur par vecteur. && et || ne regardent que le premier élément — utiles dans if(), dangereux ailleurs.

4.8 Vecteurs

Le vecteur est la structure fondamentale de R.

notes <- c(12, 15, 9, 18, 14)
length(notes)
#> [1] 5
notes[1]          # 1er élément (indexation à partir de 1 !)
#> [1] 12
notes[c(1, 3)]    # plusieurs positions
#> [1] 12  9
notes[notes >= 12]  # filtrage logique
#> [1] 12 15 18 14
# Opérations vectorisées
notes * 2
#> [1] 24 30 18 36 28
sqrt(notes)
#> [1] 3.464102 3.872983 3.000000 4.242641 3.741657
1:10
#>  [1]  1  2  3  4  5  6  7  8  9 10
seq(0, 1, by = 0.25)
#> [1] 0.00 0.25 0.50 0.75 1.00
rep(c("A", "B"), times = 3)
#> [1] "A" "B" "A" "B" "A" "B"

4.9 Matrices et tableaux

m <- matrix(1:6, nrow = 2, ncol = 3, byrow = TRUE)
m
#>      [,1] [,2] [,3]
#> [1,]    1    2    3
#> [2,]    4    5    6
m[1, 2]
#> [1] 2
m[1, ]
#> [1] 1 2 3
colSums(m)
#> [1] 5 7 9

Les arrays généralisent aux dimensions > 2. Pour l’analyse de données tabulaire, on préfère les data frames.

4.10 Listes

Une liste peut contenir des objets de types et longueurs différents.

eleve <- list(
  nom = "Samira",
  notes = c(14, 16, 12),
  admis = TRUE
)
eleve$nom
#> [1] "Samira"
eleve[["notes"]]
#> [1] 14 16 12
eleve[[2]][1]
#> [1] 14

4.11 Data frames et tibbles

df <- data.frame(
  produit = c("Stylo", "Cahier", "Agenda"),
  prix = c(1.5, 3.2, 8.0),
  stock = c(100, 40, 15)
)
df
#>   produit prix stock
#> 1   Stylo  1.5   100
#> 2  Cahier  3.2    40
#> 3  Agenda  8.0    15
df$prix
#> [1] 1.5 3.2 8.0
df[df$prix < 5, ]
#>   produit prix stock
#> 1   Stylo  1.5   100
#> 2  Cahier  3.2    40

Le tibble (package tibble / tidyverse) est un data frame modernisé : affichage plus lisible, comportement plus strict.

library(tibble)
tb <- as_tibble(df)
tb
#> # A tibble: 3 × 3
#>   produit  prix stock
#>   <chr>   <dbl> <dbl>
#> 1 Stylo     1.5   100
#> 2 Cahier    3.2    40
#> 3 Agenda    8      15

4.12 Indexation et sélection

data(mtcars)
mtcars[1:3, c("mpg", "cyl")]
#>                mpg cyl
#> Mazda RX4     21.0   6
#> Mazda RX4 Wag 21.0   6
#> Datsun 710    22.8   4
mtcars$cyl == 4
#>  [1] FALSE FALSE  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE FALSE FALSE
#> [13] FALSE FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE
#> [25] FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE  TRUE
mtcars[mtcars$cyl == 4 & mtcars$mpg > 25, c("mpg", "cyl", "wt")]
#>                 mpg cyl    wt
#> Fiat 128       32.4   4 2.200
#> Honda Civic    30.4   4 1.615
#> Toyota Corolla 33.9   4 1.835
#> Fiat X1-9      27.3   4 1.935
#> Porsche 914-2  26.0   4 2.140
#> Lotus Europa   30.4   4 1.513

4.13 Conditions : if, else, ifelse()

note <- 14
if (note >= 10) {
  message("Admis")
} else {
  message("Ajourné")
}

# Version vectorisée
notes <- c(8, 12, 15, 9)
ifelse(notes >= 10, "Admis", "Ajourné")
#> [1] "Ajourné" "Admis"   "Admis"   "Ajourné"

4.14 Boucles for et while

total <- 0
for (n in notes) {
  total <- total + n
}
total
#> [1] 44
# Équivalent vectorisé (préférable)
sum(notes)
#> [1] 44
Préférez la vectorisation

En R, sum(x), mean(x), lapply() ou dplyr remplacent souvent les boucles, de façon plus claire et souvent plus rapide.

i <- 1
acc <- 0
while (i <= 5) {
  acc <- acc + i
  i <- i + 1
}
acc
#> [1] 15

4.15 Fonctions personnalisées

moyenne_ponderee <- function(valeurs, poids) {
  if (length(valeurs) != length(poids)) {
    stop("valeurs et poids doivent avoir la même longueur")
  }
  sum(valeurs * poids) / sum(poids)
}

moyenne_ponderee(c(10, 15, 20), c(1, 2, 1))
#> [1] 15

Arguments par défaut :

bonjour <- function(prenom = "monde") {
  paste("Bonjour", prenom)
}
bonjour()
#> [1] "Bonjour monde"
bonjour("Léa")
#> [1] "Bonjour Léa"

4.16 Gestion des erreurs

lire_positif <- function(x) {
  tryCatch(
    {
      if (x < 0) stop("La valeur doit être positive")
      sqrt(x)
    },
    error = function(e) {
      message("Erreur : ", e$message)
      NA_real_
    }
  )
}
lire_positif(9)
#> [1] 3
lire_positif(-1)
#> [1] NA

4.17 Packages et bibliothèques

install.packages("dplyr")   # une fois
library(dplyr)              # à chaque session
# ou : dplyr::filter(...)   # sans charger tout le package
# Packages chargés (aperçu)
head(.packages(), 10)
#> [1] "tibble"    "stats"     "graphics"  "grDevices" "utils"     "datasets" 
#> [7] "methods"   "base"

4.18 Bonnes pratiques de programmation

  1. Noms explicites : prix_ht plutôt que x1
  2. Un script = un objectif clair
  3. Commentez le pourquoi, pas l’évidence
  4. Évitez de dupliquer : créez une fonction
  5. Fixez la graine pour la reproductibilité : set.seed(2024)
  6. Ne stockez pas de mots de passe dans les scripts
set.seed(2024)
sample(1:100, 5)
#> [1] 66 37 45 60 17

4.19 Démonstration complète

set.seed(1)
notes <- round(rnorm(30, mean = 12, sd = 3), 1)
notes <- pmin(20, pmax(0, notes))

resume_notes <- function(x) {
  list(
    n = length(x),
    moyenne = mean(x),
    mediane = median(x),
    ecart_type = sd(x),
    taux_reussite = mean(x >= 10)
  )
}

resume_notes(notes)
#> $n
#> [1] 30
#> 
#> $moyenne
#> [1] 12.25333
#> 
#> $mediane
#> [1] 12.8
#> 
#> $ecart_type
#> [1] 2.774357
#> 
#> $taux_reussite
#> [1] 0.8333333

4.20 Erreurs fréquentes

Erreur Explication
Indexation à 0 En R, le 1er élément est à l’indice 1
+ bloqué Parenthese/guillemet non fermé
Facteur traité comme nombre Convertir correctement avant calcul
Masque recyclé Longueurs incompatibles → avertissement

4.21 Exercices

4.21.1 Niveau 1

  1. Créez un vecteur ages de 5 âges et calculez min, max, moyenne.
  2. Quelle est la différence entre c(1,2) et list(1,2) ?

4.21.2 Niveau 2

  1. Écrivez une fonction est_pair(n) qui retourne TRUE si n est pair.
  2. À partir de mtcars, sélectionnez les voitures à 6 cylindres et hp > 110.

4.21.3 Niveau 3

  1. Écrivez resume_numeric(x) qui gère le cas où x contient des NA (na.rm = TRUE) et retourne un named vector (n, mean, sd).
  2. Simulez 100 tirages d’un dé équilibré et comptez les fréquences avec table().

4.22 Corrections

ages <- c(22, 34, 19, 45, 31)
min(ages); max(ages); mean(ages)
#> [1] 19
#> [1] 45
#> [1] 30.2
est_pair <- function(n) {
  n %% 2 == 0
}
est_pair(4)
#> [1] TRUE
est_pair(7)
#> [1] FALSE
mtcars[mtcars$cyl == 6 & mtcars$hp > 110, c("mpg", "cyl", "hp")]
#>               mpg cyl  hp
#> Merc 280     19.2   6 123
#> Merc 280C    17.8   6 123
#> Ferrari Dino 19.7   6 175
resume_numeric <- function(x) {
  c(
    n = sum(!is.na(x)),
    mean = mean(x, na.rm = TRUE),
    sd = sd(x, na.rm = TRUE)
  )
}
resume_numeric(c(1, 2, NA, 4))
#>        n     mean       sd 
#> 3.000000 2.333333 1.527525
set.seed(42)
de <- sample(1:6, 100, replace = TRUE)
table(de)
#> de
#>  1  2  3  4  5  6 
#> 15 24 10 19 19 13

4.23 Points clés

  • Tout est (presque) un vecteur ; les data frames organisent des vecteurs en colonnes.
  • L’indexation commence à 1 ; le filtrage logique est puissant.
  • Préférez fonctions + vectorisation aux longues boucles.
  • Les packages étendent R : installez une fois, chargez à chaque session.

4.24 Ressources

  • Aide intégrée : ?mean, help(factor)
  • R Core Team (2024), Wickham et al. (2019)

4.25 Suite

Chapter 5 : importer CSV, Excel et vérifier la qualité des données.