使用BIC估算KMEANS中的k个数


13

我目前正在尝试为我的玩具数据集(ofc iris(:))计算BIC。我想重现如图所示的结果(图5)。该论文也是我BIC公式的来源。

我对此有2个问题:

  • 符号:
    • ni =群集的元素数i
    • Ci =群集中心坐标i
    • xj =分配给群集数据点i
    • m =簇数

1)方程式中定义的方差 (2):

i=1nimj=1nixjCi2

据我所知,这是有问题的,并且当簇m大于簇中的元素时,方差可能为负。它是否正确?

2)我只是无法使我的代码能够计算出正确的BIC。希望没有错误,但是如果有人可以检查,将不胜感激。整个方程可以在等式中找到。(5)在论文中。我现在正在使用scikit学习所有内容(以证明关键字: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 2014年

谢谢ttnphns。我之前看过你的答案。但这与步骤的派生方式无关,因此与我所寻找的无关。此外,此SPSS输出或任何语法都不十分可读。不管怎样,谢谢你。由于对此问题缺乏兴趣,我将寻找参考并使用其他估计作为方差。
甘森

我知道这不能回答您的问题(因此,我将其作为评论),但是R包mclust适合有限的混合模型(一种参数化聚类方法),并自动优化聚类的数量,形状,大小,方向和异质性。我了解您正在使用sklearn,但只想将其扔在那里。
垃圾平衡

1
Brash,sklearn也有GMM
eyaler 2015年

@KamSen您可以在这里帮助我吗?: - stats.stackexchange.com/questions/342258/...
Pranay Wankhede

Answers:


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 '18

请在此处查看我的相关问题:stats.stackexchange.com/questions/374002/…–
rnso

@ Seanny123和eyaler请参阅rnso的poststats.stackexchange.com/questions/374002/…。该公式在虹膜数据上给出了大约9个群集,应该具有3个群集
Bernardo Braga

11

这基本上是eyaler的解决方案,带有一些注释。.如果有人想要快速复制/粘贴,我只是打了一下:

笔记:

  1. eyalers第四条注释不正确np.log已经是自然日志,无需更改

  2. eyalers关于逆的第五条评论是正确的。在下面的代码中,您正在寻找MAXIMUM-请记住该示例的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公式如何针对MAXIMUM优化吗?您能显示最低要求并用口头语言解释吗?发现难以解释该公式
user305883 '18

请在此处查看我的相关问题:stats.stackexchange.com/questions/374002/…–
rnso

1
公式中似乎有一个错误。有没有人设法修复它?
STiGMa
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.