Ricerca Sociale con R

Una wiki per l'analisi dei dati con R

Strumenti Utente

Strumenti Sito


Il Laboratorio di Analisi dei Dati con R, dell'Università di Teramo su piattaforma Meet, inizia il 9 aprile 2021 - Iscrizione - email
r:analisi_esplorativa:cluster_analysis

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
 |

Fig. 1: Dendrogramma e taglio delle partizioni

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)
 |

Fig. 2: Grafico dei cluster

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)
 |

Fig. 3: Grafico dei cluster

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)
 
r/analisi_esplorativa/cluster_analysis.txt · Ultima modifica: 26/09/2021 08:07 da admin