Cours 2 — Fondations

Patrick Fournier

MAT8186 — Techniques avancées en programmation statistiques R

Automne 2023

Structures de données

Définitions

  • Manière d'organiser les données en vue de leur traitement algorithmique
  • Structure linéaire \( := \) suite
  • Les plus employées en R: vecteur, matrice, array, liste, data.frame...
Exemple de tableau, case \( \Leftrightarrow \) «case mémoire»:
42 666 21 \( \cdots \) 0 31
Exemple: mémoire comme tableau: la matrice \( 2 \times 3 \) \[ \begin{pmatrix} 1 & 2 & 3\\ 4 & 5 & 6 \end{pmatrix} \] peut être représentée de deux manières:
1 2 3 4 5 6
(row-major order)

1 4 2 5 3 6
(column-major order)

Exemple: doubler une matrice


                    m <- n <- 1e3L
                    mat <- matrix(42L, m, n)

                    double_ligne <- function() {
                        for (i in seq_len(m))
                            for (j in seq_len(n))
                                mat[i, j] <- mat[i, j] + mat[i, j]
                    }

                    double_colonne <- function() {
                        for (j in seq_len(n))
                            for (i in seq_len(m))
                                mat[i, j] <- mat[i, j] + mat[i, j]
                    }
                
Benchmark double matrix

En bref: stockage linéaire dans R

  • Mémoire: très grand vecteur à éléments dans \( \{ 0, 1 \}^8 \)
  • Accès aléatoire: toute entrée est disponible pour le processeur à n'importe quel moment
  • Plus rapide d'accéder à de l'information près de celle à laquelle on vient d'accéder: localité de la référence
  • Efficacité \( \Rightarrow \) exploiter la localité de la référence 🏎

Algèbre:Scalaires et vecteurs

  • Scalaires vs vecteurs: scalaire \( \Leftrightarrow \) vecteur de dimension 1
  • Pas de type «vecteur»; dépend du contenu
    • numeric
      • integer (\( \mathbb Z \))
      • double \(\left( \mathbb R \setminus \mathbb Z \right)\)
    • complex \(\left( \mathbb C \setminus \mathbb R \right)\)
    • logical (\(\{ 0, 1 \} \Leftrightarrow \) FALSE, TRUE)
    • character (chaîne de caractère)
    • raw (données binaires 🤖)

                    vec_integer <- c(1L, 2L, 3L)
                    vec_double <- c(1.0, 2.0, 3.0)
                    vec_complexe <- c(1 + 2i, 3 + 4i)
                

                    r$> is.integer(vec_integer)
                    [1] TRUE
                    r$> is.double(vec_double)
                    [1] TRUE
                    r$> is.complex(vec_complex)
                    [1] TRUE
                

                    r$> is.numeric(vec_integer)
                    [1] TRUE
                    r$> is.numeric(vec_double)
                    [1] TRUE
                    r$> is.numeric(vec_complex)
                    [1] FALSE
                

                    ## Attention!
                    ## Même affichage =/= même valeur!
                    r$> vec_integer
                    [1] 1 2 3
                    r$> vec_double
                    [1] 1 2 3
                    r$> identical(vec_integer, vec_double)
                    [1] FALSE
                

                    vec_logical <- c(TRUE, FALSE, T, F)
                    vec_character <- c("J'αiμε", "bien", "R")
                    vec_raw <- as.raw(c(1, 13, 66, 0x42))
                

                    r$> vec_logical
                    [1] TRUE FALSE TRUE FALSE
                    r$> vec_character
                    [1] "J'αiμε" "bien" "R"
                    r$> vec_raw
                    [1] 01 0d 42 42
                

Algèbre: Matrices et tenseurs

  • De classe array
  • Matrice: de classe matrix en plus
  • Construits à partir de vecteurs
    • Simples vecteurs + attribut dim
    • \( \Rightarrow \) même types d'éléments que vecteurs

                    mat <- matrix(c(1, 2, 666, 42),
                                  nrow = 2, ncol = 2)
                    arr <- array(1:2^4, dim = c(2, 2, 4))
                

                    r$> class(mat)
                    [1] "matrix" "array"
                    r$> class(arr)
                    [1] "array"
                

Algèbre: opérations utiles

  • Transposition: t()
  • Somme, différence: +, -
  • Produit
    • Hadamard: *
    • Matriciel: %*%
    • Kronecker: %x%
  • Déterminant: det()
  • Valeurs & vecteurs propres: eigen
  • Inversion: solve()
  • Décomposition
    • Cholesky: chol()
    • QR: qr()
    • SVD: svd()
Pour deux matrices \( \bf X \) et \( \bf Y \):
  • Préférez crossprod(X, Y) à t(X) %*% Y
  • Préférez tcrossprod(X, Y) à X %*% t(Y)

Listes

  • Vecteurs: structures homogènes
    
                        r$> c(42, "quarante-deux")
                        [1] "42" "quarante-deux"
                    
  • Listes: hétérogènes
    
                        r$> list(42, "quarante-deux")
                        [[1]]
                        [1] 42
    
                        [[2]]
                        [1] "quarante-deux"
                    
  • Listes \( := \) vecteurs de références 🤓

Sélection

  • Sous-vecteur: []
    
                        r$> list("Je", "suis", 1, "liste")[3:4]
                        [[1]]
                        [1] 1
    
                        [[2]]
                        [1] "liste"
                    
  • Un seul élément [[]]
    
                        r$> list("Je", "suis", 1, "liste")[[3]]
                        [1] 1
                    

Noms

  • Possible de nommer les éléments d'un vecteur
  • Permet sélection par nom

              r$> vec <- c(4, 8, 15)

              r$> names(vec) <- c("Ford", "Reyes", "Shephard")

              r$> vec
                  Ford    Reyes Shephard
                     4        8       15
              r$> vec[c("Reyes", "Shephard")]
                 Reyes Shephard
                     8       15
              r$> vec[["Ford"]]
              [1] 4
            

Autres structures

  • Vecteur: presque tout
  • Environment
  • Tables de hachage (depuis version 4.2)

Fonctions

Concepts

  • Suite d'instructions pour réaliser une tâche
  • Peut prendre des arguments (comme en maths 🧮)
  • Peut retourner un résultat (pas comme en math 💻)
  • Peut modifier des variables externes; effets de bord
  • Syntaxe: function() & \()

                  r$> is_odd <- function(x) x %% 2 > 0

                  r$> is_odd(42)
                  [1] FALSE
                

                  r$> sapply(sample(1:100, 10), \(x) 2 * x + 1)
                   [1] 195   5 179  59  99 175 123  27 125 163
                

Fonctions d'ordre supérieur

  • Au moins un argument est une fonction (lapply, Filter, ...)
  • Retourne une fonction (Negate, purrr::compose, ...)
  • Fonctions d'ordre supérieur 🤝 fonctions anonymes

                  r$> is_even <- Negate(is_odd)

                  r$> is_even(42)
                  [1] TRUE
                

                  r$> Filter(is_even, 1:10)
                  [1]  2  4  6  8 10
                

                  r$> lapply(cars, compose(\(x) x / sd(x),
                                           \(x) x - mean(x)))
                  $speed
                  [1] -1.2056071 -1.2056071  0.2411214 ...

                  $dist
                  [1] -1.16368667 -0.08951436 -0.89514359 ...
                

Arguments par défaut

  • Normalement, chaque argument d'une fonction doit être fourni par l'utilisateur
  • Possible de spécifier des arguments par défaut
  • L'utilisateur peut fournir ou pas un tel argument

                    rand_exp <- function(n, θ = 1.0)
                        -θ * log(runif(n))
                

                    r$> mean(rand_exp(1e4L))
                    [1] 0.9987279
                    r$> mean(rand_exp(1e4L, 10))
                    [1] 9.779731
                

Fonctions variadiques

  • Peut prendre un nombre variable d'arguments
  • Argument spécial: ...
  • ... peut être
    • Passé à une autre fonction
    • Transformé en liste

                    mysum <- function(..., noise = FALSE) {
                        dat <- as.numeric(list(...))
                        n <- length(dat)

                        if (noise)
                            dat <- dat + rbeta(n, 0.5, 0.5)

                        sum(dat)
                    }
                

                    r$> mysum(1, 2, 3, 4, 5)
                    [1] 15
                    r$> mysum(1, 2, 3, 4, 5, noise = TRUE)
                    [1] 16.6915492697708
                

                  smallsum <- function(...) {
                      if (length(as.numeric(list(...))) > 5)
                          return(NA)

                      sum(...)
                  }
                

                    r$> smallsum(1, 3, 5, 6, 7, 8)
                    [1] NA
                    r$> smallsum(1, 3, 5, 6)
                    [1] 15
                

Fonctions récursives

  • Permises en R
  • Pas optimisées
  • Facile de dépasser la taille du stack 🤯

                    fact <- function(x) {
                        identical(x, 1.0) && return(x)

                        x * fact(x - 1.0)
                    }
                

                    r$> fact(10)
                    [1] 3628800
                    r$> fact(171)
                    [1] Inf
                    r$> fact(657)
                    Error: C stack usage  7972452 is too
                    close to the limit
                

Pipe 🪠

  • Nouvel opérateur (R >= 4.1): |>
  • x |> f(y, z) équivaut à f(x, y, z)
  • Utile pour chaîner des opérations
Exemple: Somme de la racine carrée des nombres naturels inférieurs à 100 qui sont multiples de 3 ou 5.

                    r$> 1:100 |>
                            Filter(f = \(x) x %% 3 == 0 |
                                            x %% 5 == 0) |>
                            sqrt() |>
                            sum()
                    [1] 319.462518394456