scikit kmeans不准确的成本\惯性

时间:2016-01-12 23:16:13

标签: python numpy machine-learning scikit-learn k-means

我想获得k-means费用(inertia in scikit kmeans)。 提醒一下:

成本是从每个点到最近的集群的平方距离之和。

我在scikit的成本计算('惯性')之间得到了一个奇怪的区别,
和我自己琐碎的计算成本的方法

请参阅以下示例:

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实施中的一个错误吗?

1 个答案:

答案 0 :(得分:2)

首先 - 它似乎不是一个错误(但肯定是丑陋的不一致)。这是为什么?您需要仔细研究代码实际执行的内容。为了这个通用目的,它调用来自_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)

你将完全惯性