Як визначити k при використанні кластеризації k-засобів?


142

Я вивчав питання про кластеризацію k-значень , і одне, що не зрозуміло, - це те, як ви обираєте значення k. Це лише питання спроб та помилок, чи є в ньому більше?


34
Ах , ах ... Це дійсно питання (про к-середніх).
mjv

Ви можете поділитися кодом для функції L (вірогідність журналу)? Дано центр у X, Y та точки у (x (i = 1,2,3,4, ..., n), y (i = 1,2,3,4, .., n)), як я отримую L?

7
посилання на статтю у Вікіпедії на тему: en.wikipedia.org/wiki/…
Amro

11
Я відповів на подібне запитання, використовуючи півдесятка методів (використовуючи R) тут: stackoverflow.com/a/15376462/1036500
Бен

Відповіді:


142

Ви можете максимально використовувати Байєсівський критерій інформації (BIC):

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

де L(X | C)вірогідність журналу набору даних Xза моделлю C, pкількість параметрів у моделі Cта nкількість точок у наборі даних. Див. "X-означає: розширення К -засобів з ефективною оцінкою кількості кластерів" Дена Пеллеґ та Ендрю Мура в ICML 2000.

Інший підхід - почати з великого значення kі продовжувати видаляти центроїди (зменшуючи k), поки це більше не зменшить довжину опису. Див. "Принцип MDL для надійної квантування векторів" Хорста Бішофа, Алеся Леонардіса та Олександра Селба в " Аналіз шаблонів та застосувань" vol. 2, с. 59-72, 1999.

Нарешті, ви можете почати з одного кластера, а потім продовжувати розділяти кластери до тих пір, поки точки, присвоєні кожному кластеру, не матимуть розподілу Гаусса. В «Ознайомлення з до в до -середній» (NIPS 2003), Грег Hamerly і Чарльз Elkan показати деякі докази того, що це працює краще , ніж BIC, і що BIC не оштрафували складності моделі досить сильно.


Чудова відповідь! Чи знаєте ви для X-Means, чи загальна оцінка BIC n: = k * 2 (k кластери, кожен кластер модельований Гауссом із параметрами середньої / дисперсії). Також якщо ви визначите BIC "батьків" BIC> "2 дитини", чи могли б ви коли-небудь розділити цей кластер знову при наступній ітерації?
Будрік

2
@Budric, ймовірно, це можуть бути окремі запитання, а може бути, і на stats.stackexchange.com.
Вебйорн Льоса

37

В основному, ви хочете знайти баланс між двома змінними: кількістю кластерів ( k ) та середньою дисперсією кластерів. Ви хочете мінімізувати перше, а також мінімізувати останнє. Звичайно, зі збільшенням кількості кластерів середня дисперсія зменшується (аж до тривіального випадку k = n та дисперсії = 0).

Як завжди в аналізі даних, не існує жодного справжнього підходу, який би працював краще, ніж усі інші у всіх випадках. Зрештою, ви повинні використовувати власне найкраще судження. Для цього допомагає побудувати кількість кластерів проти середньої дисперсії (що передбачає, що ви вже запустили алгоритм для кількох значень k ). Тоді можна використовувати кількість скупчень на коліні кривої.


24

Так, ви можете знайти найкращу кількість кластерів методом Elbow, але мені було складно знайти значення кластерів з ліктьового графіка за допомогою скрипту. Ви можете спостерігати за графіком ліктя і знаходити точку ліктя самостійно, але це було багато роботи, знаходячи це за сценарієм.

Отже, інший варіант - використовувати метод Silhouette, щоб знайти його. Результат від силуету повністю відповідає результату методу ліктьового суглоба в Р.

Ось що я зробив.

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

Сподіваюся, це допомагає !!


2
Просто додавання посилання на підручник з аналізу силуетів для користувачів python scikit-learn.org/stable/auto_examples/cluster/…
Чайтанія Шиваде

10

Можливо, хтось із початківців, як я, шукає приклад коду. інформація для silhouette_score доступна тут.

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

Подивіться на цей документ "Навчитися k k k-означає" Грега Хамерлі, Чарльза Елкана. Він використовує тест Гаусса для визначення потрібної кількості кластерів. Також автори стверджують, що цей метод кращий за BIC, про який йдеться у прийнятій відповіді.


7

Існує щось, що називається Правилом великого пальця. Це говорить про те, що кількість кластерів можна обчислити за

k = (n/2)^0.5

де n - загальна кількість елементів з вашої вибірки. Ви можете перевірити правдивість цієї інформації на наступному документі:

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

Існує також інший метод, який називається G-засобом, де ваш розподіл слідує за Гауссовим розподілом або Нормальним розподілом. Він складається з збільшення k, поки всі ваші k групи не дотримуються Гауссового розподілу. Це вимагає багато статистики, але це можна зробити. Ось джерело:

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

Я сподіваюся, що це допомагає!


3

Спочатку побудуйте мінімальну прольотну валу даних. Видалення K-1 найдорожчих країв розбиває дерево на кластери K,
тож ви зможете побудувати MST один раз, подивіться на відстані / метрику кластерів для різних K і візьміть коліно кривої.

Це працює лише для односхильних_кластерів , але для цього це швидко і просто. Крім того, MST роблять хороші візуальні зображення.
Дивіться, наприклад, графік MST під програмним забезпеченням візуалізації stats.stackexchange для кластеризації .


3

Я здивований, що ніхто не згадав цю чудову статтю: http://www.ee.columbia.edu/~dpwe/papers/PhamDN05-kmeans.pdf

Після наступних кількох пропозицій я нарешті натрапив на цю статтю під час читання цього блогу: https://datasciencelab.wordpress.com/2014/01/21/selection-of-k-in-k-means-clustering-reloaded/

Після цього я реалізував його в Scala, реалізація, яка для моїх випадків використання дає справді хороші результати. Ось код:

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 з вітром 0,12 і нак 1,3
eirirlar

Привіт @eirirlar Я намагаюся реалізувати той же код з Python - але я не міг слідувати за кодом на веб-сайті. Дивіться мій пост: stackoverflow.com/questions/36729826/python-k-means-clustering
piccolo

@ImranRashid Вибачте, що я протестував лише з двома вимірами, і я не експерт Python.
eirirlar

3

Якщо ви використовуєте MATLAB, будь-яку версію з 2013b, тобто ви можете скористатися функцією, evalclustersщоб дізнатися, яким повинен kбути оптимальний для даного набору даних.

Ця функція дозволяє вибрати один з 3 -х алгоритмів кластеризації - kmeans, linkageі gmdistribution.

Вона також дозволяє вибрати один з 4 кластеризації критеріїв оцінки - CalinskiHarabasz, DaviesBouldin, gapі silhouette.


3

Якщо ви не знаєте числа кластерів k, щоб надати в якості параметра k-значить, то є чотири способи автоматичного його пошуку:

  • Алгоритм G - означає: він автоматично виявляє кількість кластерів, використовуючи статистичний тест, щоб вирішити, розділити центр k-засобів на два. Цей алгоритм застосовує ієрархічний підхід до виявлення кількості кластерів на основі статистичного тесту гіпотези про те, що підмножина даних слідує за Гауссовим розподілом (безперервна функція, яка наближає точний біноміальний розподіл подій), а якщо ні, то він розбиває кластер . Він починається з невеликої кількості центрів, скажімо, лише один кластер (k = 1), потім алгоритм розбиває його на два центри (k = 2) і знову розбиває кожен з цих двох центрів (k = 4), маючи чотири центри в всього. Якщо G-засоби не приймають ці чотири центри, то відповідь - це попередній крок: два центри в цьому випадку (k = 2). Це кількість кластерів, на які буде розділений ваш набір даних. G-засоби дуже корисні, коли у вас немає оцінки кількості кластерів, які ви отримаєте після групування своїх примірників. Зауважте, що незручний вибір параметра "k" може дати неправильні результати. Викликається паралельна версія g-засобівр-значить . G-засоби джерела: джерело 1 джерело 2 джерело 3

  • x-означає : новий алгоритм, який ефективно шукає простір розташування кластерів та кількість кластерів для оптимізації Байєсівського критерію інформації (BIC) або інформаційного критерію Akaike (AIC). Ця версія k-засобів знаходить число k, а також прискорює k-засоби.

  • K-означає в Інтернеті або Streaming k-означає: він дозволяє виконувати k-засоби шляхом сканування всіх даних один раз і автоматично знаходить оптимальну кількість k. Іскра його реалізує.

  • Алгоритм MeanShift : це непараметрична техніка кластеризації, яка не вимагає попереднього знання кількості кластерів і не обмежує форму кластерів. Середнє кластерне зміщення має на меті виявити "краплі" в плавній щільності проб. Це алгоритм на основі центроїдів, який працює за допомогою оновлення кандидатів на центроїди як середнє значення точок у даній області. Ці кандидати потім фільтруються на етапі після обробки, щоб усунути майже дублікати, щоб утворити остаточний набір центроїдів. Джерела: source1 , source2 , source3


2

Я використав знайдене тут рішення: http://efavdb.com/mean-shift/, і воно дуже добре працювало для мене:

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

введіть тут опис зображення



1

Припускаючи, що у вас є матриця даних, що називається DATA, ви можете виконати розділення медоїдів з оцінкою кількості кластерів (шляхом аналізу силуетів) таким чином:

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

1

Одна з можливих відповідей - використовувати мета-евристичний алгоритм, як генетичний алгоритм, щоб знайти k. Це просто. ви можете використовувати випадковий K (у деякому діапазоні) та оцінити функцію придатності генетичного алгоритму за допомогою певного виміру, як «Силует» та «Найкраща база K» на функції підгонки.

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

ви вибираєте дані та бібліотеку, додаєте і скопіюєте km = [] у відсоток ': 2}) останнього та запускаєте пітон і бачите
sumit

Ласкаво просимо до переповнення стека! Хоча цей код може допомогти вирішити проблему, він не пояснює, чому та / або як він відповідає на питання. Забезпечення цього додаткового контексту суттєво покращило б його довгострокове навчальне значення. Будь ласка , змініть свій відповідь , щоб додати пояснення, в тому числі те , що застосовувати обмеження і допущення.
Toby Speight

1

Іншим підходом є використання карт самоорганізації (SOP) для пошуку оптимальної кількості кластерів. SOM (самоорганізовується карта) - це некерована методологія нейронної мережі, яка потребує лише вводу, який використовується для кластеризації для вирішення проблем. Цей підхід використано в роботі про сегментацію клієнтів.

Довідка статті є

Абдельлах Аміне та ін., Модель сегментації клієнтів в електронній комерції з використанням методів кластеризації та моделі LRFM: випадок Інтернет-магазинів у Марокко, Всесвітня академія науки, техніки та технологій Міжнародний журнал комп'ютерної та інформаційної інженерії Vol: 9, No: 8 , 2015, 1999 - 2010


0

Привіт, я спрощу це пояснити просто, мені подобається визначати кластери за допомогою бібліотеки 'NbClust'.

Тепер, як використовувати функцію 'NbClust' для визначення потрібної кількості кластерів: Ви можете перевірити фактичний проект у Github за допомогою фактичних даних та кластерів. Розширення цього алгоритму 'kmeans' також виконується за допомогою потрібної кількості 'центрів'.

Посилання на проект Github: https://github.com/RutvijBhutaiya/Thailand-Customer-Engagement-Facebook


Замість того, щоб додавати посилання github, чи можете ви додати пару ключових рядків коду, які можуть допомогти іншим, навіть якщо ваш код недоступний?
Джуліо Каччін

0

Ви можете вибрати кількість кластерів, візуально оглянувши свої точки даних, але незабаром зрозумієте, що в цьому процесі існує багато неоднозначності для всіх, крім найпростіших наборів даних. Це не завжди погано, тому що ви навчаєтесь без нагляду і в процесі маркування є якась властива суб'єктивність. Тут попередній досвід вирішення конкретної проблеми чи чогось подібного допоможе вам вибрати правильне значення.

Якщо ви хочете отримати деяку підказку щодо кількості кластерів, які ви повинні використовувати, ви можете застосувати метод Elbow:

Перш за все, обчисліть суму квадратичної помилки (SSE) для деяких значень k (наприклад, 2, 4, 6, 8 тощо). SSE визначається як сума квадратної відстані між кожним членом кластеру та його центроїдом. Математично:

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

Якщо ви побудуєте k проти SSE, ви побачите, що помилка зменшується в міру збільшення k; це тому, що коли кількість кластерів збільшується, вони повинні бути меншими, тому спотворення також менше. Ідея ліктьового методу полягає у виборі k, при якому SSE різко знижується. Це дає "ефект ліктя" на графіку, як ви бачите на наступному малюнку:

введіть тут опис зображення

У цьому випадку k = 6 - значення, вибране методом Elbow. Враховуйте, що метод «Лікоть» є евристичним і, як такий, він може чи не може працювати добре у вашому конкретному випадку. Іноді ліктя більше одного, або ліктя взагалі відсутнє. У таких ситуаціях ви, як правило, обчислюєте кращий k, оцінюючи ефективність k-засобів у контексті конкретної проблеми кластеризації, яку ви намагаєтеся вирішити.


0

Я працював над пакетом Python на колінах (алгоритм Kneedle). Він знаходить число кластера динамічно як точку, коли крива починає сплющуватися. Надаючи набір значень x і y, коліна повернуть точку коліна функції. Точка коліна - це точка максимальної кривизни. Тут є зразок коду.

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 = діапазон (1, len (y) +1)

від імпорту коліна KneeLocator kn = KneeLocator (x, y, крива = 'опукла', напрямок = 'зменшується')

друк (кн. кн.)


Будь ласка, додайте до своєї відповіді якесь пояснення, щоб інші могли дізнатися з нього
Ніко Хааз
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.