K-demektir kümelemesi kullanırken k'yı nasıl belirlerim?


142

Ben yaklaşık inceliyordum k-ortalamalar kümeleme ve net değil bir şey k değerini seçmek nasıl. Sadece deneme yanılma mıydı yoksa daha fazlası mı var?


34
Ah ah ... Gerçekten var (k-ortalama yaklaşık) bir soru.
mjv

L (log olasılığı) fonksiyonunun kodunu paylaşabilir misiniz? X, Y'de bir merkez verildiğinde ve (x (i = 1,2,3,4, ..., n), y (i = 1,2,3,4, .., n)) 'yi işaret eder, nasıl L alabilir miyim?

7
konuyla ilgili Wikipedia makalesine bağlantı: en.wikipedia.org/wiki/…
Amro

11
Buraya yarım düzine yöntemle (kullanarak R) benzer bir Q yanıtladım : stackoverflow.com/a/15376462/1036500
Ben

Yanıtlar:


142

Bayesian Bilgi Ölçütünü (BIC) en üst düzeye çıkarabilirsiniz:

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

burada L(X | C)veri kümesi log-olasılık olan Xmodele göre C, pmodel parametrelerinin sayısı C, ve nveri kümesi içinde nokta sayısıdır. Bkz. ICML 2000'de Dan Pelleg ve Andrew Moore tarafından "X-anlamları: K -ortalamalarını küme sayısını etkili bir şekilde tahmin ederek genişletme " .

Başka bir yaklaşım, kartık açıklama uzunluğunu azaltmayana kadar sentroidleri büyük bir değerle başlamak ve çıkarmaya devam etmektir (k azaltarak). Bkz "sağlam vektör nicemleme için MDL ilkesini" de Horst Bischof, Ales LEONARDIS, ve Alexander Selb tarafından Desen Analizi ve Uygulamaları vol. 2, s. 59-72, 1999.

Son olarak, bir kümeyle başlayabilir, ardından her kümeye atanan noktalar bir Gauss dağılımına sahip olana kadar kümeleri bölmeye devam edebilirsiniz. In "Öğrenme k içinde k -Ben" (2003 NIPS), Greg Hamerly ve Charles Elkan bu eserler daha iyi BIC daha ve bu BIC yeterince güçlü modelin karmaşıklığını cezalandırmak olmadığını bazı kanıtlar göstermektedir.


Mükemmel cevap! X-Ortalamaları için, genel BIC puanı n: = k * 2 (k kümeler, her kümenin Gaussian tarafından ortalama / varyans parametreleriyle modellenmiş) olup olmadığını biliyor musunuz? Ayrıca "ebeveyn" BIC> "2 çocuk" BIC'i belirlerseniz, bu kümeyi bir sonraki yinelemede tekrar böler miydiniz?
Budric

2
@Budric, bunlar muhtemelen ayrı sorular olmalı ve belki de stats.stackexchange.com adresinde olmalıdır.
Vebjorn Ljosa

37

Temel olarak, iki değişken arasında bir denge bulmak istersiniz: küme sayısı ( k ) ve kümelerin ortalama varyansı. Birincisini en aza indirirken ikincisini de küçültmek istiyorsunuz. Tabii ki, küme sayısı arttıkça ortalama varyans azalır (önemsiz k = n ve varyans = 0 durumuna kadar ).

Veri analizinde her zaman olduğu gibi, her durumda diğerlerinden daha iyi çalışan tek bir gerçek yaklaşım yoktur. Sonunda, kendi en iyi kararınızı kullanmalısınız. Bunun için, kümelerin sayısını ortalama varyansa göre çizmeye yardımcı olur (algoritmayı birkaç k değeri için zaten çalıştırdığınızı varsayar ). Sonra eğrinin dizindeki kümelerin sayısını kullanabilirsiniz.


24

Evet, Dirsek yöntemini kullanarak kümelerin en iyi sayısını bulabilirsiniz, ancak komut dosyası kullanarak dirsek grafiğinden kümelerin değerini bulmak zahmetli buldum. Dirsek grafiğini gözlemleyebilir ve dirsek noktasını kendiniz bulabilirsiniz, ancak senaryodan bulmak çok işti.

Yani başka bir seçenek bulmak için Silhouette Metodu kullanmaktır . Silhouette'in sonucu R'deki Dirsek yönteminin sonucuna tamamen uygundur.

İşte yaptığım şey.

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

Umarım yardımcı olur!!


2
Python kullanıcıları için Siluet Analizi eğitimine bir bağlantı ekleyerek scikit-learn.org/stable/auto_examples/cluster/…
Chaitanya Shivade

10

Kod örneği arayan benim gibi yeni başlayan biri olabilir. silhouette_score ile ilgili bilgilere buradan ulaşabilirsiniz.

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)

9

Bak bu Greg Hamerly Charles Elkan tarafından "k-araçlarında k Öğrenme", kağıt. Doğru sayıda kümeyi belirlemek için bir Gauss testi kullanır. Ayrıca, yazarlar bu yöntemin kabul edilen cevapta belirtilen BIC'den daha iyi olduğunu iddia etmektedir.


7

Başparmak Kuralı denilen bir şey var. Küme sayısının şu şekilde hesaplanabileceğini söylüyor:

k = (n/2)^0.5

burada n, numunenizdeki toplam öğe sayısıdır. Aşağıdaki bilgilerin bu bilgilerin doğruluğunu kontrol edebilirsiniz:

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

Ayrıca, dağıtımınızın bir Gauss Dağılımını veya Normal Dağılım'ı izlediği G-yolları adı verilen başka bir yöntem daha vardır. Tüm k gruplarınız bir Gauss Dağılımını takip edene kadar k'nın arttırılmasından oluşur. Çok fazla istatistik gerektirir, ancak yapılabilir. İşte kaynak:

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

Umarım bu yardımcı olur!


3

Önce verilerinizden oluşan minimum bir ağaç oluşturun. K-1'in en pahalı kenarlarını kaldırmak, ağacı K kümelerine ayırır,
böylece MST'yi bir kez oluşturabilir, çeşitli K için küme aralıklarına / metriklerine bakabilir ve eğrinin dizini alabilirsiniz.

Bu sadece Tekli bağlantı_kırma için çalışır , ancak bunun için hızlı ve kolaydır. Ayrıca, MST'ler iyi görseller oluşturur.
Örneğin, kümeleme için stats.stackexchange görselleştirme yazılımı altındaki MST grafiğine bakın .


3

Kimsenin bu mükemmel makaleden bahsetmediğine şaşırdım: http://www.ee.columbia.edu/~dpwe/papers/PhamDN05-kmeans.pdf

Diğer birkaç öneriyi izledikten sonra nihayet bu blogu okurken bu makaleye rastladım: https://datasciencelab.wordpress.com/2014/01/21/selection-of-k-in-k-means-clustering-reloaded/

Bundan sonra Scala'da uyguladım, kullanım durumlarım için gerçekten iyi sonuçlar veren bir uygulama. İşte kod:

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]]
}

Scala 2.11.7'de 0.12 esinti ve nak 1.3 ile
uygulandı

Merhaba @eirirlar Python ile aynı kodu uygulamaya çalışıyorum - ama web sitesindeki kodu takip edemedim.
piccolo

@ImranRashid Üzgünüm Sadece 2 boyutla test ettim ve bir Python uzmanı değilim.
eirirlar

3

MATLAB'ı, 2013b'den bu yana herhangi bir sürümü kullanırsanız, belirli bir veri kümesi için evalclustersen uygun olanı bulmak için işlevi kullanabilirsiniz k.

- Bu işlev 3 kümeleme algoritmaları arasından seçim yapmanızı sağlar kmeans, linkageve gmdistribution.

- Ayrıca 4 kümelenme değerlendirme kriterleri arasında seçim yapmanızı sağlar CalinskiHarabasz, DaviesBouldin, gapve silhouette.


3

K-araçlarına parametre olarak sağlanacak k kümelerinin sayısını bilmiyorsanız, otomatik olarak bulmanın dört yolu vardır:

  • G-algortitm anlamına gelir: bir k-ortalama merkezinin ikiye bölünüp bölünmeyeceğine karar vermek için istatistiksel bir test kullanarak kümelerin sayısını otomatik olarak keşfeder. Bu algoritma, bir veri alt kümesinin bir Gauss dağılımını (olayların tam binom dağılımına yaklaşan sürekli işlev) izlediği hipotezi için istatistiksel bir sınamaya dayalı olarak kümelerin sayısını tespit etmek için hiyerarşik bir yaklaşım benimser ve eğer değilse kümeyi böler . Sadece bir küme (k = 1) gibi az sayıda merkezle başlar, ardından algoritma onu iki merkeze böler (k = 2) ve bu iki merkezin her birini tekrar (k = 4) böler, Toplam. G-ortalaması bu dört merkezi kabul etmezse, cevap bir önceki adımdır: bu durumda iki merkez (k = 2). Bu, veri kümenizin bölüneceği küme sayısıdır. G-Ortalamaları, örneklerinizi grupladıktan sonra alacağınız küme sayısı hakkında bir tahmininiz olmadığında çok yararlıdır. "K" parametresi için uygunsuz bir seçimin size yanlış sonuçlar verebileceğine dikkat edin. G-araçlarının paralel versiyonuna denirp-anlamına gelir . G-kaynakları anlamına gelir: kaynak 1 kaynak 2 kaynak 3

  • x-anlamına gelir : Bayesian Bilgi Ölçütü (BIC) veya Akaike Bilgi Ölçütü (AIC) ölçüsünü optimize etmek için verimli bir şekilde küme konumlarını ve küme sayısını araştıran yeni bir algoritma. Bu k-araç versiyonu k sayısını bulur ve k-araçlarını hızlandırır.

  • Çevrimiçi k-araçları veya Akış k-araçları: tüm verileri bir kez tarayarak k-araçlarının yürütülmesine izin verir ve otomatik olarak optimum k sayısını bulur. Spark uygular.

  • MeanShift algoritması : kümelerin sayısı hakkında önceden bilgi gerektirmeyen ve kümelerin şeklini kısıtlamayan parametrik olmayan bir kümeleme tekniğidir. Ortalama vardiya kümelenmesi, numunelerin düzgün yoğunluğundaki “lekeleri” keşfetmeyi amaçlamaktadır. Bu, belirli bir bölgedeki noktaların ortalaması olacak şekilde sentroid adaylarını güncelleyerek çalışan bir sentroid tabanlı algoritmadır. Bu adaylar daha sonra son sentroid setini oluşturmak üzere kopyaları neredeyse ortadan kaldırmak için bir işleme sonrası aşamada filtrelenir. Kaynaklar: kaynak1 , kaynak2 , source3


2

Burada bulduğum çözümü kullandım: http://efavdb.com/mean-shift/ ve benim için çok iyi çalıştı:

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

resim açıklamasını buraya girin



1

DATAAdında bir veri matrisiniz olduğunu varsayarsak , medoidler etrafında bölümleme tahmini yaparak (siluet analiziyle) şöyle yapabilirsiniz:

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

1

Olası bir cevap, k'yi bulmak için Genetik Algoritma gibi Meta Sezgisel Algoritmayı kullanmaktır. Bu basit. rastgele K'yi (bazı aralıklarda) kullanabilir ve Genetik Algoritmanın fit fonksiyonunu Silhouette ve Find fonksiyonundaki en iyi K bazını ölçebilirsiniz.

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


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

veri ve kütüphane eklemeyi seçersiniz ve km = [] 'yi Yüzde': 2} 'ye kopyalarsınız ve
python'unuzu

Stack Overflow'a hoş geldiniz! Bu kod sorunu çözmeye yardımcı olsa da , soruyu neden ve / veya nasıl cevapladığını açıklamaz . Bu ek bağlamın sağlanması, uzun vadeli eğitim değerini önemli ölçüde artıracaktır. Hangi sınırlamalar ve varsayımlar dahil olmak üzere açıklama eklemek için lütfen yanıtınızı düzenleyin .
Toby Speight

1

Başka bir yaklaşım, optimum sayıda kümeyi bulmak için Kendi Kendini Düzenleyen Haritaları (SOP) kullanmaktır. SOM (Kendi Kendini Düzenleyen Harita) denetimsiz bir sinir ağı metodolojisidir ve problem çözme için kümelemede sadece girdinin kullanılması gerekir. Bu yaklaşım, müşteri segmentasyonu hakkında bir makalede kullanılmıştır.

Makalenin referansı

Abdellah Amine vd., Kümeleme Teknikleri ve LRFM Modeli Kullanarak E-ticarette Müşteri Segmentasyon Modeli: Fas'ta Online Mağazalar Örneği, Dünya Bilim, Mühendislik ve Teknoloji Akademisi Uluslararası Bilgisayar ve Bilişim Mühendisliği Dergisi Cilt: 9, No: 8 , 2015, 1999-2010


0

Merhaba ben açıklamak basit ve düz yapacak, 'NbClust' kitaplığı kullanarak kümeleri belirlemek istiyorum.

Şimdi, doğru sayıda kümeyi belirlemek için 'NbClust' işlevini kullanma: Github'daki gerçek projeyi gerçek veriler ve kümeler ile kontrol edebilirsiniz - Doğru sayıda 'merkez' kullanılarak gerçekleştirilen bu 'kmeans' algoritmasına eklenti.

Github Projesi Bağlantısı: https://github.com/RutvijBhutaiya/Thailand-Customer-Engagement-Facebook


Github bağlantısını eklemek yerine, kodunuza erişilemese bile başkalarına yardımcı olabilecek birkaç kod satırı ekleyebilir misiniz?
Giulio Caccin

0

Veri noktalarınızı görsel olarak inceleyerek kümelerin sayısını seçebilirsiniz, ancak yakında bu süreçte en basit veri kümeleri hariç herkes için çok fazla belirsizliğin olduğunu fark edeceksiniz. Bu her zaman kötü değildir, çünkü denetimsiz öğrenim görüyorsunuz ve etiketleme sürecinin doğasında bir sübjektiflik var. Burada, belirli bir problemle veya benzer bir şeyle daha önce deneyim sahibi olmanız, doğru değeri seçmenize yardımcı olacaktır.

Kullanmanız gereken küme sayısı hakkında bir ipucu istiyorsanız, Dirsek yöntemini uygulayabilirsiniz:

Her şeyden önce, bazı k değerleri (örneğin 2, 4, 6, 8, vb.) İçin karesel hatanın (SSE) toplamını hesaplayın. SSE, kümenin her bir üyesi ile sentroidi arasındaki kare mesafenin toplamı olarak tanımlanır. Matematiksel olarak:

SSE = ΣKi = 1Σx∈cidist (x, Cl) 2

K'yi SSE'ye göre çizerseniz, k büyüdükçe hatanın azaldığını görürsünüz; bunun nedeni, kümelerin sayısı arttığında daha küçük olmaları gerektiğinden bozulma da daha az olur. Dirsek yönteminin fikri, SSE'nin aniden azaldığı k'yi seçmektir. Bu, aşağıdaki resimde görebileceğiniz gibi, grafikte bir "dirsek efekti" üretir:

resim açıklamasını buraya girin

Bu durumda, k = 6 Dirsek yönteminin seçtiği değerdir. Dirsek yönteminin sezgisel bir yöntem olduğunu ve bu nedenle, özel durumunuzda iyi çalışabileceğini veya çalışmayabileceğini dikkate alın. Bazen birden fazla dirsek vardır veya hiç dirsek yoktur. Bu gibi durumlarda genellikle, k-araçlarının çözmeye çalıştığınız belirli kümeleme problemi bağlamında ne kadar iyi performans gösterdiğini değerlendirerek en iyi k değerini hesaplarsınız.


0

Diz çökmüş bir Python paketi üzerinde çalıştım (Kneedle algoritması). Küme numarasını, eğrinin düzleşmeye başladığı nokta olarak dinamik olarak bulur. Bir dizi x ve y değeri verildiğinde, diz fonksiyonun diz noktasını döndürür. Diz noktası maksimum eğrilik noktasıdır. İşte örnek kod.

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 = aralık (1, len (y) +1)

diz içe aktarmadan KneeLocator kn = KneeLocator (x, y, eğri = 'dışbükey', yön = 'azalan')

yazdırmak (kn.knee)


Lütfen yanıtınıza başkalarının da öğrenebileceği bir açıklama ekleyin
Nico Haase
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.