scikit-kmeans不是精确的成本惯性



我想得到k均值成本(scikit kmeans中的inertia)。只是提醒一下:

成本是从每个点到最近聚类的距离的平方和。

我发现scikit的成本计算("ertia")之间有一个奇怪的差异,
以及我自己计算成本的琐碎方法

请参阅以下示例:

p = np.random.rand(1000000,2)
from sklearn.cluster import KMeans
a = KMeans(n_clusters=3).fit(p)
print a.inertia_ , "****"
means = a.cluster_centers_
s = 0
for x in p:
    best = float("inf")
    for y in means:
        if np.linalg.norm(x-y)**2 < best:
            best = np.linalg.norm(x-y)**2
    s += best
print s, "*****"

对于我的运行,输出是:

66178.4232156 ****
66173.7928716 *****

在我自己的数据集上,结果更显著(相差20%)。
这是scikit实现中的一个错误吗?

First-这似乎不是一个bug(但肯定是丑陋的不一致)。为什么?您需要更仔细地了解代码实际在做什么。为此,它从_k_means.pyx 调用cython代码

(577-578行)

    inertia = _k_means._assign_labels_array(
        X, x_squared_norms, centers, labels, distances=distances)

它所做的基本上正是你的代码,但是。。。在C中使用使加倍。所以这可能只是一个数字问题?让我们测试您的代码,但现在,有了清晰的聚类结构(因此,没有可能分配给多个中心的点,这取决于数值精度)。

import numpy as np
from sklearn.metrics import euclidean_distances
p = np.random.rand(1000000,2)
p[:p.shape[0]/2, :] += 100 #I move half of points far away
from sklearn.cluster import KMeans
a = KMeans(n_clusters=2).fit(p) #changed to two clusters
print a.inertia_ , "****"
means = a.cluster_centers_
s = 0
for x in p:
    best = float("inf")
    for y in means:
        d = (x-y).T.dot(x-y)
        if d < best:
            best = d
    s += best
print s, "*****"

结果

166805.190832 ****
166805.190946 *****

有道理。因此,问题在于"边界附近"是否存在样本,根据算术精度,这些样本可能被分配给多个聚类。不幸的是,我无法准确地追踪差异的来源。

有趣的是实际上存在不一致性,因为inertia_字段填充了Cython代码,而.score调用NumPy一个。因此,如果您调用

print -a.score(p)

你会得到你的惯性。

相关内容

  • 没有找到相关文章

最新更新