Використання BIC для оцінки кількості k у KMEANS


13

В даний час я намагаюся обчислити BIC для мого набору даних про іграшки (ofc iris (:). Я хочу відтворити результати, як показано тут (рис. 5). Цей документ також є моїм джерелом для формул BIC).

У мене є 2 проблеми з цим:

  • Позначення:
    • ni = кількість елементів кластераi
    • Ci = центральні координати кластераi
    • xj = точки даних, призначені кластеруi
    • m = кількість кластерів

1) Дисперсія, визначена у рівнянні. (2):

i=1nimj=1nixjCi2

Наскільки я бачу, це проблематично і не охоплено, що дисперсія може бути негативною, коли в кластері є більше кластерів m ніж елементів. Це правильно?

2) Я просто не можу змусити свій код працювати для обчислення правильного BIC. Сподіваємось, помилок немає, але було б дуже вдячно, якби хтось міг перевірити. Ціле рівняння можна знайти у рівнянні. (5) у статті. Я використовую scikit learn для всього зараз (щоб виправдати ключове слово: P).

from sklearn import cluster
from scipy.spatial import distance
import sklearn.datasets
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import numpy as np

def compute_bic(kmeans,X):
    """
    Computes the BIC metric for a given clusters

    Parameters:
    -----------------------------------------
    kmeans:  List of clustering object from scikit learn

    X     :  multidimension np array of data points

    Returns:
    -----------------------------------------
    BIC value
    """
    # assign centers and labels
    centers = [kmeans.cluster_centers_]
    labels  = kmeans.labels_
    #number of clusters
    m = kmeans.n_clusters
    # size of the clusters
    n = np.bincount(labels)
    #size of data set
    N, d = X.shape

    #compute variance for all clusters beforehand
    cl_var = [(1.0 / (n[i] - m)) * sum(distance.cdist(X[np.where(labels == i)], [centers[0][i]], 'euclidean')**2)  for i in xrange(m)]

    const_term = 0.5 * m * np.log10(N)

    BIC = np.sum([n[i] * np.log10(n[i]) -
           n[i] * np.log10(N) -
         ((n[i] * d) / 2) * np.log10(2*np.pi) -
          (n[i] / 2) * np.log10(cl_var[i]) -
         ((n[i] - m) / 2) for i in xrange(m)]) - const_term

    return(BIC)



# IRIS DATA
iris = sklearn.datasets.load_iris()
X = iris.data[:, :4]  # extract only the features
#Xs = StandardScaler().fit_transform(X)
Y = iris.target

ks = range(1,10)

# run 9 times kmeans and save each result in the KMeans object
KMeans = [cluster.KMeans(n_clusters = i, init="k-means++").fit(X) for i in ks]

# now run for each cluster the BIC computation
BIC = [compute_bic(kmeansi,X) for kmeansi in KMeans]

plt.plot(ks,BIC,'r-o')
plt.title("iris data  (cluster vs BIC)")
plt.xlabel("# clusters")
plt.ylabel("# BIC")

Мої результати для BIC виглядають приблизно так:

Що навіть не є близьким до того, що я очікував, а також не має сенсу ... Я деякий час дивився на рівняння і не отримую жодного подальшого визначення моєї помилки):


Ви можете знайти обчислення BIC для кластеризації тут . Це так, як це робить SPSS. Не обов’язково точно так само, як ви показуєте.
ttnphns

Дякую ttnphns. Раніше я бачив вашу відповідь. Але це не має посилання на те, як здійснюються кроки, і, отже, не те, що я шукав. Більше того, цей вихід SPSS або будь-який синтаксис не дуже читабельний. В будь-якому випадку, дякую. Через відсутність інтересу до цих питань я шукаю посилання та використовую іншу оцінку для дисперсії.
Kam Sen

Я знаю, що це не відповідає на ваше запитання (тому я залишаю це як коментар), але пакет Rc mclust підходить для кінцевих моделей сумішей (параметричний метод кластеризації) і автоматично оптимізує кількість, форму, розмір, орієнтацію та неоднорідність кластерів. Я розумію, ти використовуєш sklearn, але просто хотів це викинути.
Brash Equilibrium

1
Brash, sklearn також має GMM
eyaler

@KamSen чи можете ви мені тут допомогти? : - stats.stackexchange.com/questions/342258/…
Pranay Wankhede

Відповіді:


14

Здається, у ваших формулах є кілька помилок, визначених порівнянням із:

1.

np.sum([n[i] * np.log(n[i]) -
               n[i] * np.log(N) -
             ((n[i] * d) / 2) * np.log(2*np.pi) -
              (n[i] / 2) * np.log(cl_var[i]) -
             ((n[i] - m) / 2) for i in range(m)]) - const_term

Тут у роботі є три помилки, у четвертому та п’ятому рядках відсутній фактор d, останній рядок замінить m на 1. Це має бути:

np.sum([n[i] * np.log(n[i]) -
               n[i] * np.log(N) -
             ((n[i] * d) / 2) * np.log(2*np.pi*cl_var) -
             ((n[i] - 1) * d/ 2) for i in range(m)]) - const_term

2.

Const_term:

const_term = 0.5 * m * np.log(N)

має бути:

const_term = 0.5 * m * np.log(N) * (d+1)

3.

Формула дисперсії:

cl_var = [(1.0 / (n[i] - m)) * sum(distance.cdist(p[np.where(label_ == i)], [centers[0][i]], 'euclidean')**2)  for i in range(m)]

має бути скаляром:

cl_var = (1.0 / (N - m) / d) * sum([sum(distance.cdist(p[np.where(labels == i)], [centers[0][i]], 'euclidean')**2) for i in range(m)])

4.

Використовуйте натуральні журнали замість ваших журналів base10.

5.

Нарешті, і найголовніше, що BIC, який ви обчислюєте, має зворотний знак від звичайного визначення. тому ви шукаєте максимізацію, а не мінімізацію


1
Відзначимо, у BIC_notes ( https://github.com/bobhancock/goxmeans/blob/master/doc/BIC_notes.pdf ) походження від (21) до (22) отримало знак неправильно. Код у відповіді з найбільшою оцінкою є правильним. MK(ϕ)2
Мікоян

@eyaler, будь ласка, виправте мене тут? : - stats.stackexchange.com/questions/342258/…
Pranay Wankhede

Ви можете зв'язати папір або написати це в математичній розмітці?
donlan

Дивіться моє відповідне запитання тут: stats.stackexchange.com/questions/374002/…
rnso

@ Seanny123 та eyaler див. Пост stats.stackexchange.com/questions/374002/… від rnso. Ця формула дає близько 9 кластерів за даними райдужки, які повинні мати 3 кластери
Бернардо Брага

11

Це в основному рішення електронної пошти, з кількома примітками. Я просто набрав це, якщо хтось хотів швидкої копії / вставки:

Примітки:

  1. eyalers 4 коментар невірний np.log - це вже природний журнал, зміни не потрібні

  2. еялєри 5-й коментар про зворотну правильний. У наведеному нижче коді ви шукаєте МАКСИМАЛЬНИЙ - майте на увазі, що приклад має негативні номери BIC

Код наступний (знову ж, весь кредит для eyaler):

from sklearn import cluster
from scipy.spatial import distance
import sklearn.datasets
from sklearn.preprocessing import StandardScaler
import numpy as np

def compute_bic(kmeans,X):
    """
    Computes the BIC metric for a given clusters

    Parameters:
    -----------------------------------------
    kmeans:  List of clustering object from scikit learn

    X     :  multidimension np array of data points

    Returns:
    -----------------------------------------
    BIC value
    """
    # assign centers and labels
    centers = [kmeans.cluster_centers_]
    labels  = kmeans.labels_
    #number of clusters
    m = kmeans.n_clusters
    # size of the clusters
    n = np.bincount(labels)
    #size of data set
    N, d = X.shape

    #compute variance for all clusters beforehand
    cl_var = (1.0 / (N - m) / d) * sum([sum(distance.cdist(X[np.where(labels == i)], [centers[0][i]], 
             'euclidean')**2) for i in range(m)])

    const_term = 0.5 * m * np.log(N) * (d+1)

    BIC = np.sum([n[i] * np.log(n[i]) -
               n[i] * np.log(N) -
             ((n[i] * d) / 2) * np.log(2*np.pi*cl_var) -
             ((n[i] - 1) * d/ 2) for i in range(m)]) - const_term

    return(BIC)



# IRIS DATA
iris = sklearn.datasets.load_iris()
X = iris.data[:, :4]  # extract only the features
#Xs = StandardScaler().fit_transform(X)
Y = iris.target

ks = range(1,10)

# run 9 times kmeans and save each result in the KMeans object
KMeans = [cluster.KMeans(n_clusters = i, init="k-means++").fit(X) for i in ks]

# now run for each cluster the BIC computation
BIC = [compute_bic(kmeansi,X) for kmeansi in KMeans]

print BIC

Дивлячись на github.com/bobhancock/goxmeans/blob/master/doc/BIC_notes.pdf, чи можете ви пояснити, як ця BIC формула оптимізується для МАКСИМАЛЬНОГО? Чи можете ви показати мінімум та пояснити, що це робить у словесній мові? що важко інтерпретувати формулу
user305883

Дивіться моє відповідне запитання тут: stats.stackexchange.com/questions/374002/…
rnso

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