\[Analyse~et~qualité~des~données~(cours)~-~Ben~Iman\] ### Importation des modules

library(dplyr)
## 
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
## 
##     filter, lag
## The following objects are masked from 'package:base':
## 
##     intersect, setdiff, setequal, union
library(ggplot2)
library(cluster)

Exercice 1 : Calcul des 21 premiers termes de la suite de Fibonacci

# Initialisation des variables
fibonacci <- numeric(21) # Création d'un vecteur vide pour stocker les 21 termes
fibonacci[1] <- 0  # Premier terme
fibonacci[2] <- 1  # Deuxième terme

# Calcul des termes suivants avec une boucle for
for (n in 3:21) {
  fibonacci[n] <- fibonacci[n-1] + fibonacci[n-2]
}

# Affichage des résultats
cat("Les 21 premiers termes de la suite de Fibonacci sont :\n")
## Les 21 premiers termes de la suite de Fibonacci sont :
fibonacci
##  [1]    0    1    1    2    3    5    8   13   21   34   55   89  144  233  377
## [16]  610  987 1597 2584 4181 6765

La Suite de Fibonacci : Une Merveille Mathématique !

La suite de Fibonacci, c’est une série de nombres très spéciale et simple à comprendre ! Elle commence comme ça :
0, 1, 1, 2, 3, 5, 8, 13, 21, 34…

Comment ça marche ?

Chaque nombre est la somme des deux nombres qui le précèdent.
- On commence avec 0 et 1.
- Ensuite, on ajoute les deux :
\(0 + 1 = 1\).
- Puis, on continue :
\(1 + 1 = 2\),
\(1 + 2 = 3\),
\(2 + 3 = 5\), et ainsi de suite.

Un Exemple Simple

Imagine que tu plantes une graine d’arbre. Chaque mois, elle donne un nouveau bourgeon qui lui-même pousse le mois suivant. Le nombre de bourgeons suit la suite de Fibonacci !

Pourquoi c’est génial ?

La suite de Fibonacci apparaît partout !
- Dans la nature : les pétales de fleurs, la spirale des coquillages, et même les pommes de pin.
- En maths et en informatique : elle est utilisée dans plein de calculs et algorithmes.

Un jeu pour vous !

Essayez de continuer la suite ! Après 34, quels sont les deux prochains nombres ?

Rappel : 0, 1, 1, 2, 3, 5, 8, 13, 21, 34…

Exercice 2 : Centre de gravité

Ecrire un code permettant de stocker cette matrice

# === Stockage de la matrice X ===
c1 <- c(2, 7.5,3, 0.5, 6)
c2 <- c(2 ,4 ,3 ,5, 4) 
X <- cbind(c1,c2)

# Nous créons une matrice nommée X avec 5 lignes et 2 colonnes avec cbind 
# Les données sont entrées dans un vecteur, puis organisées sous forme de matrice.
# 


# === Affichage de la matrice. ===
cat("Matrice X :\n")
## Matrice X :
X
##       c1 c2
## [1,] 2.0  2
## [2,] 7.5  4
## [3,] 3.0  3
## [4,] 0.5  5
## [5,] 6.0  4

Ecrire un code permettant d’afficher le centre de gravité

# === Fonction pour calculer la moyenne de chaque colonne d'une matrice ===
moyenne_colonnes <- function(matrice) {
  # Initialiser un vecteur pour stocker les moyennes
  moyennes <- numeric(ncol(matrice)) 
  
  # Calculer la moyenne pour chaque colonne
  for (i in 1:ncol(matrice)) {
    moyennes[i] <- sum(matrice[, i])/nrow(matrice)
  }
  
  return(moyennes)
}

# === Utilisation ===
centre_gravite <- moyenne_colonnes(X)  # Appel de la fonction
cat("Centre de gravité :", centre_gravite, "\n")
## Centre de gravité : 3.8 3.6

Faire une représentation graphique.

# === Représentation graphique du nuage de points ===

plot(X, pch = 1, col = "blue", xlab = "X1", ylab = "X2", 
     main = "Nuage de points et centre de gravité", xlim = c(0, 8), xaxt = "n")

# La fonction plot() permet de créer un graphique des points définis par la matrice X.
# - `pch = 1` : Style des points (ici, cercles vides).
# - `col = "blue"` : Couleur des points du nuage.
# - `xlab` et `ylab` : Labels pour les axes X et Y.
# - `main` : Titre principal du graphique.
# - `xlim` : Limites de l'axe des abscisses avec des espacements entiers.



#=== Ajout d'une échelle d'axes X avec des espacements entiers ===

axis(side = 1, at = seq(0, 8, by = 1))
# La fonction axis() permet de personnaliser les graduations des axes.
# - `side = 1` : Indique que nous modifions l'axe X (abscisses).
# - `at` : Définit les positions des graduations sur l'axe.



#=== Ajout du centre de gravité au graphique ===

points(centre_gravite[1], centre_gravite[2], col = "red", pch = 1, cex = 1.5)

# La fonction points() permet d'ajouter un point supplémentaire sur le graphique.
# - `centre_gravite[1]` et `centre_gravite[2]` : Coordonnées X et Y du centre de gravité.
# - `cex = 1.5` : Taille du point (1.5 fois la taille par défaut).



# === Ajout d'une légende à l'extérieur du graphique ===

legend("topright", legend = c("Points", "Centre de gravité"), 
       col = c("blue", "red"), pch = c(1, 1))

# Ajout d'une légende au graphique
# La fonction legend() ajoute une légende pour distinguer les points du nuage et le centre de gravité.
# - `"topright"` : Position de la légende (coin supérieur droit).
# - `legend` : Texte pour chaque élément de la légende.
# - `col` : Couleurs associées aux éléments (points bleus et point rouge).

Exercice 2 : Les distances

- Distance euclidienne :

Démonstration

Introduction

Soit \(m \in \mathbb{N}^*\)

Nous voulons démontrer que la distance euclidienne, définie par :
\[ d(x, y) = \sqrt{\sum_{i=1}^m (x_i - y_i)^2}, \]\(x = (x_1, \dots, x_m) \in \mathbb{R}^m\) et \(y = (y_1, \dots, y_m) \in \mathbb{R}^m\), satisfait les trois propriétés d’une distance (cf. le cours Analyse et qualité de données) :

  1. L’identité : \(d(x, y) = 0 \iff x = y\). (NB : une distance est toujous positive, je suppose que c’est évident.)
  2. Symétrie : \(d(x, y) = d(y, x)\).
  3. Inégalité triangulaire : \(d(x, y) \leq d(x, z) + d(z, y)\), pour tout \(x, y, z \in \mathbb{R}^m\).

1. Séparation

Si \(d(x, y) = 0\), alors :
\[ \sqrt{\sum_{i=1}^m (x_i - y_i)^2} = 0. \] Cela implique que :
\[ \sum_{i=1}^m (x_i - y_i)^2 = 0. \] Étant donné que chaque terme \((x_i - y_i)^2 \geq 0\), cela est vrai si, et seulement si, \((x_i - y_i)^2 = 0\) pour tout \(i\), ce qui signifie que \(x_i = y_i\) pour tout \(i\). Donc, \(x = y\).

Inversement, si \(x = y\), alors \(x_i = y_i\) pour tout \(i\), donc \(d(x, y) = 0\).

2. Symétrie

En permutant \(x\) et \(y\), on a :
\[ d(x, y) = \sqrt{\sum_{i=1}^m (x_i - y_i)^2}. \] Or \((x_i - y_i)^2 = (y_i - x_i)^2\), donc :
\[ d(x, y) = \sqrt{\sum_{i=1}^m (y_i - x_i)^2} = d(y, x). \]

3. Inégalité triangulaire

Pour tout \(x, y, z \in \mathbb{R}^m\), on veut montrer que :
\[ d(x, y) \leq d(x, z) + d(z, y). \] En utilisant l’inégalité de Minkowski pour la norme \(L_2\), on a :
\[ \sqrt{\sum_{i=1}^m (x_i - y_i)^2} \leq \sqrt{\sum_{i=1}^m (x_i - z_i)^2} + \sqrt{\sum_{i=1}^m (z_i - y_i)^2}. \] Ainsi, l’inégalité triangulaire est vérifiée.

Conclusion

Nous avons montré que la distance euclidienne satisfait les trois propriétés suivantes :

  1. \(d(x, y) = 0 \iff x = y\),
  2. \(d(x, y) = d(y, x)\),
  3. \(d(x, y) \leq d(x, z) + d(z, y)\).

Subséquemment, la distance euclidienne est bien une distance au sens mathématique.

_ _ Code : stockage distance euclidienne _ _

distance_euclidienne <- function(x,y) {
  # Calcul de la somme des carrés des différences
  diff_xy = sum((x - y)^2)
  
  # Racine carrée de la somme des carrés pour obtenir la distance
  distance <- sqrt(diff_xy)
  
  # Retourner la distance calculée
  return(distance)
}
# ATTENTION : les vecteurs doivent être de même dimension
distance_euclidienne(c(2, 7.5, 3, 0.5, 6),c(2, 4, 3, 5, 4))
## [1] 6.041523

- Distance de Manhattan

Démonstration :

La distance de Manhattan entre deux points \(x = (x_1, x_2, \ldots, x_m)\) et \(y = (y_1, y_2, \ldots, y_m)\) est définie par :

\[ d(x, y) = \sum_{i=1}^{m} |x_i - y_i| \]

1. Séparation

  • \(d(x, y) \geq 0\) car \(|x_i - y_i| \geq 0\) pour tout \(i\).
  • \(d(x, y) = 0\) si et seulement si \(|x_i - y_i| = 0\) pour tout \(i\), ce qui implique que \(x_i = y_i\) pour tout \(i\), donc \(x = y\).

2. Symétrie

\[d(x, y) = \sum_{i=1}^{m} |x_i - y_i| = \sum_{i=1}^{m} |y_i - x_i| = d(y, x)\]

3. Inégalité triangulaire

  • Pour tout \(x, y, z \in \mathbb{R}^m\),
    \[ d(x, y) = \sum_{i=1}^{m} |x_i - y_i| \leq \sum_{i=1}^{m} (|x_i - z_i| + |z_i - y_i|) = d(x, z) + d(z, y) \]

  • Cette inégalité découle de l’inégalité triangulaire pour la valeur absolue : \(|x_i - y_i| \leq |x_i - z_i| + |z_i - y_i|\).

_ _ _ Code : stockage distance de Manhattan _ _ _

manhattan_distance <- function(x, y) {
  sum(abs(x - y))
}

# === Utilisation ===
x <- c1
y <- c2
manhattan_distance(x, y)
## [1] 10

Rappel : c1 = (2, 7.5,3, 0.5, 6) et c2 = c(2 ,4 ,3 ,5, 4)

Distance de Minkowski

La distance de Minkowski est une généralisation des distances classiques comme la distance Euclidienne et la distance de Manhattan. Elle est utilisée pour mesurer la distance entre deux points dans un espace vectoriel de manière flexible, en fonction d’un paramètre appelé ordre \(p\).

Définition
La distance de Minkowski entre deux points \(x = (x_1, x_2, \dots, x_n)\) et \(y = (y_1, y_2, \dots, y_n)\) dans un espace à \(n\) dimensions est définie par la formule :

\[ D_p(x, y) = \left( \sum_{i=1}^{n} |x_i - y_i|^p \right)^{1/p} \]

Où :

- \(x_i\) et \(y_i\) sont les coordonnées des deux points dans l’espace, - \(p\) est un paramètre de l’ordre de la distance (un réel positif),

- La somme est effectuée sur toutes les dimensions de l’espace.

Interprétation selon la valeur de p :

- Lorsque \(p = 1\), la distance de Minkowski devient la distance de Manhattan (ou distance L1), qui est la somme des valeurs absolues des différences des coordonnées :

\[ D_1(x, y) = \sum_{i=1}^{n} |x_i - y_i| \]

  • Lorsque \(p = 2\), la distance de Minkowski devient la distance Euclidienne (ou distance L2), qui est la plus courante :

\[ D_2(x, y) = \left( \sum_{i=1}^{n} (x_i - y_i)^2 \right)^{1/2} \]

  • Lorsque \(p \to \infty\), la distance de Minkowski devient la distance de Chebyshev, qui mesure la plus grande différence absolue entre les coordonnées :

\[ D_{\infty}(x, y) = \max_{i} |x_i - y_i| \]

# === Fonction pour calculer la distance de Minkowski ===
minkowski_distance <- function(x, y, p) {
  # p : Ordre de la distance (ex : p=2 pour euclidienne, p=1 pour Manhattan).
  
  # Calcul : somme des différences absolues élevées à la puissance p
  sum_diff_p <- sum(abs(x - y)^p)
  
  # Racine de degré p
  return(sum_diff_p^(1 / p))
}

# Exemple
x <- c1
y <- c2
print(minkowski_distance(x, y, p = 2))
## [1] 6.041523

Distance de Canberra

La distance de Canberra est définie par la formule suivante :

\[ D_{\text{Canberra}}(x, y) = \sum_{i=1}^{m} \frac{|x_i - y_i|}{|x_i| + |y_i|} \]

Où : - \(x_i\) et \(y_i\) sont les éléments des deux vecteurs \(x\) et \(y\), - La somme est effectuée sur toutes les dimensions de l’espace.

Elle mesure la différence relative entre les coordonnées de deux vecteurs, en tenant compte des valeurs absolues des différences et des sommes des valeurs absolues

\(|x_{i}| + |y_{i}|\) normalise la différence en fonction des valeurs absolues de \(x_i\) et \(y_i\) , ce qui est particulièrement utile pour éviter que de grandes valeurs de \(x\) ou \(y\) n’affectent trop la distance.

_ _ _ Code distance de Canberra _ _ _

# Fonction pour calculer la distance de Canberra
canberra_distance <- function(x, y) {
  
  # Somme des fractions : |xi - yi| / (|xi| + |yi|)
  somme_fractions <- sum(abs(x - y) / (abs(x) + abs(y)))
  
  # Somme des fractions
  return(somme_fractions)
}

# Utilisation
x <- c1
y <- c2
print(canberra_distance(x, y))
## [1] 1.32253

Rappel : c1 = (2, 7.5,3, 0.5, 6) | c2 = (2 ,4 ,3 ,5, 4)

ATTENTION : \(|x_{i}|\) + \(|y_{i}|\) =! 0

Distance maximale (code)

# Fonction pour calculer la distance maximale
maximum_distance <- function(x, y) {

  # Différence absolue
  diff <- abs(x - y)
  
  # Retourne la valeur maximale
  return(max(diff))
}

# Utilisation
x <- c1
y <- c2
print(maximum_distance(x, y))
## [1] 4.5

Distance entre individus (slide 37)

▶ Ecrire une fonction en R et Python prenant en argument une table de donnée et retourner la matrice de dissimilarité pour une distance quelconque d

#Calcul des distance entre les individus gen
dist_individus <- function(maData) {
  # Initialiser une matrice pour stocker les distances
  d <- matrix(rep(0,9), nrow(maData), ncol(maData))
  
  # Boucle sur les lignes de la matrice
  for (i in 1:nrow(maData)) {
    for (j in 1:nrow(maData)) {
      # Calculer la distance Euclidienne entre les individus i et j
      d[i, j] = sum((maData[i, ] - maData[j, ])^2)
    }
  }
  
  return(sqrt(d)) #Passe d^2 à la racine et renvoie la matrice des distances
}

— Exemple d’utilisation —

# Exemple d'utilisation
Data=matrix(1:9, ncol=3, nrow = 3)
Data
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
distances <- dist_individus(Data)
cat("\nLa matrice de dissimilarité :\n")
## 
## La matrice de dissimilarité :
distances
##          [,1]     [,2]     [,3]
## [1,] 0.000000 1.732051 3.464102
## [2,] 1.732051 0.000000 1.732051
## [3,] 3.464102 1.732051 0.000000

▶ Ecrire des fonctions pour évaluer des distances Euclidienne, Manhatan, etc..

  • Fonction distance euclidienne
#Calcul des distance entre les individus gen
distance_euclidienne_dissimilarite <- function(maData) {
  # Initialiser une matrice pour stocker les distances
  d <- matrix(rep(0,9), nrow(maData), ncol(maData))
  
  # Boucle sur les lignes de la matrice
  for (i in 1:nrow(maData)) {
    for (j in 1:nrow(maData)) {
      # Calculer la distance Euclidienne entre les individus i et j
      d[i, j] = sum((maData[i, ] - maData[j, ])^2)
    }
  }
  
  return(sqrt(d))
}

Notez bien que, dans tout ce qui suit, j’utilise des matrices 3x3, d’où rep(0, 9), une matrice avec 9 éléments. Il serait donc peut-être pertinent de généraliser cela par la suite. Je ne connais pas encore le nombre maximum d’éléments que R peut accepter.

  • Fonction distance Manhattan
distance_manhattan_dissimilarite <- function(maData) {
  d <- matrix(rep(0,9), nrow(maData), ncol(maData))
  for (i in 1:nrow(maData)) {
    for (j in 1:nrow(maData)) {
      # Calculer la distance de Manhattan entre les individus i et j
      d[i, j] = sum(abs(maData[i, ] - maData[j, ]))
    }
  }
  return(d)
}
  • Fonction distance Canberra
distance_camberra_dissimilarite <- function(maData){
  d <- matrix(rep(0,9),nrow(maData), ncol(maData))
  for (i in 1:nrow(maData)){
    for (j in 1:nrow(maData)){
      #Calcul des distances en utilisant la méthode de camberra
      d[i, j] = sum(abs(maData[i,] - maData[j,])/abs(maData[i,] + maData[j,]))
    }
  }
  return(d)
}
  • Fonction distance maximum
distance_maximum_dissimilarite <- function(maData) {
  d <- matrix(rep(0,9), nrow(maData), nrow(maData))
  for (i in 1:nrow(maData)) {
    for (j in 1:nrow(maData)) {
      # Calcul des distances en utilisant la méthode de Chebyshev (maximum)
      d[i, j] <- sum(max(abs(maData[i,] - maData[j,])))
    }
  }
  
  return(d)
}
  • Distance de Minkowski
distance_minkowski_dissimilarite <- function(maData, p) {
  
  d <- matrix(0, nrow(maData), nrow(maData))
  
  for (i in 1:nrow(maData)) {
    for (j in 1:nrow(maData)) {
      # Calcul des distances en utilisant la méthode de Minkowski
      d[i, j] <- (sum(abs(maData[i, ] - maData[j, ])^p))^(1/p)
    }
  }
  
  # Retourner la matrice de distances
  return(d)
}

▶ Ecrire une fonction permettant de prendre en argument une table de donnée, de choisir une distance d parmi une famille de distances disponibles et retourner la matrice de dissimilarité

ma_matrice_des_distances <- function(maData, methode, ordre){
  # Si : Méthode euclidienne
  if (methode == "euclidienne" && ordre == FALSE) {
    distance_euclidienne_dissimilarite(maData)
  # Sinon Si : Methode de manhattan
  } else if (methode == "manhattan" && ordre == FALSE) {
      distance_manhattan_dissimilarite(maData)
  # Sinon Si : Méthode de canberra
  } else if (methode == "canberra" && ordre == FALSE) {
      distance_camberra_dissimilarite(maData)
  # Sinon Si : Méthode maximum
  } else if (methode == "maximum" && ordre == FALSE) {
      distance_maximum_dissimilarite(maData)
  # Sinon : Méthode de Minkowski
  } else {
      distance_minkowski_dissimilarite(maData, p = ordre)
  }
}

Notice : La fonction ma_matrice_des_distances() prend en arguments votre data, la méthode que vous voulez utiliser, et par défaut, l’ordre doit être FALSE. L’ordre est le paramètre p de la méthode Minkowski.

– Exemple d’utlisation –

# Exemple d'utilisation
Data=matrix(1:9, ncol=3, nrow = 3)
Data
##      [,1] [,2] [,3]
## [1,]    1    4    7
## [2,]    2    5    8
## [3,]    3    6    9
# Définissez votre méthode ici, pour une raison visuelle !
methode <- "minkowski" 

distances <- ma_matrice_des_distances(Data, methode, ordre=2) 
cat(sprintf("\nLa matrice de dissimilarité (Méthode : %s) :\n", methode))
## 
## La matrice de dissimilarité (Méthode : minkowski) :
distances
##          [,1]     [,2]     [,3]
## [1,] 0.000000 1.732051 3.464102
## [2,] 1.732051 0.000000 1.732051
## [3,] 3.464102 1.732051 0.000000

Exercice 3 : Décomposition de Huygens

Définitions et notations

  1. \(\omega_i\) :
    Représente les \(n\) individus de l’ensemble, où chaque \(\omega_i\) est un vecteur dans un espace vectoriel \(\mathbb{R}^m\) (espace des \(m\)-dimensions).
    Domaine de définition : \(\omega_i \in \mathbb{R}^m\).

  2. \(G\) :
    Le centre de gravité global, calculé comme la moyenne des \(\omega_i\). Il s’agit du barycentre de l’ensemble des individus.
    Domaine de définition : \(G \in \mathbb{R}^m\).

  3. \(C_k\) :
    Un sous-groupe d’individus \(C_k \subseteq \{\omega_1, \omega_2, \dots, \omega_n\}\), où chaque groupe \(C_k\) contient \(n_k\) individus.
    Domaine de définition : \(C_k \subseteq \{\omega_1, \omega_2, \dots, \omega_n\}\), et \(n_k\) est l’effectif de ce sous-groupe : \(n_k = \text{card}(C_k)\).

  4. \(G_k\) :
    Le centre de gravité de chaque groupe \(C_k\), défini comme la moyenne des individus appartenant à \(C_k\).
    Domaine de définition : \(G_k \in \mathbb{R}^m\).

  5. \(d(\omega_i, G)\) :
    La distance entre un individu \(\omega_i\) et le centre de gravité global \(G\). Typiquement, cette distance est la norme euclidienne dans \(\mathbb{R}^m\), i.e.,
    \[ d(\omega_i, G) = \| \omega_i - G \| \]
    Domaine de définition : \(\omega_{i}\) d(\(\omega_{i}\) ,G) \(\in\mathbb{R}+\)

  6. \(I_{\text{tot}}, I_{\text{intra}}, et I_{\text{inter}}\) :

    • \(I_{\text{tot}}\) : L’inertie totale, qui mesure la dispersion de tous les individus par rapport au centre de gravité global \(G\).
      \[ I_{\text{tot}} = \frac{1}{n} \sum_{i=1}^n d^2(\omega_i, G) \]
      Domaine de définition : \(I_{tot}\) valeur réelle positive.

    • \(I_{\text{intra}}\) : L’inertie intra-classe, qui mesure la dispersion des individus à l’intérieur des groupes, par rapport à leur centre de gravité respectif \(G_k\).
      \[ I_{\text{intra}} = \frac{1}{n} \sum_{k=1}^K \sum_{\omega_i \in C_k} d^2(\omega_i, G_k) \]
      Domaine de définition : \(I_{intra}\) valeur réelle positive.

    • \(I_{\text{inter}}\) : L’inertie inter-classe, qui mesure la dispersion des centres de gravité des groupes \(G_k\) par rapport au centre de gravité global \(G\).
      \[ I_{\text{inter}} = \frac{1}{n} \sum_{k=1}^K n_k d^2(G_k, G) \]
      Domaine de définition : \(I_{inter}\) valeur réelle positive.

Théorème

La relation entre les inerties s’écrit ainsi : \[ I_{\text{tot}} = I_{\text{intra}} + I_{\text{inter}} \]

Démonstration

  1. Décomposition de la distance au carré :
    La distance entre un individu \(\omega_i\) et le centre de gravité global \(G\) peut se réécrire en utilisant le centre de gravité du groupe \(G_k\) auquel appartient \(\omega_i\), grâce à la propriété du barycentre : \[ d^2(\omega_i, G) = d^2(\omega_i, G_k) + d^2(G_k, G) \]
    Domaine de définition : Les deux termes \(d^2(\omega_i, G_k)\) et \(d^2(G_k, G)\) sont des réels positifs.

  2. Somme sur tous les individus :
    En sommant cette relation pour tous les individus, on obtient : \[ \sum_{i=1}^n d^2(\omega_i, G) = \sum_{k=1}^K \sum_{\omega_i \in C_k} \left( d^2(\omega_i, G_k) + d^2(G_k, G) \right) \]
    Domaine de définition : Cette somme est toujours bien définie et donne une quantité réelle.

  3. Séparation des termes :
    Cette somme peut être séparée en deux parties, représentant respectivement l’inertie intra-classe et l’inertie inter-classe : \[ \sum_{i=1}^n d^2(\omega_i, G) = \underbrace{\sum_{k=1}^K \sum_{\omega_i \in C_k} d^2(\omega_i, G_k)}_{\text{Inertie intra-classe}} + \underbrace{\sum_{k=1}^K \sum_{\omega_i \in C_k} d^2(G_k, G)}_{\text{Inertie inter-classe}} \]
    Domaine de définition : Les deux termes sont réels et positifs.

  4. Regroupement des termes inter-classes :
    En utilisant la cardinalité \(n_k\) de chaque groupe \(C_k\), la somme inter-classe devient : \[ \sum_{k=1}^K \sum_{\omega_i \in C_k} d^2(G_k, G) = \sum_{k=1}^K n_k d^2(G_k, G) \]
    Domaine de définition : Cette somme est bien définie et donne un réel positif.

Conclusion

La décomposition de l’inertie totale s’écrit donc comme suit : \[ I_{\text{tot}} = I_{\text{intra}} + I_{\text{inter}} \]

Cette décomposition montre comment l’inertie totale se sépare entre la variabilité à l’intérieur des groupes (inertie intra-classe) et la variabilité entre les groupes (inertie inter-classe).

Rappel : …. (Théroreme du barycentre) ????

Inertie totale : Imagine que tu as tous les points dans un grand nuage. L’inertie totale mesure la dispersion des points par rapport au centre global.

Exemple : Si tu jettes des billes par terre et que tu dessines le centre de ce tas de billes, l’inertie totale te dit à quel point elles sont dispersées autour de ce centre.

Inertie intra-classes : Maintenant, divise les billes en deux groupes (par exemple, rouges et bleues). Dans chaque groupe, tu calcules à quel point les billes sont éloignées de leur propre centre.

Exemple : Si tu regroupes les billes rouges d’un côté et les bleues de l’autre, tu mesures la “cohésion” dans chaque groupe.

Inertie inter-classes : Enfin, mesure à quel point les centres des groupes (rouge et bleu) sont éloignés l’un de l’autre.

Exemple : Si les rouges et les bleues sont très loin l’un de l’autre, leur inertie inter sera grande.

Conclusion : L’inertie totale, qui mesure la dispersion globale, peut être décomposée comme ceci :

\[Inertie~totale = Inertie~intra\_classes + Inertie~inter\_classes\]

- Code pour calculer \(I_\text{tot}\), \(I_\text{inter}\), et \(I_\text{intra}\) pour une partition \(A, B\).

Inertie intra-classes

calculer_inertie_intra <- function(donnees, groupes) {
  n <- nrow(donnees)  # Nombre total d'individus
  k <- max(groupes)   # Nombre de groupes
  inertie_intra <- 0  # Initialisation de l'inertie intra-classe
  
  # Une boucle pour chaque groupe
  for (groupe in 1:k) {
    # Points appartenant au groupe actuel (nA_{k})
    points_groupe <- donnees[groupes == groupe, ]
    # Centre de gravité du groupe
    centre_groupe <- moyenne_colonnes(points_groupe)

    # Calcul de l'inertie intra-classe pour le groupe
    for (i in 1:nrow(points_groupe)) {
      inertie_intra <- inertie_intra + sum((points_groupe[i, ] - centre_groupe)^2)
    }
  }
  
  # Retour de l'inertie intra-classe moyenne
  return(inertie_intra / n)
}

Inertie inter

calculer_inertie_inter <- function(donnees, groupes) {
  n <- nrow(donnees)  # Nombre total d'individus
  k <- max(groupes)   # Nombre de groupes
  inertie_inter <- 0  # Initialisation de l'inertie inter-classe
  centre_global <- moyenne_colonnes(donnees)  # Calcul du centre de gravité global
  
  # Boucle sur chaque groupe
  for (groupe in 1:k) {
    points_groupe <- donnees[groupes == groupe, ] # Points appartenant au groupe actuel "1*" 
    taille_groupe <- nrow(points_groupe) # Taille du groupe
    centre_groupe <- moyenne_colonnes(points_groupe)  # Centre de gravité du groupe
    
    inertie_inter <- inertie_inter + taille_groupe * sum((centre_groupe - centre_global)^2)  # Calcul de l'inertie inter-classe pour le groupe
  }
  
  # Retour de l'inertie inter-classe moyenne
  return(inertie_inter / n) #inertie inter sur le nombre total d'individus
}

“1*” : Cette expression crée un vecteur logique (ou booléen) de la même longueur que groupes. Pour chaque élément de groupes, elle vérifie s’il est égal à la valeur actuelle de groupe. Le résultat est un vecteur de valeurs TRUE et FALSE. Par exemple, si groupes est [1, 1, 1, 2, 2, 2] et groupe est 1, alors groupes == groupe donne [TRUE, TRUE, TRUE, FALSE, FALSE, FALSE].

Inertie totale

calculer_inertie_totale <- function(donnees, groupes) {
  
  inertie_intra <- calculer_inertie_intra(donnees, groupes) # Inertie intra-classe
  
  inertie_inter <- calculer_inertie_inter(donnees, groupes) # Inertie inter-classe
  
  inertie_totale <- inertie_intra + inertie_inter
  
  # Retour des inerties calculées
  return(inertie_totale)
}

Exemple d’utilisation

# Données (2 dimensions, 6 individus, 2 groupes)
donnees <- matrix(c(1, 2, 2, 1, 1, 1,   # Groupe 1
                    6, 7, 7, 6, 6, 6),  # Groupe 2
                  ncol = 2, byrow = TRUE)

groupes <- c(1, 1, 1, 2, 2, 2)  # Appartenance des individus aux groupes (*Observation*)

# Appel de la fonction pour calculer les inerties
resultats1 <- calculer_inertie_totale(donnees, groupes)

resultats2 <- calculer_inertie_intra(donnees, groupes)

resultats3 <- calculer_inertie_inter(donnees, groupes)

# Affichage des résultats
cat("Inertie totale :", resultats1, "\n")
## Inertie totale : 12.94444
cat("\nInertie intra classes :", resultats2, "\n")
## 
## Inertie intra classes : 0.4444444
cat("Inertie inter classes :", resultats3, "\n")
## Inertie inter classes : 12.5

Observation : Les groupes doivent être des entiers, sinon le code ne fonctionne pas.

I - Etude de la ressemblance

3- Ecarts

Exercice 3 : Clustering ascendant hiérarchique (CAH) (slide 87-90)

Enoncé de l’exercice

On souhaite analyser la similarité entre différents échantillons de données environnementales à l’aide des distances de Bray-Curtis et de Simpson, puis appliquer un clustering ascendant hiérarchique pour regrouper les échantillons.

La matrice suivante représente l’abondance de trois espèces (S1, S2, S3) dans quatre échantillons (E1, E2, E3, E4) :

matrice_ech <- matrix(c(10, 15, 5, 0, 20, 10, 15, 5, 5, 5, 10, 10), 
                  nrow = 3, # nombre de lignes
                  byrow = TRUE) # Remplis la matrice par lignes

rownames(matrice_ech) <- c("S1", "S2", "S3")
colnames(matrice_ech) <- c("E1", "E2", "E3", "E4")
matrice_ech
##    E1 E2 E3 E4
## S1 10 15  5  0
## S2 20 10 15  5
## S3  5  5 10 10
  • Matrice de dissimilarité entre les échantillons (E1, E2, E3, E4) avec la méthode de Bray-Curtis
#Initialisons une matrice vide
d <- matrix(0, nrow(matrice_ech), ncol = nrow(matrice_ech))

#Boucle sur les lignes et les colonnes
for (i in 1:nrow(matrice_ech)){
  for (j in 1:nrow(matrice_ech)){
    # formule de bray-curtis
    d[i, j] <- sum(abs(matrice_ech[i,] - matrice_ech[j, ])/sum((matrice_ech[i,] + matrice_ech[j, ])))
  }
}
ma_matrice_dist_bray_curtis <- d
ma_matrice_dist_bray_curtis
##       [,1]  [,2]  [,3]
## [1,] 0.000 0.375 0.500
## [2,] 0.375 0.000 0.375
## [3,] 0.500 0.375 0.000

Observation : Nous avons une somme au numérateur et une deuxième somme au dénominateur. Il faut donc utiliser deux fois la fonction sum(). J’avais fait l’erreur d’utiliser un seul sum() et je dirais que cela ne marchait pas trop.

  • Matrice de dissimilarité avec la méthode de Simpson (Ma version fausse)
#d_simp <- matrix(0, nrow(matrice_ech), ncol = nrow(matrice_ech))
#for (i in 1:nrow(matrice_ech)){
#  for (j in 1:nrow(matrice_ech)){
#    d_simp[i ,j] <- 1 - (sum(pmin(matrice_ech[i,],matrice[j,])) / #sum(matrice_ech[i,]))
    #pmin "1*"
#  }
#}
#ma_matrice_dist_simpson <- d_simp
#ma_matrice_dist_simpson

“1*” : x <- c(3, 5, 7) y <- c(4, 2, 8)

pmin(x, y)

[1] 3 2 7

Observation : Cela est déconcertant car nous n’avons pas une matrice symétrique. Je pense que j’ai du faire une erreur quelque part, mais je n’arrive pas à la trouver.

  • Matrice de dissimilarité avec la méthode de Simpson (déboguage avec laide de l’IA)
d_simp <- matrix(0, nrow(matrice_ech), ncol = nrow(matrice_ech))
for (i in 1:nrow(matrice_ech)){
  for (j in i:nrow(matrice_ech)){  # commence à j = i pour éviter les calculs redondants
    dist_simpson <- 1 - (sum(pmin(matrice_ech[i,], matrice_ech[j,])) / sum(matrice_ech[i,]))
    d_simp[i, j] <- dist_simpson
    d_simp[j, i] <- dist_simpson  # pour garantir la symétrie
  }
}
ma_matrice_dist_simpson <- d_simp
ma_matrice_dist_simpson
##           [,1]      [,2] [,3]
## [1,] 0.0000000 0.1666667  0.5
## [2,] 0.1666667 0.0000000  0.5
## [3,] 0.5000000 0.5000000  0.0
  1. Utilisez la matrice de dissimilarité obtenue avec la distance de Bray-Curtis pour effectuer un clustering ascendant hiérarchique.
trouvons_cluster_1 <- hclust(as.dist(ma_matrice_dist_bray_curtis), method = "complete" ) # "1*"
#hclust() : Applique un algorithme de classification hiérarchique ascendante (CAH) en utilisant les distances calculées.
trouvons_cluster_1
## 
## Call:
## hclust(d = as.dist(ma_matrice_dist_bray_curtis), method = "complete")
## 
## Cluster method   : complete 
## Number of objects: 3

“1*” : Méthode “complete” : Cette méthode est appelée “lien complet” (complete linkage).

Elle fusionne les groupes en choisissant la plus grande distance entre tous les points des groupes. Plus la distance de fusion est grande, plus les groupes fusionnés sont éloignés les uns des autres.

Processus de clustering : Chaque ligne de donnees_brutes est initialement un cluster unique. On fusionne les deux clusters les plus proches (ceux avec la plus petite distance).On répète l’opération jusqu’à ce qu’il ne reste plus qu’un seul cluster.

  • Représentez les regroupements sous forme d’un dendrogramme.
plot(trouvons_cluster_1, main="Dendrogramme CAH (Distance bray-curtis)")

Alors plus simplement !

Étape 1 : Vous avez des points à regrouper. Exemple :
- Point A
- Point B
- Point C


Étape 2 : Vous calculez les distances entre tous.

      | A | B | C |

|——-|—-|—-|—-|

A | 0 | 2 | 5 |
B | 2 | 0 | 3 |
C | 5 | 3 | 0 |

(Exemple : Distance entre A et B = 2, A et C = 5, etc.)


Étape 3 : Complete Linkage, c’est quoi ?

  • Quand vous fusionnez deux groupes, vous gardez la distance MAX entre leurs membres.
  • C’est comme dire :
    “Même si un seul membre est loin, on bloque la fusion !”

Exemple Concret : 1. Fusionne A et B (distance 2️).
Nouveau groupe : {A, B}.

  1. Calcule la distance entre {A,B} et C :
    • A ↔︎ C = 5
    • B ↔︎ C = 3
      Distance = 5 (le max !).
  2. Fusionne {A,B} avec C à la distance 5.

Résultat : - Les groupes sont compacts :
- {A,B} sont proches (distance 2).
- {A,B} et C sont fusionnés seulement à 5, car nous avons gardé la pire distance.

En Image :

          5 (max entre A-C et B-C)
          / \
        {A,B} C
         / \
        A   B (distance 2)
  • Même question pour la distance de Simpson
trouvons_cluster_2 <- hclust(as.dist(ma_matrice_dist_simpson), method = "complete" ) # "1*"
#hclust() : Applique un algorithme de classification hiérarchique ascendante (CAH) en utilisant les distances calculées.
trouvons_cluster_2
## 
## Call:
## hclust(d = as.dist(ma_matrice_dist_simpson), method = "complete")
## 
## Cluster method   : complete 
## Number of objects: 3
# Réprésentation dendrogramme
plot(trouvons_cluster_2, main="Dendrogramme CAH (Distance Simpson)")

  • Intérprétation

▶ Bray-Curtis donne une distance plus grande entre 1 et 2 (≈ 0.36), alors que Simpson les considère comme plus proches (≈ 0.15). La fusion finale avec l’objet 3 se fait à une hauteur légèrement plus faible avec Simpson (0.45 contre 0.48 avec Bray-Curtis). Simpson semble donner une structure plus compacte, où les éléments les plus similaires fusionnent à des distances plus faibles.

Bray-Curtis

  • Avantages :
    • Compare bien les proportions, même pour de petites différences.
    • Distingue nettement les ensembles proches.
  • Limites : De petites variations ou éléments rares peuvent exagérer les différences.

Simpson

  • Avantages :
    • Se concentre sur les éléments les plus nombreux, réduisant l’influence des rares.
    • Regroupe des ensembles aux tendances dominantes similaires.
  • Limites : Peut masquer des différences subtiles en négligeant les éléments rares.

En résumé :
- Bray-Curtis est idéale pour capter des détails fins.
- Simpson convient mieux quand on veut une vue globale en se concentrant sur l’essentiel.

Note à moi-même : l’exercice de la silde 91 n’a pas encore été fait

II- Algorithme des centres mobiles ou K-means clustering

Exercice 4 : Application de la méthode k-means clustering avec choix initales des centres (slide 125)

Pour cette exercice nous allons utiliser La base de données Iris : Un célèbre jeu de données étudié par le statisticien Fisher en 1936 est “les iris de Fisher”. Pour 3 variétés d’iris : Setosa, Versicolor, Virginica, et pour 150 iris par variété, on considère 4 caractères quantitatifs :

▶ X1 la longueur en cm d’un pétale.

▶ X2 la largeur en cm d’un pétale.

▶ X3 la longueur en cm d’un sépale.

▶ X4 la largeur en cm d’un sépale.

▶ Y le type de variétés à savoir setosa, versicolor, virginica.

Ce sont les variables explicatives X1, X2, X3 et X4. La variable à expliquer Y est une variable qualitative dont les modalités sont les variétés.

data <- iris

▶ Montrez un aperçu de la base (les 5 premiers lignes)

head(data)
##   Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 1          5.1         3.5          1.4         0.2  setosa
## 2          4.9         3.0          1.4         0.2  setosa
## 3          4.7         3.2          1.3         0.2  setosa
## 4          4.6         3.1          1.5         0.2  setosa
## 5          5.0         3.6          1.4         0.2  setosa
## 6          5.4         3.9          1.7         0.4  setosa
#View(date)  #Pour voir la table entière dans les yeux !

▶ Extraction de la sous base data des variables explicatives X1, X2, X3 et X4 uniquement.

names(data)
## [1] "Sepal.Length" "Sepal.Width"  "Petal.Length" "Petal.Width"  "Species"
Data = data%>%rename(X1 = "Sepal.Length", X2 = "Sepal.Width", X3 = "Petal.Length", X4 = "Petal.Width")%>%select("X1","X2","X3","X4")
# Nous renommons les colonne, par suite , on selectionne les colonnes qui nous intéressent

head(Data)
##    X1  X2  X3  X4
## 1 5.1 3.5 1.4 0.2
## 2 4.9 3.0 1.4 0.2
## 3 4.7 3.2 1.3 0.2
## 4 4.6 3.1 1.5 0.2
## 5 5.0 3.6 1.4 0.2
## 6 5.4 3.9 1.7 0.4

▶ Appliquons l’Algorithme du K-means Clustering avec 3 centres initiaux qui sont les individus correspondants aux lignes 15, 135 et 65 du jeu de données.

Note à moi-même : “explique un peu plus comment fonctionne cet algorithme”

centres_initiaux <- Data[c(15, 65, 135), ]
centres_initiaux
##      X1  X2  X3  X4
## 15  5.8 4.0 1.2 0.2
## 65  5.6 2.9 3.6 1.3
## 135 6.1 2.6 5.6 1.4
modele_kmeans <- kmeans(Data, centers = centres_initiaux, algorithm = "Lloyd")
# === Afficher les clusters ===
modele_kmeans$cluster
##   [1] 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
##  [38] 1 1 1 1 1 1 1 1 1 1 1 1 1 3 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
##  [75] 2 2 2 3 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 3 2 3 3 3 3 2 3 3 3 3
## [112] 3 3 2 2 3 3 3 3 2 3 2 3 2 3 3 2 2 3 3 3 3 3 2 3 3 3 3 2 3 3 3 2 3 3 3 2 3
## [149] 3 2

▶ Présentons le grahique clusplot des clusters formés.

# Ajouter les clusters au DataFrame normalisé
Data$Cluster <- as.factor(modele_kmeans$cluster) # as.factor() sert à convertir la variable kmeans$cluster en un attribut de Data

# Visualiser les résultats
ggplot(Data, aes(x = X1, y = X2, color = Cluster)) + geom_point(size = 2) + labs(title = "Clustering K-means sur les données iris", x = "X1", y = "X2") + theme_minimal()

Observation : les clusters 2 et 3 sont un peu melangés. L’approche avec “Lloyd” n’est pas l’approche idéale pour faire de belle segmentations.

Note à moi-même : continuer sur la notion d’imputation… \[FIN\]