分层凝聚聚类:如何更新距离矩阵?

Posted

技术标签:

【中文标题】分层凝聚聚类:如何更新距离矩阵?【英文标题】:Hierarchical agglomerative clustering: how to update distance matrix? 【发布时间】:2020-01-23 21:34:17 【问题描述】:

我想根据伪代码实现简单的层次凝聚聚类:

我在需要更新距离矩阵的最后部分卡住了。到目前为止,我有:

import numpy as np

X = np.array([[1, 2],
              [0, 3],
              [2, 3],])

# Clusters
C = np.zeros((X.shape[0], X.shape[0]))

# Keeps track of active clusters
I = np.zeros(X.shape[0])

# For all n datapoints
for n in range(X.shape[0]):
    for i in range(X.shape[0]):
        # Compute the similarity of all N x N pairs of images
        C[n][i] = np.linalg.norm(X[n] - X[i])
        I[n] = 1

# Collects clustering as a sequence of merges
A = []
In each of N iterations
for k in range(X.shape[0] - 1):
    # TODO: Find the indices of the smallest distance
    #  Updated distance matrix

我想实现单链接聚类,所以我想找到距离矩阵的 argmin。我最初想过做这样的事情:

i, m = np.where(C == np.min(C[np.nonzero(C)]))
    i, m = i[0], m[0]
    A.append((i, m))

找到 argmin,但我认为它不正确,因为它没有指定 I 中的活动集群的条件。我也很困惑,因为我应该只查看矩阵的上三角形或下三角形,所以如果我使用上述方法,由于对称性,我可以两次获得相同的 argmin。

我也在考虑先创建新合并集群的行和列:

C = np.vstack((C, np.zeros((1, C.shape[1]))))
C = np.hstack((C, np.zeros((C.shape[0], 1))))

然后以某种方式更新它:

for j in range(X.shape[0]):
    C[i][j] = min(C[i][j], C[m][j])
    C[j][i] = min(C[i][j], C[m][j])

我不确定这是否是正确的方法。是否有更简单的方法来查找 argmin、合并行和列并更新值?

【问题讨论】:

【参考方案1】:

如果你对如何找到最小 dist 误差的行和列索引感到困惑,

首先,

为避免由于对称性而两次获得 argmin,您可以将初始距离矩阵构造为下三角矩阵的形状。

def euclidean_distance(p1,p2):
    return math.sqrt((p1[0]-p2[0])**2+(p1[1]-p2[1])**2)

distance_matrix = np.zeros((len(X.shape[0]),len(X.shape[0])))

for i in range(len(distance_matrix)):
    for j in range(i):
        distance_matrix[i][j] = euclidean_distance(X[i],X[j])

其次,

如果您不喜欢使用 np 工具或者您正在寻找一种简单的方法,您可以手动在给定的矩阵中进行最小搜索。

min_value = np.inf
for i in range(len(distance_matrix)):
    for j in range(i):
        if( distance_matrix[i][j] < min_value):
            min_value = distance_matrix[i][j]
            min_i = i
            min_j = j

最后,

更新距离矩阵并将集群合并为休耕:

for i in range(len(distance_matrix)):
    if( i > min_i  and i < min_j ):
        distance_matrix[i][min_i] = min(distance_matrix[i][min_i],distance_matrix[min_j][i])

    elif( i > min_j ):
        distance_matrix[i][min_i] = min(distance_matrix[i][min_i],distance_matrix[i][min_j])

for j in range(len(distance_matrix)):
    if( j < min_i ):
        distance_matrix[min_i][j] = min(distance_matrix[min_i][j],distance_matrix[min_j][j])

#remove one of the old clusters data from the distance matrix
distance_matrix = np.delete(distance_matrix, min_j, axis=1)
distance_matrix = np.delete(distance_matrix, min_j, axis=0)

A[min_i] = A[min_i] + A[min_j] 
A.pop(min_j)

【讨论】:

以上是关于分层凝聚聚类:如何更新距离矩阵?的主要内容,如果未能解决你的问题,请参考以下文章

凝聚法层次聚类之ward linkage method

使用 DTW 距离矩阵的凝聚聚类

高维数据的聚类小记

sklearn 具有距离链接准则的凝聚聚类

凝聚聚类层次可视化

如何使用 PHP 从距离矩阵中获取集群?