Utilizzo di BIC per stimare il numero di k in KMEANS


13

Attualmente sto provando a calcolare il BIC per il mio set di dati giocattolo (ofc iris (:). Voglio riprodurre i risultati come mostrato qui (Fig. 5). Quel documento è anche la mia fonte per le formule BIC.

Ho 2 problemi con questo:

  • Notazione:
    • ni = numero di elementi nel clusteri
    • Ci = coordinate centrali del clusteri
    • xj = punti dati assegnati al clusteri
    • m = numero di cluster

1) La varianza come definita nell'Eq. (2):

i=1nimj=1nixjCi2

Per quanto posso vedere, è problematico e non coperto che la varianza possa essere negativa quando ci sono più cluster m rispetto agli elementi nel cluster. È corretto?

2) Non riesco proprio a far funzionare il mio codice per calcolare il BIC corretto. Speriamo che non ci siano errori, ma sarebbe molto apprezzato se qualcuno potesse controllare. L'intera equazione può essere trovata nell'Eq. (5) nel documento. Sto usando Scikit Learn per tutto in questo momento (per giustificare la parola chiave: 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")

I miei risultati per il BIC si presentano così:

Il che non è nemmeno vicino a quello che mi aspettavo e non ha nemmeno senso ... Ho guardato le equazioni ormai da un po 'di tempo e non riesco più a localizzare il mio errore):


È possibile trovare il calcolo di BIC per il clustering qui . È come lo fa SPSS. Non necessariamente esattamente nello stesso modo in cui lo mostri.
ttnphns,

Grazie ttnphns. Ho visto la tua risposta prima. Ma questo non ha alcun riferimento su come vengono derivati ​​i passaggi e quindi non su ciò che stavo cercando. Inoltre, questo output SPSS o qualunque sia la sintassi non è molto leggibile. Grazie lo stesso. A causa della mancanza di interesse per queste domande cercherò il riferimento e userò un'altra stima per la varianza.
Kam Sen,

So che questo non risponde alla tua domanda (quindi la lascio come commento), ma il pacchetto R mclust si adatta ai modelli di miscela finita (un metodo di raggruppamento parametrico) e ottimizza automaticamente il numero, la forma, le dimensioni, l'orientamento e l'eterogeneità dei cluster. Capisco che stai usando sklearn ma volevo solo buttarlo lì.
Brash Equilibrium,

1
Brash, sklearn ha anche GMM
eyaler

@KamSen puoi aiutarmi per favore qui? : - stats.stackexchange.com/questions/342258/…
Pranay Wankhede

Risposte:


14

Sembra che tu abbia alcuni errori nelle tue formule, come determinato confrontando con:

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

Qui ci sono tre errori nel documento, la quarta e la quinta riga mancano di un fattore d, l'ultima riga sostituisce m con 1. Dovrebbe essere:

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)

dovrebbe essere:

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

3.

La formula della varianza:

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

dovrebbe essere uno scalare:

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.

Usa i log naturali, invece dei log di base10.

5.

Infine, e soprattutto, il BIC che stai elaborando ha un segno inverso rispetto alla definizione normale. quindi stai cercando di massimizzare anziché minimizzare


1
Per citare, in BIC_notes ( https://github.com/bobhancock/goxmeans/blob/master/doc/BIC_notes.pdf ), la derivazione da (21) a (22) ha ottenuto il segno di sbagliato. Il codice nella risposta più votata è corretto. MK(ϕ)2
Mikoyan,

@eyaler puoi per favore correggermi qui? : - stats.stackexchange.com/questions/342258/…
Pranay Wankhede

puoi collegare un documento o scrivere questo in markup matematico?
donlan,

Vedi la mia domanda correlata qui: stats.stackexchange.com/questions/374002/…
rnso

@ Seanny123 ed eyaler, vedi post stats.stackexchange.com/questions/374002/… da rnso. Questa formula fornisce circa 9 cluster sui dati dell'iride che dovrebbero avere 3 cluster
Bernardo Braga

11

Questa è fondamentalmente la soluzione di eyaler, con alcune note .. L'ho appena digitata se qualcuno voleva una copia / incolla veloce:

Appunti:

  1. Il 4 ° commento di eyalers è errato np.log è già un log naturale, non sono necessarie modifiche

  2. Il 5 ° commento di eyalers sull'inverso è corretto. Nel codice seguente, stai cercando il MASSIMO: tieni presente che l'esempio ha numeri BIC negativi

Il codice è il seguente (di nuovo, tutto il merito a 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

Guardando github.com/bobhancock/goxmeans/blob/master/doc/BIC_notes.pdf potresti spiegare come questa formula BIC sta ottimizzando per il MASSIMO? Potresti mostrare il minimo e spiegare cosa fa nel linguaggio verbale? trovando difficile interpretare la formula
user305883

Vedi la mia domanda correlata qui: stats.stackexchange.com/questions/374002/…
rnso

1
sembra che ci sia un bug nella formula. Qualcuno è riuscito a risolverlo?
STiGMa,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.