\[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)
# 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, 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…
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 !
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.
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…
# === 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
# === 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
# === 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).
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},
\] où \(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) :
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\).
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).
\]
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.
Nous avons montré que la distance euclidienne satisfait les trois propriétés suivantes :
Subséquemment, la distance euclidienne est bien une distance au sens mathématique.
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
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| \]
\[d(x, y) = \sum_{i=1}^{m} |x_i - y_i| = \sum_{i=1}^{m} |y_i - x_i| = d(y, x)\]
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|\).
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)
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| \]
\[ D_2(x, y) = \left( \sum_{i=1}^{n} (x_i - y_i)^2 \right)^{1/2} \]
\[ 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
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.
# 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
# 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
▶ 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..
#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.
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)
}
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)
}
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_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
\(\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\).
\(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\).
\(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)\).
\(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\).
\(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}+\)
\(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.
La relation entre les inerties s’écrit ainsi : \[ I_{\text{tot}} = I_{\text{intra}} + I_{\text{inter}} \]
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.
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.
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.
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.
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\]
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)
}
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].
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)
}
# 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.
3- Ecarts
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
#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.
#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.
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
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.
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.
|——-|—-|—-|—-|
(Exemple : Distance entre A et B = 2, A et C = 5, etc.)
Exemple Concret : 1. Fusionne A et
B (distance 2️).
Nouveau groupe : {A, B}.
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)
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)")
▶ 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
Simpson
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
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\]
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.