web-dev-qa-db-fra.com

Comment puis-je déterminer k lorsque j'utilise un clustering k-means?

J'ai étudié le clustering k-means , et une chose qui n'est pas claire, c'est comment vous choisissez la valeur de k. Est-ce juste une question d'essais et d'erreurs, ou y a-t-il autre chose?

134
Jason Baker

Vous pouvez maximiser le critère d'information bayésien (BIC):

BIC(C | X) = L(X | C) - (p / 2) * log n

L(X | C) est la log-vraisemblance de l'ensemble de données X selon le modèle C, p est le nombre de paramètres du modèle C et n est le nombre de points de l'ensemble de données . Voir "X-signifie: extension K-moyenne avec estimation efficace du nombre de grappes " par Dan Pelleg et Andrew Moore dans ICML 2000.

Une autre approche consiste à commencer avec une valeur élevée pour k et à continuer à supprimer les centroïdes (en réduisant k) jusqu'à ce que la longueur de description ne soit plus réduite. Voir "Principe MDL pour la quantification vectorielle robuste" par Horst Bischof, Ales Leonardis et Alexander Selb dans Pattern Analysis and Applications vol. 2, p. 59 à 72, 1999.

Enfin, vous pouvez commencer avec un cluster, puis diviser les clusters jusqu'à ce que les points attribués à chaque cluster aient une distribution gaussienne. Dans "Apprendre le k dans k -means" (NIPS 2003), Greg Hamerly et Charles Elkan montrent que cela fonctionne mieux que BIC et que BIC ne pénalise pas. la complexité du modèle assez fortement.

136
Vebjorn Ljosa

En gros, vous voulez trouver un équilibre entre deux variables: le nombre de grappes ( k ) et la variance moyenne des grappes. Vous voulez minimiser le premier tout en minimisant le dernier. Bien entendu, lorsque le nombre de grappes augmente, la variance moyenne diminue (jusqu'au cas trivial de k = n et de la variance = 0).

Comme toujours dans l'analyse des données, il n'y a pas une seule approche vraie qui fonctionne mieux que toutes les autres dans tous les cas. En fin de compte, vous devez utiliser votre propre jugement. Pour cela, il est utile de tracer le nombre de clusters par rapport à la variance moyenne (ce qui suppose que vous avez déjà exécuté l'algorithme pour plusieurs valeurs de k ). Ensuite, vous pouvez utiliser le nombre de grappes au genou de la courbe.

36
Jan Krüger

Oui, vous pouvez trouver le meilleur nombre de grappes à l’aide de la méthode Elbow, mais j’ai trouvé difficile de trouver la valeur des grappes à partir du graphe elbow à l’aide de script. Vous pouvez observer le graphe du coude et trouver le point du coude vous-même, mais il a fallu beaucoup de travail pour le trouver à partir d'un script.

Donc, une autre option consiste à utiliser Méthode Silhouette pour le trouver. Le résultat de Silhouette est totalement conforme au résultat de la méthode Elbow dans R. 

Voici ce que j'ai fait.

#Dataset for Clustering
n = 150
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))))
mydata<-d
#Plot 3X2 plots
attach(mtcars)
par(mfrow=c(3,2))

#Plot the original dataset
plot(mydata$x,mydata$y,main="Original Dataset")

#Scree plot to deterine the number of clusters
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")

# Ward Hierarchical Clustering
d <- dist(mydata, method = "euclidean") # distance matrix
fit <- hclust(d, method="ward") 
plot(fit) # display dendogram
groups <- cutree(fit, k=5) # cut tree into 5 clusters
# draw dendogram with red borders around the 5 clusters 
rect.hclust(fit, k=5, border="red")

#Silhouette analysis for determining the number of clusters
library(fpc)
asw <- numeric(20)
for (k in 2:20)
  asw[[k]] <- pam(mydata, k) $ silinfo $ avg.width
k.best <- which.max(asw)

cat("silhouette-optimal number of clusters:", k.best, "\n")
plot(pam(d, k.best))

# K-Means Cluster Analysis
fit <- kmeans(mydata,k.best)
mydata 
# get cluster means 
aggregate(mydata,by=list(fit$cluster),FUN=mean)
# append cluster assignment
mydata <- data.frame(mydata, clusterid=fit$cluster)
plot(mydata$x,mydata$y, col = fit$cluster, main="K-means Clustering results")

J'espère que ça aide!!

23
Udeep Shakya

Peut-être quelqu'un de débutant comme moi qui cherche un exemple de code. Les informations pour silhouette_score sont disponibles ici.

from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score

range_n_clusters = [2, 3, 4]            # clusters range you want to select
dataToFit = [[12,23],[112,46],[45,23]]  # sample data
best_clusters = 0                       # best cluster number which you will get
previous_silh_avg = 0.0

for n_clusters in range_n_clusters:
    clusterer = KMeans(n_clusters=n_clusters)
    cluster_labels = clusterer.fit_predict(dataToFit)
    silhouette_avg = silhouette_score(dataToFit, cluster_labels)
    if silhouette_avg > previous_silh_avg:
        previous_silh_avg = silhouette_avg
        best_clusters = n_clusters

# Final Kmeans for best_clusters
kmeans = KMeans(n_clusters=best_clusters, random_state=0).fit(dataToFit)
7
bhargav patel

Regardez ceci papier, "Apprendre le k dans k-signifie" de Greg Hamerly, Charles Elkan. Il utilise un test gaussien pour déterminer le bon nombre de grappes. En outre, les auteurs affirment que cette méthode est meilleure que BIC, qui est mentionnée dans la réponse acceptée.

7

Il y a quelque chose appelé la règle du pouce. Il est dit que le nombre de clusters peut être calculé par k = (n/2) ^ 0,5, où n est le nombre total d'éléments de votre échantillon . Vous pouvez vérifier la véracité de cette information sur le papier suivant. :

http://www.ijarcsms.com/docs/paper/volume1/issue6/V1I6-0015.pdf

Il existe également une autre méthode appelée G-means, dans laquelle votre distribution suit une distribution gaussienne, ou distribution normale… .. Elle consiste à augmenter k jusqu'à ce que tous vos k groupes suivent une distribution gaussienne…. mais peut être fait . Voici la source:

http://papers.nips.cc/paper/2526-learning-the-k-in-k-means.pdf

J'espère que ça aide!

4
Arthur Busqueiro

Commencez par créer un minimum Spanning Tree de vos données . La suppression des arêtes les plus chères du K-1 divise l’arbre en K groupes,
afin de pouvoir construire le MST une fois, examinez les espacements/métriques de cluster pour divers K, et prenez le coude de la courbe. 

Cela ne fonctionne que pour Single-linkage_clustering , Mais pour cela, c'est rapide et facile. De plus, les MST créent de bons visuels.
Voir par exemple le graphique MST sous logiciel de visualisation stats.stackexchange pour la mise en cluster .

3
denis

Si vous utilisez MATLAB, quelle que soit la version depuis 2013b, vous pouvez utiliser la fonction evalclusters pour déterminer le type optimal k pour un ensemble de données donné. 

Cette fonction vous permet de choisir parmi 3 algorithmes de clustering: kmeans, linkage et gmdistribution.

Il vous permet également de choisir parmi 4 critères d’évaluation de la classification - CalinskiHarabasz, DaviesBouldin, gap et silhouette.

3
Kristada673

Je suis surpris que personne n'ait mentionné cet excellent article: http://www.ee.columbia.edu/~dpwe/papers/PhamDN05-kmeans.pdf

Après avoir suivi plusieurs autres suggestions, je suis finalement tombé sur cet article en lisant ce blog: https://datasciencelab.wordpress.com/2014/01/21/selection-of-k-in-k-means- clustering-reloaded /

Après cela, je l'ai implémenté dans Scala, une implémentation qui, pour mes cas d'utilisation, donne de très bons résultats. Voici le code:

import breeze.linalg.DenseVector
import Kmeans.{Features, _}
import nak.cluster.{Kmeans => NakKmeans}

import scala.collection.immutable.IndexedSeq
import scala.collection.mutable.ListBuffer

/*
https://datasciencelab.wordpress.com/2014/01/21/selection-of-k-in-k-means-clustering-reloaded/
 */
class Kmeans(features: Features) {
  def fkAlphaDispersionCentroids(k: Int, dispersionOfKMinus1: Double = 0d, alphaOfKMinus1: Double = 1d): (Double, Double, Double, Features) = {
    if (1 == k || 0d == dispersionOfKMinus1) (1d, 1d, 1d, Vector.empty)
    else {
      val featureDimensions = features.headOption.map(_.size).getOrElse(1)
      val (dispersion, centroids: Features) = new NakKmeans[DenseVector[Double]](features).run(k)
      val alpha =
        if (2 == k) 1d - 3d / (4d * featureDimensions)
        else alphaOfKMinus1 + (1d - alphaOfKMinus1) / 6d
      val fk = dispersion / (alpha * dispersionOfKMinus1)
      (fk, alpha, dispersion, centroids)
    }
  }

  def fks(maxK: Int = maxK): List[(Double, Double, Double, Features)] = {
    val fadcs = ListBuffer[(Double, Double, Double, Features)](fkAlphaDispersionCentroids(1))
    var k = 2
    while (k <= maxK) {
      val (fk, alpha, dispersion, features) = fadcs(k - 2)
      fadcs += fkAlphaDispersionCentroids(k, dispersion, alpha)
      k += 1
    }
    fadcs.toList
  }

  def detK: (Double, Features) = {
    val vals = fks().minBy(_._1)
    (vals._3, vals._4)
  }
}

object Kmeans {
  val maxK = 10
  type Features = IndexedSeq[DenseVector[Double]]
}
2
eirirlar

Mon idée est d'utiliser Coefficient de silhouette pour trouver le numéro de cluster optimal (K). Les explications détaillées sont ici .

1
qmaruf

Une solution possible consiste à utiliser un algorithme méta-heuristique, tel que l'algorithme génétique, pour trouver k . C'est simple. vous pouvez utiliser K aléatoire (dans certaines limites) et évaluer la fonction d’ajustement de l’algorithme génétique avec des mesures telles que Silhouette

https://en.wikipedia.org/wiki/Silhouette_(clustering)

1
Masoud

Une autre approche consiste à utiliser des cartes auto-organisées (SOP) pour trouver le nombre optimal de clusters. La carte SOM (Self-Organizing Map) est une méthodologie de réseau neuralnetwork, qui nécessite uniquement l'entrée. Elle est utilisée pour la classification Pour la résolution de problèmes. Cette approche est utilisée dans un article sur la segmentation de la clientèle. 

La référence du papier est 

Abdellah Amine et al., Modèle de segmentation de la clientèle dans le commerce électronique en utilisant Techniques de clustering et modèle LRFM: le cas Des magasins en ligne au Maroc, Académie mondiale des sciences, de l’ingénierie et de la technologie. Ingénierie informatique et de l'information Vol: 9, No: 8, 2015, 1999 - 2010

1
boyaronur
km=[]
for i in range(num_data.shape[1]):
    kmeans = KMeans(n_clusters=ncluster[i])#we take number of cluster bandwidth theory
    ndata=num_data[[i]].dropna()
    ndata['labels']=kmeans.fit_predict(ndata.values)
    cluster=ndata
    co=cluster.groupby(['labels'])[cluster.columns[0]].count()#count for frequency
    me=cluster.groupby(['labels'])[cluster.columns[0]].median()#median
    ma=cluster.groupby(['labels'])[cluster.columns[0]].max()#Maximum
    mi=cluster.groupby(['labels'])[cluster.columns[0]].min()#Minimum
    stat=pd.concat([mi,ma,me,co],axis=1)#Add all column
    stat['variable']=stat.columns[1]#Column name change
    stat.columns=['Minimum','Maximum','Median','count','variable']
    l=[]
    for j in range(ncluster[i]):
        n=[mi.loc[j],ma.loc[j]] 
        l.append(n)

    stat['Class']=l
    stat=stat.sort(['Minimum'])
    stat=stat[['variable','Class','Minimum','Maximum','Median','count']]
    if missing_num.iloc[i]>0:
        stat.loc[ncluster[i]]=0
        if stat.iloc[ncluster[i],5]==0:
            stat.iloc[ncluster[i],5]=missing_num.iloc[i]
            stat.iloc[ncluster[i],0]=stat.iloc[0,0]
    stat['Percentage']=(stat[[5]])*100/count_row#Freq PERCENTAGE
    stat['Cumulative Percentage']=stat['Percentage'].cumsum()
    km.append(stat)
cluster=pd.concat(km,axis=0)## see documentation for more info
cluster=cluster.round({'Minimum': 2, 'Maximum': 2,'Median':2,'Percentage':2,'Cumulative Percentage':2})
1
sumit

En supposant que vous ayez une matrice de données appelée DATA, vous pouvez effectuer un partitionnement autour de médoïdes avec une estimation du nombre de clusters (par analyse de silhouette) comme ceci:

library(fpc)
maxk <- 20  # arbitrary here, you can set this to whatever you like
estimatedK <- pamk(dist(DATA), krange=1:maxk)$nc
1
Megatron

Si vous ne connaissez pas les nombres des grappes que k doit fournir comme paramètre à k-means, vous avez quatre possibilités pour le trouver automatiquement:

  • Algorithme de G-means: il découvre automatiquement le nombre de clusters en utilisant un test statistique pour décider de scinder ou non un centre de k-means en deux. Cet algorithme utilise une approche hiérarchique pour détecter le nombre de clusters, basé sur un test statistique pour l'hypothèse qu'un sous-ensemble de données suit une distribution gaussienne (fonction continue qui se rapproche de la distribution binomiale exacte des événements), et sinon il divise le cluster. . Il commence avec un petit nombre de centres, disons un seul cluster (k = 1), puis l’algorithme le divise en deux centres (k = 2) et divise à nouveau chacun de ces deux centres (k = 4). total. Si G-moyennes n'accepte pas ces quatre centres, la réponse est l'étape précédente: deux centres dans ce cas (k = 2). C'est le nombre de clusters dans lesquels votre jeu de données sera divisé. G-means est très utile lorsque vous ne disposez pas d'une estimation du nombre de clusters que vous obtiendrez après le regroupement de vos instances. Notez qu'un choix peu pratique pour le paramètre "k" peut vous donner des résultats erronés. La version parallèle de g-means est appelée p-means . G-signifie sources: source 1source 2source 3

  • x-means : un nouvel algorithme qui parcourt efficacement l'espace des emplacements de cluster et le nombre de clusters pour optimiser le critère d'information bayésien (BIC) ou la mesure de critère d'information d'Akaike (AIC). Cette version de k-means trouve le nombre k et accélère également k-means.

  • K-means en ligne ou k-means en streaming: permet d'exécuter k-means en parcourant une fois les données complètes et en recherchant automatiquement le nombre optimal de k. Spark le met en œuvre.

  • Algorithme MeanShift : il s’agit d’une technique de classification non paramétrique qui ne nécessite pas de connaissance préalable du nombre de grappes et ne contraint pas la forme des grappes. Le clustering de décalage moyen vise à découvrir des "blobs" dans une densité lisse d'échantillons. C'est un algorithme basé sur le centroïde, qui fonctionne en mettant à jour les candidats pour que les centroïdes soient la moyenne des points dans une région donnée. Ces candidats sont ensuite filtrés dans une étape de post-traitement pour éliminer les quasi-doublons afin de former le jeu final de centroïdes. Sources: source1 , source2 , source3

0
nabiltos

Bonjour, je vais expliquer les choses simplement et simplement. J'aime déterminer les clusters à l'aide de la bibliothèque 'NbClust'.

Maintenant, comment utiliser la fonction 'NbClust' pour déterminer le bon nombre de clusters: Vous pouvez vérifier le projet actuel dans Github avec les données réelles et les clusters - Extension à cet algorithme 'kmeans' également effectuée en utilisant le bon nombre de 'centres'.

Lien vers le projet Github: https://github.com/RutvijBhutaiya/Thailand-Customer-Engagement-Facebook

0
Rutvij

J'ai utilisé la solution trouvée ici: http://efavdb.com/mean-shift/ et cela a très bien fonctionné pour moi 

import numpy as np
from sklearn.cluster import MeanShift, estimate_bandwidth
from sklearn.datasets.samples_generator import make_blobs
import matplotlib.pyplot as plt
from itertools import cycle
from PIL import Image

#%% Generate sample data
centers = [[1, 1], [-.75, -1], [1, -1], [-3, 2]]
X, _ = make_blobs(n_samples=10000, centers=centers, cluster_std=0.6)

#%% Compute clustering with MeanShift

# The bandwidth can be automatically estimated
bandwidth = estimate_bandwidth(X, quantile=.1,
                               n_samples=500)
ms = MeanShift(bandwidth=bandwidth, bin_seeding=True)
ms.fit(X)
labels = ms.labels_
cluster_centers = ms.cluster_centers_

n_clusters_ = labels.max()+1

#%% Plot result
plt.figure(1)
plt.clf()

colors = cycle('bgrcmykbgrcmykbgrcmykbgrcmyk')
for k, col in Zip(range(n_clusters_), colors):
    my_members = labels == k
    cluster_center = cluster_centers[k]
    plt.plot(X[my_members, 0], X[my_members, 1], col + '.')
    plt.plot(cluster_center[0], cluster_center[1],
             'o', markerfacecolor=col,
             markeredgecolor='k', markersize=14)
plt.title('Estimated number of clusters: %d' % n_clusters_)
plt.show()

 enter image description here

0
snoob dogg