# K-moyennes
<!-- paragraph -->
```{r setup, echo=FALSE}
knitr::opts_chunk$set(fig.path="ch17-figures/")
```
<!-- paragraph -->
Dans ce chapitre, nous explorerons plusieurs visualisations de l’agrégation (clustering) par K-moyennes, un algorithme d’apprentissage non supervisé.
<!-- paragraph -->
Plan du chapitre :
<!-- paragraph -->
- Nous commençons par visualiser deux caractéristiques des données Iris.
<!-- comment -->
- Nous choisissons de manière aléatoire K= 3 points de données à utiliser comme centres d’agrégation.
<!-- comment -->
- Nous expliquons comment calculer et visualiser la distance entre les points de données et les centres d’agrégation.
<!-- comment -->
- Nous terminons par une visualisation de l’évolution des paramètres du modèle K-moyennes à chaque itération.
<!-- paragraph -->
## Visualisation des données Iris avec des étiquettes {#vis-iris}
<!-- paragraph -->
Nous commençons par une visualisation typique des données de l’iris, comprenant une légende de couleurs pour les espèces.
<!-- paragraph -->
```{r}
library(animint2)
color.code <- c(
setosa="#1B9E77",
versicolor="#D95F02",
virginica="#7570B3",
"1"="#E7298A",
"2"="#66A61E",
"3"="#E6AB02",
"4"="#A6761D")
ggplot()+
scale_color_manual(values=color.code)+
geom_point(aes(
Petal.Length, Petal.Width, color=Species),
data=iris)+
coord_equal()
```
<!-- paragraph -->
Nous allons illustrer l’algorithme d’agrégation K-moyennes à l’aide de deux dimensions.
<!-- paragraph -->
```{r, results=TRUE}
data.mat <- as.matrix(iris[,c("Petal.Width","Petal.Length")])
head(data.mat)
str(data.mat)
```
<!-- paragraph -->
Pour exécuter K-moyennes, l’hyperparamètre du nombre d’agrégations (K) doit être fixé à l’avance.
<!-- comment -->
Ensuite, les K-points de données aléatoires sont sélectionnés comme centres d’agrégation initiaux.
<!-- paragraph -->
```{r}
K <- 3
library(data.table)
data.dt <- data.table(data.mat)
set.seed(3)
centers.dt <- data.dt[sample(1:.N, K)]
(centers.mat <- as.matrix(centers.dt))
centers.dt[, cluster := factor(1:K)]
centers.dt
gg.centers <- ggplot()+
scale_color_manual(values=color.code)+
geom_point(aes(
Petal.Length, Petal.Width),
color="grey50",
data=data.dt)+
geom_point(aes(
Petal.Length, Petal.Width, color=cluster),
data=centers.dt)+
coord_equal()
gg.centers
```
<!-- paragraph -->
Ci-dessus, nous avons affiché les deux ensembles de données (centres d’agrégation et données) à l’aide de deux `geom_point()`.
<!-- comment -->
Nous calculons ci-dessous la distance entre chaque point de données et chaque centre d’agrégation :
<!-- paragraph -->
```{r}
pairs.dt <- data.table(expand.grid(
centers.i=1:nrow(centers.mat),
data.i=1:nrow(data.mat)))
```
<!-- paragraph -->
Ces éléments peuvent être visualisés à l’aide d’un `geom_point()`.
<!-- paragraph -->
```{r}
seg.dt <- pairs.dt[, data.table(
data.i,
data=data.mat[data.i,],
center=centers.mat[centers.i,])]
gg.centers+
geom_segment(aes(
data.Petal.Length, data.Petal.Width,
xend=center.Petal.Length, yend=center.Petal.Width),
size=1,
data=seg.dt)
```
<!-- paragraph -->
Il y a `r nrow(seg.dt)` segments superposés ci-dessus, si bien que l’interactivité serait utile pour mettre en évidence les segments connectés à un point de données précis.
<!-- comment -->
À cet effet, nous créons ci-dessous une variable de sélection `data.i` :
<!-- paragraph -->
```{r ch17-kmeans-distances}
animint(
ggplot()+
theme_bw()+
theme_animint(height=300, width=640)+
scale_color_manual(values=color.code)+
scale_x_continuous(breaks=seq(1,7,by=0.5))+
scale_y_continuous(breaks=seq(0, 2.5, by=0.5))+
geom_point(aes(
Petal.Length, Petal.Width, color=cluster),
size=4,
data=centers.dt)+
geom_segment(aes(
data.Petal.Length, data.Petal.Width,
xend=center.Petal.Length, yend=center.Petal.Width),
size=1,
showSelected="data.i",
data=seg.dt)+
geom_point(aes(
Petal.Length, Petal.Width),
clickSelects="data.i",
size=2,
color="grey50",
data=data.table(data.mat, data.i=1:nrow(data.mat))))
```
<!-- paragraph -->
Dans la visualisation des données ci-dessus, vous pouvez cliquer sur un point de données pour afficher les distances entre ce point et chaque centre d’agrégation.
<!-- paragraph -->
Exercices pour cette section :
<!-- paragraph -->
- Modifiez les échelles x/y de façon à ce que les mêmes graduations soient représentées.
<!-- comment -->
- Modifiez la couleur de chaque segment pour qu’elle soit la même que l’agrégation correspondante.
<!-- comment -->
- Ajoutez une infobulle qui indique la valeur de la distance.
<!-- comment -->
- Faites varier la largeur du segment en fonction de son optimalité (le segment connecté au centre de l’agrégation la plus proche devrait être mis en évidence par une largeur plus importante).
<!-- paragraph -->
## Visualisation des itérations de l’algorithme {#vis-iterations}
<!-- paragraph -->
Nous calculons le centre d’agrégation le plus proche pour chaque point de données.
<!-- paragraph -->
```{r}
pairs.dt[, error := rowSums(
(data.mat[data.i,]-centers.mat[centers.i,])^2)]
(closest.dt <- pairs.dt[, .SD[which.min(error)], by=data.i])
(closest.data <- closest.dt[, .(
data.dt[data.i],
cluster=factor(centers.i)
)])
(both.dt <- rbind(
data.table(type="centers", centers.dt),
data.table(type="data", closest.data)))
ggplot()+
scale_fill_manual(values=color.code)+
scale_color_manual(values=c(centers="black", data="grey"))+
scale_size_manual(values=c(centers=5, data=3))+
geom_point(aes(
Petal.Length, Petal.Width, fill=cluster, size=type, color=type),
data=both.dt)+
coord_equal()+
theme_bw()
```
<!-- paragraph -->
Ensuite, nous mettons à jour les centres d’agrégation.
<!-- paragraph -->
```{r}
new.centers <- closest.dt[, data.table(
t(colMeans(data.dt[data.i]))
), by=.(cluster=centers.i)]
(new.both <- rbind(
data.table(type="centers", new.centers),
data.table(type="data", closest.data)))
ggplot()+
scale_fill_manual(values=color.code)+
scale_color_manual(values=c(centers="black", data="grey"))+
scale_size_manual(values=c(centers=5, data=3))+
geom_point(aes(
Petal.Length, Petal.Width, fill=cluster, size=type, color=type),
data=new.both)+
coord_equal()+
theme_bw()
```
<!-- paragraph -->
Les visualisations ci-dessus illustrent les étapes de la méthode K-moyennes : (1) mise à jour de l’agrégation sur la base du centre le plus proche (2) mise à jour du centre à partir des données affectées à cette agrégation.
<!-- comment -->
Pour visualiser plusieurs itérations des deux étapes ci-dessus, nous utilisons une boucle for.
<!-- paragraph -->
```{r}
set.seed(3)
centers.dt <- data.dt[sample(1:.N, K)]
(centers.mat <- as.matrix(centers.dt))
data.and.centers.list <- list()
iteration.error.list <- list()
for(iteration in 1:20){
pairs.dt[, error := {
rowSums((data.mat[data.i,]-centers.mat[centers.i,])^2)
}]
closest.dt <- pairs.dt[, .SD[which.min(error)], by=data.i]
iteration.error.list[[iteration]] <- data.table(
iteration, error=sum(closest.dt[["error"]]))
iteration.both <- rbind(
data.table(type="centers", centers.dt, cluster=1:K),
closest.dt[, data.table(
type="data", data.dt[data.i], cluster=factor(centers.i))])
data.and.centers.list[[iteration]] <- data.table(
iteration, iteration.both)
new.centers <- closest.dt[, data.table(
t(colMeans(data.dt[data.i]))
), keyby=.(cluster=centers.i)]
centers.dt <- new.centers[, names(centers.dt), with=FALSE]
centers.mat <- as.matrix(centers.dt)
}
(data.and.centers <- do.call(rbind, data.and.centers.list))
(iteration.error <- do.call(rbind, iteration.error.list))
```
<!-- paragraph -->
Nous créons d’abord un graphique d’ensemble avec une courbe d’erreur pour sélectionner la taille du modèle.
<!-- paragraph -->
```{r}
gg.err <- ggplot()+
theme_bw()+
geom_point(aes(
iteration, error),
data=iteration.error)+
make_tallrect(iteration.error, "iteration", alpha=0.3)
```
<!-- paragraph -->
Nous créons également un graphique montrant l’itération en cours.
<!-- paragraph -->
```{r}
gg.iteration <- ggplot()+
scale_fill_manual(values=color.code)+
scale_color_manual(values=c(centers="black", data=NA))+
scale_size_manual(values=c(centers=5, data=2))+
geom_point(aes(
Petal.Length, Petal.Width, fill=cluster, size=type, color=type),
showSelected="iteration",
data=data.and.centers)+
coord_equal()+
theme_bw()
gg.iteration
```
<!-- paragraph -->
La combinaison des deux graphiques produit une visualisation interactive.
<!-- paragraph -->
```{r ch17-kmeans-iterations}
animint(gg.err, gg.iteration)
```
<!-- paragraph -->
## Résumé du chapitre et exercices {#ch17-exercises}
<!-- paragraph -->
Exercices :
<!-- paragraph -->
- Faites en sorte que les centres apparaissent toujours au premier plan (au-dessus des données).
<!-- comment -->
- Ajoutez des transitions fluides.
<!-- comment -->
- Animez la variable d’itération.
<!-- comment -->
- Le code actuel impose un nombre maximal d’itérations, il est donc possible que les dernières ne progressent pas.
<!-- comment -->
Par exemple, l’itération 16 est la dernière à réduire l’erreur (les itérations 17 à 20 n’entraînent aucune diminution).
<!-- comment -->
Modifiez le code pour arrêter l’itération en absence de diminution de l’erreur.
<!-- comment -->
- La visualisation actuelle n’a qu’un cadre d’animation (sous-ensemble `showSelected`) par itération (la moyenne est affichée avant sa mise à jour).
<!-- comment -->
Ajoutez un autre cadre d’animation qui montre la moyenne après la mise à jour.
<!-- comment -->
- Ajoutez des segments interactifs qui montrent la distance entre chaque point de données et chaque centre d’agrégation (comme dans le premier animint de cette page).
<!-- comment -->
- Ajoutez les fonctionnalités décrites dans les exercices de la section précédente.
<!-- comment -->
- Calculez les résultats pour différentes graines aléatoires, puis affichez les taux d’erreur correspondants sur le graphique d’aperçu des erreurs. Permettez ensuite à l’utilisateur de sélectionner n’importe lequel de ces résultats.
<!-- comment -->
- Calculez les résultats pour plusieurs nombres d’agrégations (K).
<!-- comment -->
Calculez l'indice de Rand ajusté en utilisant `pdfCluster::adj.rand.index(species, cluster)` pour chaque K et graine aléatoire.
<!-- comment -->
Ajoutez un graphique d’ensemble qui montre la valeur ARI de chaque modèle et autorise la sélection du nombre d’agrégations.
<!-- comment -->
- Créez une visualisation similaire d’un autre ensemble de données tel que `data("penguins", package="palmerpenguins")`.
<!-- paragraph -->
Dans le [chapitre 18](/ch18), nous vous expliquerons comment visualiser l’algorithme d’apprentissage par descente de gradient pour l’apprentissage des réseaux neuronaux.
<!-- paragraph -->