Как определить 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-means: расширение K- средних с эффективной оценкой числа кластеров» Дана Пеллега и Эндрю Мура в ICML 2000.

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

Наконец, вы можете начать с одного кластера, а затем продолжать разбивать кластеры, пока точки, назначенные каждому кластеру, не будут иметь гауссово распределение. В «Изучение k в k- средних» (NIPS 2003) Грег Хамерли и Чарльз Элкан показывают некоторые доказательства того, что это работает лучше, чем BIC, и что BIC недостаточно сильно наказывает за сложность модели.

Вебьорн Лёса
источник
Отличный ответ! Что касается X-средних, знаете ли вы, если общая оценка BIC n: = k * 2 (k кластеров, каждый кластер моделируется по Гауссу с параметрами среднего / дисперсии). Также, если вы определите «родительский» BIC> «2 дочерних» BIC, вы когда-нибудь снова разделите этот кластер в следующей итерации?
Будрик
2
@Budric, это, вероятно, должны быть отдельные вопросы, и, возможно, на stats.stackexchange.com.
Вебьорн Лёса
37

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

Как всегда в анализе данных, не существует единственного правильного подхода, который работал бы лучше всех остальных во всех случаях. В конце концов, вы должны принять собственное суждение. Для этого полезно построить график зависимости числа кластеров от средней дисперсии (что предполагает, что вы уже запустили алгоритм для нескольких значений k ). Тогда вы можете использовать количество кластеров в колене кривой.

Ян Крюгер
источник
24

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

Так что другой вариант - использовать Silhouette Method, чтобы найти его. Результат от Silhouette полностью соответствует результату метода Elbow в R.

Вот что я сделал.

#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
Просто добавьте ссылку на учебник Silhouette Analysis для пользователей 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-средних». Он использует тест Гаусса, чтобы определить правильное количество кластеров. Кроме того, авторы утверждают, что этот метод лучше, чем BIC, который упоминается в принятом ответе.

автономный
источник
7

Есть нечто, называемое «Правило большого пальца». Это говорит о том, что количество кластеров может быть рассчитано

k = (n/2)^0.5

где n - общее количество элементов в вашем образце. Вы можете проверить достоверность этой информации на следующей бумаге:

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

Существует также другой метод, называемый G-means, где ваше распределение следует распределению по Гауссу или нормальному распределению. Он состоит из увеличения k до тех пор, пока все ваши k групп не будут следовать распределению Гаусса. Это требует много статистики, но может быть сделано. Вот источник:

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

Надеюсь, это поможет!

Артур Бускейро
источник
3

Сначала создайте минимальное связующее дерево ваших данных. Удаление K-1 самых дорогих ребер разделяет дерево на K кластеров,
так что вы можете построить MST один раз, посмотреть на расстояния / метрики кластеров для различных K и взять колено кривой.

Это работает только для Single-linkage_clustering , но для этого это быстро и просто. Кроме того, 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]]
}
eirirlar
источник
Внесено в Scala 2.11.7 с ветерком 0,12 и Nak 1,3
Eirirlar
Привет @eirirlar Я пытаюсь реализовать тот же код с Python - но я не мог следовать код на веб-сайте. Смотрите мой пост: stackoverflow.com/questions/36729826/python-k-means-clustering
piccolo
@ImranRashid Извините, я тестировал только 2 измерения, и я не эксперт по Python.
Эйрирлар
3

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

Эта функция позволяет выбрать один из 3 -х алгоритмов кластеризации - kmeans, linkageи gmdistribution.

Она также позволяет выбрать один из 4 кластеризации критериев оценки - CalinskiHarabasz, DaviesBouldin, gapи silhouette.

Kristada673
источник
3

Если вы не знаете номера кластеров k, которые должны быть представлены в качестве параметра для k-средних, есть четыре способа найти его автоматически:

  • Алгоритм G-средних: он обнаруживает количество кластеров автоматически, используя статистический тест, чтобы решить, следует ли разбивать центр k-средних на два. Этот алгоритм использует иерархический подход для определения количества кластеров, основанный на статистическом тесте для гипотезы о том, что подмножество данных следует гауссову распределению (непрерывная функция, которая приближается к точному биномиальному распределению событий), и, если нет, разделяет кластер. , Он начинается с небольшого числа центров, скажем, только один кластер (k = 1), затем алгоритм разбивает его на два центра (k = 2) и снова разбивает каждый из этих двух центров (k = 4), имея четыре центра в общее количество. Если G-среднее не принимает эти четыре центра, то ответом является предыдущий шаг: два центра в этом случае (k = 2). Это количество кластеров, на которые будет разделен ваш набор данных. G-means очень полезен, когда у вас нет оценки количества кластеров, которые вы получите после группировки ваших экземпляров. Обратите внимание, что неудобный выбор параметра «k» может привести к неверным результатам. Параллельная версия g-средних называетсяр-значит . Источники G-средних: источник 1, источник 2, источник 3

  • x-означает : новый алгоритм, который эффективно ищет пространство местоположений кластеров и количество кластеров для оптимизации байесовского критерия информации (BIC) или показателя информационного критерия Акаике (AIC). Эта версия k-средних находит число k, а также ускоряет k-средние.

  • K-средства онлайн или потоковые k-средства: он позволяет выполнить k-средства путем сканирования всех данных один раз и автоматически находит оптимальное число k. Spark реализует это.

  • Алгоритм MeanShift : это непараметрическая методика кластеризации, которая не требует предварительного знания количества кластеров и не ограничивает форму кластеров. Кластеризация по среднему сдвигу направлена ​​на обнаружение «пятен» в гладкой плотности образцов. Это алгоритм, основанный на центроидах, который работает, обновляя кандидатов на центроиды, чтобы они были средними точками в данном регионе. Эти кандидаты затем фильтруются на этапе последующей обработки, чтобы исключить почти дубликаты, чтобы сформировать окончательный набор центроидов. Источники: источник1 , источник2 , источник3

curiosus
источник
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 (в некотором диапазоне) и оценить функцию подбора Генетического алгоритма с помощью некоторого измерения, такого как Silhouette And Find best 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})
Sumit
источник
вы выбираете данные и добавляете библиотеку и копируете km = [] в Percentage ': 2}) last и запускаете свой python и видите
sumit
Добро пожаловать в стек переполнения! Хотя этот код может помочь решить проблему, он не объясняет, почему и / или как он отвечает на вопрос. Предоставление этого дополнительного контекста значительно улучшило бы его долгосрочную образовательную ценность. Пожалуйста, измените свой ответ, чтобы добавить объяснение, в том числе какие ограничения и предположения применяются.
Тоби Спейт
1

Другой подход заключается в использовании самоорганизующихся карт (SOP) для нахождения оптимального количества кластеров. SOM (самоорганизующаяся карта) - это методология нейронной сети без надзора, для которой требуется только вход, используемый для кластеризации для решения проблем. Этот подход используется в статье о сегментации клиентов.

Ссылка на статью

Абделла Амин и др., Модель сегментации клиентов в электронной торговле с использованием методов кластеризации и модели LRFM: пример интернет-магазинов в Марокко, Всемирная академия наук, инженерии и технологии Международный журнал по вычислительной технике и информатике, том 9, № 8 , 2015, 1999 - 2010

boyaronur
источник
0

Привет, я сделаю это просто и понятно, мне нравится определять кластеры, используя библиотеку 'NbClust'.

Теперь, как использовать функцию «NbClust» для определения правильного количества кластеров: вы можете проверить фактический проект в Github с фактическими данными и кластерами - расширение этого алгоритма «kmeans» также выполняется с использованием правильного количества «центров».

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

Rutvij
источник
Вместо добавления ссылки на github, можете ли вы добавить пару ключевых строк кода, которые могут помочь другим, даже если ваш код недоступен?
Джулио Качинь
0

Вы можете выбрать количество кластеров, визуально осмотрев свои точки данных, но вскоре вы поймете, что в этом процессе много неопределенности для всех, кроме самых простых наборов данных. Это не всегда плохо, потому что вы занимаетесь обучением без присмотра, и в процессе маркировки есть некоторая внутренняя субъективность. Здесь, имея предыдущий опыт решения этой конкретной проблемы или чего-то подобного, вы сможете выбрать правильное значение.

Если вы хотите получить некоторую подсказку о количестве кластеров, которые вам следует использовать, вы можете применить метод Elbow:

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

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

Если вы построите график k по отношению к SSE, вы увидите, что ошибка уменьшается с увеличением k; Это связано с тем, что когда количество кластеров увеличивается, они должны быть меньше, поэтому искажения также меньше. Идея метода локтя состоит в том, чтобы выбрать k, при котором SSE резко уменьшается. Это создает «эффект локтя» на графике, как вы можете видеть на следующем рисунке:

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

В этом случае k = 6 - это значение, выбранное методом Elbow. Примите во внимание, что метод Elbow является эвристическим и, как таковой, он может или не может хорошо работать в вашем конкретном случае. Иногда бывает больше одного локтя или совсем нет локтя. В этих ситуациях вы обычно заканчиваете тем, что вычисляете наилучшее k, оценивая, насколько хорошо k-means работает в контексте конкретной проблемы кластеризации, которую вы пытаетесь решить.

Фейсал Шахбаз
источник
0

Я работал над пакетным пакетом Python (алгоритм Kneedle). Он находит номер кластера динамически как точку, где кривая начинает выравниваться. При заданном наборе значений x и 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]

х = диапазон (1, лен (у) +1)

из коленного импорта KneeLocator kn = KneeLocator (x, y, кривая = «выпуклая», направление = «убывающая»)

печать (kn.knee)

мадхури м
источник
Пожалуйста, добавьте пояснения к своему ответу, чтобы другие могли извлечь из него урок
Нико Хаасе