web-dev-qa-db-fra.com

Analyse de cluster en R: déterminer le nombre optimal de clusters

Étant un novice en R, je ne sais pas trop comment choisir le meilleur nombre de clusters pour effectuer une analyse en k-means. Après avoir tracé un sous-ensemble des données ci-dessous, combien de clusters seront appropriés? Comment puis-je effectuer une analyse de dendro de cluster?

n = 1000
kk = 10    
x1 = runif(kk)
y1 = runif(kk)
z1 = runif(kk)    
x4 = sample(x1,length(x1))
y4 = sample(y1,length(y1)) 
randObs <- function()
{
  ix = sample( 1:length(x4), 1 )
  iy = sample( 1:length(y4), 1 )
  rx = rnorm( 1, x4[ix], runif(1)/8 )
  ry = rnorm( 1, y4[ix], runif(1)/8 )
  return( c(rx,ry) )
}  
x = c()
y = c()
for ( k in 1:n )
{
  rPair  =  randObs()
  x  =  c( x, rPair[1] )
  y  =  c( y, rPair[2] )
}
z <- rnorm(n)
d <- data.frame( x, y, z )
411
user2153893

Si votre question est how can I determine how many clusters are appropriate for a kmeans analysis of my data?, voici quelques options. Le article de wikipedia sur la détermination du nombre de clusters présente une bonne critique de certaines de ces méthodes.

Premièrement, quelques données reproductibles (les données du Q ne sont pas claires pour moi):

n = 100
g = 6 
set.seed(g)
d <- data.frame(x = unlist(lapply(1:g, function(i) rnorm(n/g, runif(1)*i^2))), 
                y = unlist(lapply(1:g, function(i) rnorm(n/g, runif(1)*i^2))))
plot(d)

enter image description here

Un . Recherchez un pli ou un coude dans la somme du tracé d'éboulis d'erreur au carré (SSE). Voir http://www.statmethods.net/advstats/cluster.html & http://www.mattpeeples.net/kmeans.html pour plus d'informations. La position du coude dans la parcelle résultante suggère un nombre approprié de groupes pour les kméens:

mydata <- d
wss <- (nrow(mydata)-1)*sum(apply(mydata,2,var))
  for (i in 2:15) wss[i] <- sum(kmeans(mydata,
                                       centers=i)$withinss)
plot(1:15, wss, type="b", xlab="Number of Clusters",
     ylab="Within groups sum of squares")

Nous pourrions en conclure que 4 groupes seraient indiqués par cette méthode: enter image description here

Deux . Vous pouvez partitionner des medoids pour estimer le nombre de clusters à l’aide de la fonction pamk dans le package fpc.

library(fpc)
pamk.best <- pamk(d)
cat("number of clusters estimated by optimum average silhouette width:", pamk.best$nc, "\n")
plot(pam(d, pamk.best$nc))

enter image description hereenter image description here

# we could also do:
library(fpc)
asw <- numeric(20)
for (k in 2:20)
  asw[[k]] <- pam(d, k) $ silinfo $ avg.width
k.best <- which.max(asw)
cat("silhouette-optimal number of clusters:", k.best, "\n")
# still 4

Trois . Critère de Calinsky: Une autre approche pour diagnostiquer le nombre de grappes correspondant aux données. Dans ce cas, nous essayons 1 à 10 groupes.

require(vegan)
fit <- cascadeKM(scale(d, center = TRUE,  scale = TRUE), 1, 10, iter = 1000)
plot(fit, sortg = TRUE, grpmts.plot = TRUE)
calinski.best <- as.numeric(which.max(fit$results[2,]))
cat("Calinski criterion optimal number of clusters:", calinski.best, "\n")
# 5 clusters!

enter image description here

Quatre . Déterminer le modèle optimal et le nombre de grappes selon le critère d'information bayésien pour la maximisation des attentes, initialisé par la classification hiérarchique pour les modèles de mélange gaussiens paramétrés

# See http://www.jstatsoft.org/v18/i06/paper
# http://www.stat.washington.edu/research/reports/2006/tr504.pdf
#
library(mclust)
# Run the function to see how many clusters
# it finds to be optimal, set it to search for
# at least 1 model and up 20.
d_clust <- Mclust(as.matrix(d), G=1:20)
m.best <- dim(d_clust$z)[2]
cat("model-based optimal number of clusters:", m.best, "\n")
# 4 clusters
plot(d_clust)

enter image description hereenter image description hereenter image description here

Cinq . Clustering de propagation d'affinité (AP), voir http://dx.doi.org/10.1126/science.11368

library(apcluster)
d.apclus <- apcluster(negDistMat(r=2), d)
cat("affinity propogation optimal number of clusters:", length(d.apclus@clusters), "\n")
# 4
heatmap(d.apclus)
plot(d.apclus, d)

enter image description hereenter image description here

Six . Statistique d'écart pour l'estimation du nombre de grappes. Voir aussi n code pour une sortie graphique de Nice . Essayer 2 à 10 grappes ici:

library(cluster)
clusGap(d, kmeans, 10, B = 100, verbose = interactive())

Clustering k = 1,2,..., K.max (= 10): .. done
Bootstrapping, b = 1,2,..., B (= 100)  [one "." per sample]:
.................................................. 50 
.................................................. 100 
Clustering Gap statistic ["clusGap"].
B=100 simulated reference sets, k = 1..10
 --> Number of clusters (method 'firstSEmax', SE.factor=1): 4
          logW   E.logW        gap     SE.sim
 [1,] 5.991701 5.970454 -0.0212471 0.04388506
 [2,] 5.152666 5.367256  0.2145907 0.04057451
 [3,] 4.557779 5.069601  0.5118225 0.03215540
 [4,] 3.928959 4.880453  0.9514943 0.04630399
 [5,] 3.789319 4.766903  0.9775842 0.04826191
 [6,] 3.747539 4.670100  0.9225607 0.03898850
 [7,] 3.582373 4.590136  1.0077628 0.04892236
 [8,] 3.528791 4.509247  0.9804556 0.04701930
 [9,] 3.442481 4.433200  0.9907197 0.04935647
[10,] 3.445291 4.369232  0.9239414 0.05055486

Voici le résultat de la mise en œuvre par Edwin Chen de la statistique d'écart: enter image description here

Sept . Vous pouvez également trouver utile d'explorer vos données avec clustergrams pour visualiser l'attribution de cluster, voir http://www.r-statistics.com/2010/06/clustergram-visualization-and-diagnostics-for-cluster- analysis-r-code / pour plus de détails.

Huit . Le package NbClust fournit 30 indices pour déterminer le nombre de clusters dans un jeu de données.

library(NbClust)
nb <- NbClust(d, diss="NULL", distance = "euclidean", 
        min.nc=2, max.nc=15, method = "kmeans", 
        index = "alllong", alphaBeale = 0.1)
hist(nb$Best.nc[1,], breaks = max(na.omit(nb$Best.nc[1,])))
# Looks like 3 is the most frequently determined number of clusters
# and curiously, four clusters is not in the output at all!

enter image description here

Si votre question est how can I produce a dendrogram to visualize the results of my cluster analysis, vous devriez commencer par: http://www.statmethods.net/advstats/cluster.htmlhttp://www.r-tutor.com/gpu-computing/clustering/hierarchical-cluster-analysishttp://gastonsanchez.wordpress.com/2012/10/03/7-ways-to-plot-dendrograms-in-r/ Et voyez ici pour des méthodes plus exotiques: http://cran.r-project.org/web/views/Cluster.html

Voici quelques exemples:

d_dist <- dist(as.matrix(d))   # find distance matrix 
plot(hclust(d_dist))           # apply hirarchical clustering and plot

enter image description here

# a Bayesian clustering method, good for high-dimension data, more details:
# http://vahid.probstat.ca/paper/2012-bclust.pdf
install.packages("bclust")
library(bclust)
x <- as.matrix(d)
d.bclus <- bclust(x, transformed.par = c(0, -50, log(16), 0, 0, 0))
viplot(imp(d.bclus)$var); plot(d.bclus); ditplot(d.bclus)
dptplot(d.bclus, scale = 20, horizbar.plot = TRUE,varimp = imp(d.bclus)$var, horizbar.distance = 0, dendrogram.lwd = 2)
# I just include the dendrogram here

enter image description here

La bibliothèque pvclust calcule également les valeurs p pour la mise en grappe hiérarchique via le rééchantillonnage multi-échelons par bootstrap. Voici l'exemple de la documentation (ne fonctionnera pas sur des données aussi dimensionnelles que dans mon exemple):

library(pvclust)
library(MASS)
data(Boston)
boston.pv <- pvclust(Boston)
plot(boston.pv)

enter image description here

Est-ce que cela vous aide?

1001
Ben

Il est difficile d’ajouter une réponse aussi complexe. Bien que j'estime que nous devrions mentionner identify ici, en particulier parce que @Ben montre beaucoup d'exemples de dendrogrammes.

d_dist <- dist(as.matrix(d))   # find distance matrix 
plot(hclust(d_dist)) 
clusters <- identify(hclust(d_dist))

identify vous permet de choisir de manière interactive des clusters dans un dendrogramme et de stocker vos choix dans une liste. Appuyez sur Echap pour quitter le mode interactif et revenir à la console R. Notez que la liste contient les index, pas les noms de pages (par opposition à cutree).

19
Matt Bannert

Afin de déterminer le k-cluster optimal dans les méthodes de clustering. J'utilise habituellement la méthode Elbow accompagnée d'un traitement parallèle pour éviter la perte de temps. Ce code peut échantillonner comme ceci:

méthode du coude

elbow.k <- function(mydata){
dist.obj <- dist(mydata)
hclust.obj <- hclust(dist.obj)
css.obj <- css.hclust(dist.obj,hclust.obj)
elbow.obj <- elbow.batch(css.obj)
k <- elbow.obj$k
return(k)
}

coude courant parallèle

no_cores <- detectCores()
    cl<-makeCluster(no_cores)
    clusterEvalQ(cl, library(GMD))
    clusterExport(cl, list("data.clustering", "data.convert", "elbow.k", "clustering.kmeans"))
 start.time <- Sys.time()
 elbow.k.handle(data.clustering))
 k.clusters <- parSapply(cl, 1, function(x) elbow.k(data.clustering))
    end.time <- Sys.time()
    cat('Time to find k using Elbow method is',(end.time - start.time),'seconds with k value:', k.clusters)

Ça marche bien.

9
VanThaoNguyen

Ces méthodes sont excellentes mais lorsque vous essayez de trouver k pour des ensembles de données beaucoup plus volumineux, ceux-ci peuvent être très lents dans R.

Une bonne solution que j'ai trouvée est le paquet "RWeka", qui a une implémentation efficace de l'algorithme X-Means - une version étendue de K-Means qui s'adapte mieux et déterminera le nombre optimal de clusters pour vous.

Tout d'abord, vous devez vous assurer que Weka est installé sur votre système et que XMeans est installé via le gestionnaire de paquets de Weka.

library(RWeka)

# Print a list of available options for the X-Means algorithm
WOW("XMeans")

# Create a Weka_control object which will specify our parameters
weka_ctrl <- Weka_control(
    I = 1000,                          # max no. of overall iterations
    M = 1000,                          # max no. of iterations in the kMeans loop
    L = 20,                            # min no. of clusters
    H = 150,                           # max no. of clusters
    D = "weka.core.EuclideanDistance", # distance metric Euclidean
    C = 0.4,                           # cutoff factor ???
    S = 12                             # random number seed (for reproducibility)
)

# Run the algorithm on your data, d
x_means <- XMeans(d, control = weka_ctrl)

# Assign cluster IDs to original data set
d$xmeans.cluster <- x_means$class_ids
5
RDRR

Splendide réponse de Ben. Cependant, je suis surpris que la méthode de propagation par affinité (AP) ait été suggérée ici uniquement pour trouver le numéro de cluster de la méthode k-means, où AP effectue en général un meilleur travail de regroupement des données. Veuillez consulter l'article scientifique soutenant cette méthode dans Science ici:

Frey, Brendan J. et Delbert Dueck. "Clustering en transmettant des messages entre des points de données." Science 315.5814 (2007): 972-976.

Donc, si vous n'êtes pas biaisé vers k-means, je suggère d'utiliser AP directement, ce qui permettra de regrouper les données sans qu'il soit nécessaire de connaître le nombre de clusters:

library(apcluster)
apclus = apcluster(negDistMat(r=2), data)
show(apclus)

Si les distances euclidiennes négatives ne sont pas appropriées, vous pouvez utiliser une autre mesure de similarité fournie dans le même package. Par exemple, pour les similitudes basées sur les corrélations de Spearman, voici ce dont vous avez besoin:

sim = corSimMat(data, method="spearman")
apclus = apcluster(s=sim)

Veuillez noter que ces fonctions pour les similitudes dans le package AP sont simplement fournies pour des raisons de simplicité. En fait, la fonction apcluster () dans R acceptera toute matrice de corrélations. La même chose avant avec corSimMat () peut être fait avec ceci:

sim = cor(data, method="spearman")

ou

sim = cor(t(data), method="spearman")

en fonction de ce que vous voulez regrouper sur votre matrice (lignes ou colonnes).

5
zsram

Une solution simple est la bibliothèque factoextra. Vous pouvez modifier la méthode de clustering et la méthode permettant de calculer le meilleur nombre de groupes. Par exemple, si vous voulez connaître le meilleur nombre de grappes pour un k- signifie:

Données: mtcars

library(factoextra)   
fviz_nbclust(mtcars, kmeans, method = "wss") +
      geom_vline(xintercept = 3, linetype = 2)+
      labs(subtitle = "Elbow method")

Enfin, nous obtenons un graphique comme:

enter image description here

2
Cro-Magnon

Les réponses sont géniales. Si vous souhaitez donner une chance à une autre méthode de clustering, vous pouvez utiliser le clustering hiérarchique et voir comment les données sont fractionnées.

> set.seed(2)
> x=matrix(rnorm(50*2), ncol=2)
> hc.complete = hclust(dist(x), method="complete")
> plot(hc.complete)

enter image description here

En fonction du nombre de classes dont vous avez besoin, vous pouvez découper votre dendrogramme comme suit:

> cutree(hc.complete,k = 2)
 [1] 1 1 1 2 1 1 1 1 1 1 1 1 1 2 1 2 1 1 1 1 1 2 1 1 1
[26] 2 1 1 1 1 1 1 1 1 1 1 2 2 1 1 1 2 1 1 1 1 1 1 1 2

Si vous tapez ?cutree, vous verrez les définitions. Si votre ensemble de données comporte trois classes, il s'agira simplement de cutree(hc.complete, k = 3). L'équivalent pour cutree(hc.complete,k = 2) est cutree(hc.complete,h = 4.9).

1
boyaronur