Indice
Cluster Analysis
Tecniche gerarchiche e non gerarchiche
Le tecniche classiche di cluster analysis si dividono in due grandi categorie.
Le tecniche gerarchiche procedono per aggregazioni successive a partire dai singoli casi da aggegare ( $n$ gruppi di dimensione 1) per arrivare ad un unico gruppo di dimensioni $n$ (tecniche gerarchiche aggregative); oppure, al contrario, per scissioni successive partendo da un uico gruppo per arrivare a $n$ gruppi unitari (tecniche gerarchiche scissorie).
Le tecniche non gerarchiche (o a partizioni ripetute) conducono direttamente ad una partizione degli n casi in k gruppi, o seguendo una regola per il riallocamento dei casi, o ottimizzando la soluzione in relazione ad una funzione obiettivo.
Matrice delle distanze
Le tecniche gerarchiche si applicano alla matrice delle distanze. La funzione di base in R è:
dist(x, method = "euclidean", diag = FALSE, upper = FALSE, p = 2)
dist(USArrests)
## Alabama Alaska Arizona Arkansas ... ## Alaska 37.17701 ... ## Arizona 63.00833 46.59249 ... ## Arkansas 46.92814 77.19741 108.85192 ... ## California 55.52477 45.10222 23.19418 97.58202 ... ...
I metodi disponibili in questa funzione sono: "euclidean", "maximum", "manhattan", "canberra", "binary", "minkowski"
.
Ma esistono altre funzioni per il calcolo delle distanze.
Cluster gerarchica aggregativa
La funzione hclust()
produce una classificazione gerarchica a partire da una matrice delle distanze.
Applichiamo la funzione dist()
ai risultati ai risultati dell'ACP sul dataset USArrest.
PCA <- princomp(USArrests, cor = TRUE) df <- cbind(USArrests, PCA$scores)
Consideriamo, nel calcolare le distanze fra gli stati, solo le prime due componenti:
d <- dist(df[,5:6])
Utilizziamo il metodo di Ward:
res <- hclust(d, method = "ward")
I criteri utilizzabili sono: "ward.D", "ward.D2", "single", "complete", "average", "mcquitty", "median", "centroid"
La funzione hcut()
di factoextra può essere utilizzata direttamente con il dataframe originario, indicando le variabili:
# pacchetti library(factoextra) library(tidyverse) res <- hcut(df[,5:6], k = 4, hc_func = "hclust", hc_method = "ward") res
## Call: ## stats::hclust(d = x, method = hc_method) ## ## Cluster method : ward.D ## Distance : euclidean ## Number of objects: 50
La distanza utilizzata di default è quella euclidea, ma possono essere indicate anche altre misure: quelle della funzione dist()
e quelle basate sulla correlazione ("pearson", "spearman" or "kendall").
Possiamo anche scegliere il numero di cluster da formare (k = 4
). Il nome della funzione, infatti, fa riferimento al taglio dell'albero in $k$ cluster (hcut).
Il dendrogramma
Ai fini della scelta del numero ottimale di cluster, è utile studiare il dendrogramma.
res <- hcut(df[,5:6], k = 4, hc_func = "hclust", hc_method = "ward") res

Interpretazione
Il grafico dei risultati rappresenta --- rispetto alle variabili utilizzate, ovvero le prime due componenti dell'ACP --- i punti dei casi, e i cluster come aree colorate che li contengono:
fviz_cluster(res)

Aggiungiamo l'appartenenza dei casi ai cluster come nuova variabile del dataset:
df$cluster_1 <- res$cluster
Per analizzare ed interpretare i cluster, possiamo studiare la distribuzione della nuova variabile, e studiare le sue relazioni con le altre, ad esempio con le medie:
df %>% group_by(cluster_1) %>% summarise_all(mean)
## # A tibble: 4 x 9 ## cluster_1 Murder Assault UrbanPop Rape Comp.1 Comp.2 Comp.3 Comp.4 ## * <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> ## 1 1 14.1 253. 53.5 24.5 1.32 1.47 0.156 0.129 ## 2 2 11.1 264. 79.1 32.6 2.00 -0.501 -0.0849 -0.113 ## 3 3 6.35 142 70 19.5 -0.399 -0.444 0.0666 0.0677 ## 4 4 2.87 76.1 54.1 11.4 -2.08 0.182 -0.132 -0.0894
Nota | La funzione summarise_all() , del pacchetto dplyr (tidyverse) consente di applicare a tutte le variabili del dataset una funzione di sintesi (in questo caso mean() ). |
Cluster a centri mobili (k-means)
Consideriamo il caso della cluster intorno a centri mobili (k-means), e la funzione kmeans()
.
set.seed(691) res <-kmeans(scale(df[,5:6]), centers = 4)
Nota | Poiché la procedura di aggregazione dei cluster intorno ai centroidi è in parte random, può produrre risultati diversi e non replicabili. Per tale ragione, viene usato il comando set.seed() : ogni volta che si usa lo stesso seme (il numero indicato), si otterrà la stessa sequenza di numeri casuali (pseudocasuali), e dunque lo stesso risultato. |
Gli argomenti della funzione consentono di scegliere il numero dei centroidi (o casi da indicare come centroidi iniziali), il numero di iterazioni massime e l'algoritmo:
kmeans(x, centers, iter.max = 10, nstart = 1, algorithm = c("Hartigan-Wong", "Lloyd", "Forgy", "MacQueen"), trace=FALSE)
L'output produce le principali informazioni necessarie: numerosità dei cluster, i centroidi (medie), l'analisi della devianza:
res
## K-means clustering with 4 clusters of sizes 9, 12, 11, 18 ## ## Cluster means: ## Comp.1 Comp.2 ## 1 0.7290728 1.4253445 ## 2 1.1866898 -0.4791662 ## 3 -1.2074561 0.5908049 ## 4 -0.4177731 -0.7542756 ## ## Clustering vector: ## Alabama Alaska Arizona Arkansas California Colorado ## 1 1 2 1 2 2 ## Connecticut Delaware Florida Georgia Hawaii Idaho ## 4 4 2 1 4 3 ## Illinois Indiana Iowa Kansas Kentucky Louisiana ## 2 4 3 4 3 1 ## Maine Maryland ## 3 2 ## [ reached getOption("max.print") -- omitted 30 entries ] ## ## Within cluster sum of squares by cluster: ## [1] 3.877781 5.235565 5.074939 7.829937 ## (between_SS / total_SS = 77.5 %) ## ## Available components: ## ## [1] "cluster" "centers" "totss" "withinss" "tot.withinss" ## [6] "betweenss" "size" "iter" "ifault"
Per ottenere il grafico con la funzione fviz_cluster()
di factoextra, dobbiamo indicare il dataset originario (in quanto i valori delle variabili originarie non sono contenuti nei risultati):
fviz_cluster(res, USArrests)

Salviamo i risultati della cluster nel nostro dataset:
df$cluster_2 <- res$cluster
E confrontiamo le medie dei cluster:
df %>% group_by(cluster_2) %>% summarise_at(1:4, mean)
## # A tibble: 4 x 5 ## cluster_2 Murder Assault UrbanPop Rape ## * <int> <dbl> <dbl> <dbl> <dbl> ## 1 1 13.5 246. 53.1 24.0 ## 2 2 10.9 257. 78.3 32.2 ## 3 3 4 86.8 49.4 12.0 ## 4 4 5.18 127. 73.1 18.2
Nota | La funzione summarise_at() , sempre del pacchetto dplyr, consente di applicare ad alcune variabili del dataset (in questo caso 1:4 ) una funzione di sintesi (in questo caso mean() ). |
Script di esempio
- hclust.R
# PCA PCA <- princomp(USArrests, cor = TRUE) df <- cbind(USArrests, PCA$scores) # matrice delle distanze d <- dist(df[,5:6]) # con hclust res <- hclust(d, method = "ward", members = NULL) library(tidyverse) library(factoextra) # oppure con factoextra res <- hcut(df[,5:6], k = 4, hc_func = "hclust", hc_method = "ward") # dendrogramma plot(res) # variabili df$cluster_1 <- res$cluster # medie df %>% group_by(cluster_1) %>% summarise_all(mean) # grafico fviz_cluster(res)
- kmeans.R
# PCA PCA <- princomp(USArrests, cor = TRUE) df <- cbind(USArrests, PCA$scores) # kmeans set.seed(691) res <-kmeans(scale(df[,5:6]), centers = 4) res library(tidyverse) library(factoextra) # grafico fviz_cluster(res, USArrests) # variabili df$cluster_2 <- res$cluster # medie df %>% group_by(cluster_2) %>% summarise_all(mean)