Bagaimana cara menentukan k ketika menggunakan k-means clustering?

142

Saya telah mempelajari tentang k-means clustering , dan satu hal yang tidak jelas adalah bagaimana Anda memilih nilai k. Apakah ini hanya masalah coba-coba, atau ada yang lebih dari itu?

Jason Baker
sumber
34
Ah ah ... Itu benar - benar pertanyaan (tentang k-mean).
mjv
dapatkah Anda membagikan kode untuk fungsi L (kemungkinan log)? Diberikan pusat pada X, Y dan titik di (x (i = 1,2,3,4, ..., n), y (i = 1,2,3,4, .., n)), bagaimana saya mendapatkan L?
7
tautan ke artikel Wikipedia tentang hal ini: en.wikipedia.org/wiki/…
Amro
11
Saya telah menjawab Q serupa dengan setengah lusin metode (menggunakan R) di sini: stackoverflow.com/a/15376462/1036500
Ben

Jawaban:

142

Anda dapat memaksimalkan Kriteria Informasi Bayesian (BIC):

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

di mana L(X | C)kemungkinan log dari dataset Xmenurut model C, padalah jumlah parameter dalam model C, dan njumlah titik dalam dataset. Lihat "X-means: memperluas K- berarti dengan estimasi efisien jumlah cluster" oleh Dan Pelleg dan Andrew Moore dalam ICML 2000.

Pendekatan lain adalah mulai dengan nilai besar untuk kdan terus menghapus centroid (mengurangi k) sampai tidak lagi mengurangi panjang deskripsi. Lihat "Prinsip MDL untuk quantisation vektor yang kuat" oleh Horst Bischof, Ales Leonardis, dan Alexander Selb dalam Analisis Pola dan Aplikasi vol. 2, hal. 59-72, 1999.

Akhirnya, Anda bisa mulai dengan satu kluster, lalu terus membelah kluster hingga titik yang ditetapkan untuk masing-masing klaster memiliki distribusi Gaussian. Dalam "Learning the k in k -means" (NIPS 2003), Greg Hamerly dan Charles Elkan menunjukkan beberapa bukti bahwa ini bekerja lebih baik daripada BIC, dan bahwa BIC tidak cukup menghukum kompleksitas model yang cukup kuat.

Vebjorn Ljosa
sumber
Jawaban bagus! Untuk X-Means, apakah Anda tahu jika skor BIC keseluruhan n: = k * 2 (k cluster, setiap cluster dimodelkan oleh Gaussian dengan parameter mean / variance). Juga jika Anda menentukan BIC "induk"> "2 anak", apakah Anda akan pernah memecah kluster itu lagi di iterasi berikutnya?
Budric
2
@Budric, ini mungkin pertanyaan yang terpisah, dan mungkin di stats.stackexchange.com.
Vebjorn Ljosa
37

Pada dasarnya, Anda ingin menemukan keseimbangan antara dua variabel: jumlah cluster ( k ) dan varians rata-rata dari cluster. Anda ingin meminimalkan yang pertama sementara juga meminimalkan yang kedua. Tentu saja, ketika jumlah cluster meningkat, varians rata-rata menurun (hingga kasus sepele k = n dan varians = 0).

Seperti biasa dalam analisis data, tidak ada satu pendekatan sejati yang berfungsi lebih baik daripada semua yang lain dalam semua kasus. Pada akhirnya, Anda harus menggunakan penilaian terbaik Anda sendiri. Untuk itu, ada baiknya untuk merencanakan jumlah cluster terhadap varian rata-rata (yang mengasumsikan bahwa Anda telah menjalankan algoritma untuk beberapa nilai k ). Kemudian Anda bisa menggunakan jumlah cluster di bagian bawah kurva.

Jan Kruger
sumber
24

Ya, Anda dapat menemukan jumlah cluster terbaik menggunakan metode Elbow, tetapi saya merasa kesulitan untuk menemukan nilai cluster dari grafik siku menggunakan skrip. Anda dapat mengamati grafik siku dan menemukan titik siku sendiri, tetapi banyak pekerjaan yang menemukannya dari skrip.

Jadi pilihan lain adalah menggunakan Metode Silhouette untuk menemukannya. Hasil dari Silhouette sepenuhnya mematuhi hasil dari metode Elbow di R.

Inilah yang saya lakukan.

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

Semoga ini bisa membantu !!

Udeep Shakya
sumber
2
Hanya menambahkan tautan ke tutorial Analisis Silhouette untuk pengguna python scikit-learn.org/stable/auto_examples/cluster/…
Chaitanya Shivade
10

Mungkin seseorang pemula seperti saya mencari contoh kode. informasi untuk silhouette_score tersedia di sini.

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)
bhargav patel
sumber
9

Lihatlah makalah ini , "Belajar k dalam k-means" oleh Greg Hamerly, Charles Elkan. Ini menggunakan tes Gaussian untuk menentukan jumlah cluster yang tepat. Juga, penulis mengklaim bahwa metode ini lebih baik daripada BIC yang disebutkan dalam jawaban yang diterima.

Otonom
sumber
7

Ada sesuatu yang disebut Aturan Jempol. Dikatakan bahwa jumlah cluster dapat dihitung oleh

k = (n/2)^0.5

di mana n adalah jumlah total elemen dari sampel Anda. Anda dapat memeriksa kebenaran informasi ini di kertas berikut:

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

Ada juga metode lain yang disebut G-means, di mana distribusi Anda mengikuti Distribusi Gaussian atau Distribusi Normal. Ini terdiri dari peningkatan k sampai semua grup k Anda mengikuti Distribusi Gaussian. Itu membutuhkan banyak statistik tetapi bisa dilakukan. Inilah sumbernya:

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

Saya harap ini membantu!

Arthur Busqueiro
sumber
3

Saya terkejut tidak ada yang menyebutkan artikel yang luar biasa ini: http://www.ee.columbia.edu/~dpwe/papers/PhamDN05-kmeans.pdf

Setelah mengikuti beberapa saran lain, saya akhirnya menemukan artikel ini ketika membaca blog ini: https://datasciencelab.wordpress.com/2014/01/21/selection-of-k-in-k-means-clustering-reloaded/

Setelah itu saya mengimplementasikannya di Scala, implementasi yang untuk kasus penggunaan saya memberikan hasil yang sangat baik. Ini kode:

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]]
}
eirirlar
sumber
Diterapkan dalam scala 2.11.7 dengan angin 0.12 dan nak 1.3
eirirlar
Hai @ eirirlar Saya mencoba menerapkan kode yang sama dengan Python - tapi saya tidak bisa mengikuti kode di situs web. Lihat posting saya: stackoverflow.com/questions/36729826/python-k-means-clustering
piccolo
@ImranRashid Maaf saya hanya menguji dengan 2 dimensi, dan saya bukan ahli Python.
eirirlar
3

Jika Anda menggunakan MATLAB, versi apa pun sejak 2013b, Anda dapat menggunakan fungsi ini evalclustersuntuk mencari tahu apa yang seharusnya optimal kuntuk dataset yang diberikan.

Fungsi ini memungkinkan Anda memilih di antara 3 algoritma pengelompokan - kmeans, linkagedan gmdistribution.

Hal ini juga memungkinkan Anda memilih dari antara kriteria evaluasi 4 pengelompokan - CalinskiHarabasz, DaviesBouldin, gapdan silhouette.

Kristada673
sumber
3

Jika Anda tidak tahu jumlah klaster k yang harus disediakan sebagai parameter untuk k-means, maka ada empat cara untuk menemukannya secara otomatis:

  • Algortitme G-means: ia menemukan jumlah cluster secara otomatis menggunakan uji statistik untuk memutuskan apakah akan membagi pusat k-means menjadi dua. Algoritme ini mengambil pendekatan hierarkis untuk mendeteksi jumlah cluster, berdasarkan pada uji statistik untuk hipotesis bahwa subset data mengikuti distribusi Gaussian (fungsi kontinu yang mendekati distribusi peristiwa binomial yang tepat), dan jika tidak memecah cluster . Ini dimulai dengan sejumlah kecil pusat, katakan satu klaster saja (k = 1), kemudian algoritma membaginya menjadi dua pusat (k = 2) dan membelah masing-masing dua pusat ini lagi (k = 4), memiliki empat pusat di total. Jika G-means tidak menerima empat pusat ini maka jawabannya adalah langkah sebelumnya: dua pusat dalam kasus ini (k = 2). Ini adalah jumlah cluster yang akan dibagi oleh dataset Anda. G-means sangat berguna ketika Anda tidak memiliki estimasi jumlah cluster yang akan Anda dapatkan setelah mengelompokkan instance Anda. Perhatikan bahwa pilihan yang tidak nyaman untuk parameter "k" mungkin memberi Anda hasil yang salah. Versi paralel dari g-means disebutp-means . Sumber G-means: sumber 1 sumber 2 sumber 3

  • x-means : algoritma baru yang efisien, mencari ruang lokasi cluster dan jumlah cluster untuk mengoptimalkan Bayesian Information Criterion (BIC) atau ukuran Akaike Information Criterion (AIC). Versi k-means ini menemukan angka k dan juga mempercepat k-means.

  • Online k-means atau Streaming k-means: memungkinkan untuk mengeksekusi k-means dengan memindai seluruh data satu kali dan menemukan secara otomatis jumlah k yang optimal. Spark mengimplementasikannya.

  • Algoritma MeanShift : ini adalah teknik cluster nonparametric yang tidak memerlukan pengetahuan sebelumnya tentang jumlah cluster, dan tidak membatasi bentuk cluster. Mean shift clustering bertujuan untuk menemukan "gumpalan" dalam kepadatan sampel yang halus. Ini adalah algoritma berbasis centroid, yang bekerja dengan memperbarui kandidat untuk centroid menjadi rata-rata poin dalam wilayah tertentu. Kandidat ini kemudian disaring dalam tahap pasca-pemrosesan untuk menghilangkan duplikat-hampir untuk membentuk set terakhir centroid. Sumber: source1 , source2 , source3

curiosus
sumber
2

Saya menggunakan solusi yang saya temukan di sini: http://efavdb.com/mean-shift/ dan itu bekerja sangat baik untuk saya:

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

masukkan deskripsi gambar di sini

snoob dogg
sumber
1

Ide saya adalah menggunakan Koefisien Siluet untuk menemukan nomor cluster optimal (K). Penjelasan detail ada di sini .

qmaruf
sumber
1

Dengan asumsi Anda memiliki matriks data yang disebut DATA, Anda dapat melakukan partisi di sekitar medoid dengan estimasi jumlah cluster (dengan analisis siluet) seperti ini:

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

Salah satu jawaban yang mungkin adalah menggunakan Meta Heuristic Algorithm seperti Genetic Algorithm untuk menemukan k. Sederhana saja. Anda dapat menggunakan K acak (dalam beberapa rentang) dan mengevaluasi fungsi kecocokan Algoritma Genetika dengan beberapa pengukuran seperti Silhouette Dan Temukan basis K terbaik pada fungsi fit.

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

Masoud
sumber
1
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})
sumit
sumber
Anda memilih data dan pustaka tambahkan dan Anda salin km = [] ke Persentase ': 2}) lalu dan jalankan python Anda dan lihat
sumit
Selamat Datang di Stack Overflow! Meskipun kode ini dapat membantu menyelesaikan masalah, kode ini tidak menjelaskan mengapa dan / atau bagaimana ia menjawab pertanyaan. Memberikan konteks tambahan ini akan secara signifikan meningkatkan nilai pendidikan jangka panjangnya. Harap edit jawaban Anda untuk menambahkan penjelasan, termasuk batasan dan asumsi apa yang berlaku.
Toby Speight
1

Pendekatan lain adalah menggunakan Self Organizing Maps (SOP) untuk menemukan jumlah cluster yang optimal. SOM (Self-Organizing Map) adalah metodologi jaringan saraf yang tidak diawasi, yang hanya membutuhkan input yang digunakan untuk pengelompokan untuk pemecahan masalah. Pendekatan ini digunakan dalam makalah tentang segmentasi pelanggan.

Referensi dari makalah ini adalah

Abdellah Amine et al., Model Segmentasi Pelanggan dalam E-commerce Menggunakan Teknik Clustering dan Model LRFM: Kasus Toko Online di Maroko, World Academy of Science, Engineering and Technology Jurnal Internasional Teknik Komputer dan Informasi Vol: 9, No: 8 , 2015, 1999 - 2010

boyaronur
sumber
0

Hai Saya akan membuatnya sederhana dan langsung untuk menjelaskan, saya ingin menentukan cluster menggunakan perpustakaan 'NbClust'.

Sekarang, bagaimana menggunakan fungsi 'NbClust' untuk menentukan jumlah cluster yang tepat: Anda dapat memeriksa proyek aktual di Github dengan data dan cluster aktual - Perluasan algoritma 'kmeans' ini juga dilakukan dengan menggunakan jumlah 'pusat' yang tepat.

Tautan Proyek Github: https://github.com/RutvijBhutaiya/Thailand-Customer-Engagement-Facebook

Rutvij
sumber
Alih-alih menambahkan tautan github, dapatkah Anda menambahkan beberapa baris kunci kode yang dapat membantu orang lain meskipun kode Anda tidak dapat dijangkau?
Giulio Caccin
0

Anda dapat memilih jumlah cluster dengan secara visual memeriksa poin data Anda, tetapi Anda akan segera menyadari bahwa ada banyak ambiguitas dalam proses ini untuk semua kecuali kumpulan data yang paling sederhana. Ini tidak selalu buruk, karena Anda melakukan pembelajaran tanpa pengawasan dan ada beberapa subjektivitas yang melekat dalam proses pelabelan. Di sini, memiliki pengalaman sebelumnya dengan masalah khusus itu atau yang serupa akan membantu Anda memilih nilai yang tepat.

Jika Anda ingin beberapa petunjuk tentang jumlah cluster yang harus Anda gunakan, Anda dapat menerapkan metode Siku:

Pertama-tama, hitung jumlah kesalahan kuadrat (SSE) untuk beberapa nilai k (misalnya 2, 4, 6, 8, dll.). SSE didefinisikan sebagai jumlah dari jarak kuadrat antara setiap anggota cluster dan centroid-nya. Secara matematis:

SSE = ∑Ki = 1∑x∈cidist (x, ci) 2

Jika Anda memplot k terhadap SSE, Anda akan melihat bahwa errornya menurun ketika k bertambah besar; ini karena ketika jumlah cluster meningkat, mereka harus lebih kecil, sehingga distorsi juga lebih kecil. Gagasan metode siku adalah untuk memilih k di mana SSE menurun secara tiba-tiba. Ini menghasilkan "efek siku" pada grafik, seperti yang Anda lihat pada gambar berikut:

masukkan deskripsi gambar di sini

Dalam hal ini, k = 6 adalah nilai yang telah dipilih metode Elbow. Mempertimbangkan bahwa metode Siku adalah heuristik dan, dengan demikian, mungkin atau mungkin tidak berfungsi dengan baik dalam kasus khusus Anda. Terkadang, ada lebih dari satu siku, atau tidak ada siku sama sekali. Dalam situasi tersebut, Anda biasanya menghitung k terbaik dengan mengevaluasi seberapa baik kinerja k-means dalam konteks masalah pengelompokan tertentu yang Anda coba selesaikan.

Faisal Shahbaz
sumber
0

Saya bekerja pada rajutan paket Python (algoritma Kneedle). Ia menemukan nomor cluster secara dinamis sebagai titik di mana kurva mulai merata .. Diberikan satu set nilai x dan y, rajutan akan mengembalikan titik lutut fungsi. Titik lutut adalah titik kelengkungan maksimum. Berikut adalah contoh kode.

y = [7342,1301373073857, 6881,7109460930769, 6531,1657905495022,
6356,2255554679778, 6209,8382535595829, 6094,9052166741121, 5980,0191582610196, 5880,1869867848218, 5779,8957906367368, 5691,1879324562778, 5617,5153566271356, 5532,2613232619951, 5467,352265375117, 5395,4493783888756, 5345,3459908298091, 5290,6769823693812, 5243,5271656371888, 5207,2501206569532, 5164,9617535255456]

x = rentang (1, len (y) +1)

dari impor kneed KneeLocator kn = KneeLocator (x, y, kurva = 'cembung', arah = 'menurun')

print (kn.knee)

madhuri M
sumber
Silakan tambahkan beberapa penjelasan untuk jawaban Anda sehingga orang lain dapat belajar darinya
Nico Haase