在sklearn的KMeans中找到平均欧几里得距离和使用inertia_有什么区别?

数据挖掘 Python scikit-学习 聚类 k-均值
2021-09-26 06:07:58

在使用肘部方法确定 K-Means 的最佳聚类数时,我在网上找到了两种不同的方法。

一种方法是使用以下代码:

distortions_2.append(sum(np.min(cdist(data,
                                      kmeanModel.cluster_centers_,
                                      'euclidean'),
                                axis = 1)) / data.shape[0])

在此处输入图像描述

另一种是使用来自 sklearn.cluster.KMeans 的惯性_:

distortions_3.append(kmeanModel.inertia_)

在此处输入图像描述

当我绘制结果(使用相同的随机状态)时,两者都会给出不同的结果,但我不确定有什么区别,有人可以帮忙吗?

编辑:如果我按照下面的建议将归一化因子 / data.shape[0] 替换为平方 **2,那么我仍然没有得到与惯性图相同的结果:

distortions_2.append(sum(np.min(cdist(data, 
                                      kmeanModel.cluster_centers_, 
                                      'euclidean'), 
                                axis = 1)) ** 2)

使用 squared 只会使情节更平滑一些,但绝对与使用 intertia_ 不同,我只是不太确定惯性_ 是如何计算的以及它的含义。

1个回答

您会注意到惯性是每个点与其最近的聚类中心之间的平方距离之和。因此,通过删除归一化项/ data.shape[0]并用平方替换它,**2这两个表达式将是等价的

distortions_2.append(sum(np.min(cdist(data
                              , kmeanModel.cluster_centers_
                              , 'euclidean')
                              , axis = 1)) **2)

distortions_2.append(kmeanModel.inertia_)

例如,使用这个人工数据源,我们生成 5 个高斯分布,每个分布有 300 个点。

params = [[[ 0,1],  [ 0,1]], 
          [[ 5,1],  [ 5,1]], 
          [[-2,5],  [ 2,5]],
          [[ 2,1],  [ 2,1]],
          [[-5,1],  [-5,1]]]

n = 300
dims = len(params[0])

data = []
y = []
for ix, i in enumerate(params):
    inst = np.random.randn(n, dims)
    for dim in range(dims):
        inst[:,dim] = params[ix][dim][0]+params[ix][dim][1]*inst[:,dim]
        label = ix + np.zeros(n)

    if len(data) == 0: data = inst
    else: data = np.append( data, inst, axis= 0)
    if len(y) == 0: y = label
    else: y = np.append(y, label)

num_clusters = len(params)

在此处输入图像描述

然后我们将使用不同数量的集群应用 KMeans

k = [1,2,3,4,5,6,7,8,9,10]

inertias = []
dists = []

for i in k:
    kmeans = KMeans(i)
    kmeans.fit(data)
    inertias.append(kmeans.inertia_)
    dists.append(sum(np.min(spatial.distance.cdist(data, kmeans.cluster_centers_, 'euclidean'), axis=1)**2))

plt.plot(range(1, len(inertias)+1), inertias, label = 'Inertia')
plt.plot(range(1, len(dists)+1), dists, label = 'Distance')
plt.legend()
plt.show()

在此处输入图像描述