模糊聚类的操作Ⅱ

152 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第15天,点击查看活动详情

先前我们实现了从数据集到模糊相似矩阵的转变。

有了相似矩阵,就引出了进一步的操作。

找一个等价矩阵,由等价矩阵实现划分。

我们的重点在于代码上的实现,具体的原理可以参考相关wiki。

模糊矩阵是从布尔矩阵推广得到的。

先前也说过,它把布尔代数的加法和乘法推广成了所谓的模糊乘法和模糊加法。

基于此,布尔矩阵的乘法也可以进一步的推广成为如下的形式:

def mul(a, b):
    c = np.zeros((a.shape[0], b.shape[1]))
    for i in range(a.shape[0]):
        for j in range(b.shape[1]):
            c[i, j] = np.max(np.minimum(a[i], b[:, j])) # 1
    return c

如果认为运算行的取最大最小值是或和与运算(注意它是兼容的),那么这里完全兼容布尔代数的。

现在由推广的两个操作,得到了一种新的类似矩阵乘法的运算。我们称之为极大极小复合运算

这个运算的用处在于另一个推广的操作:所谓的求传递闭包。

方法使用的是不断的求矩阵和自身极大极小复合运算,直到复合操作不再是矩阵变化,这个时候矩阵被成为传递闭包矩阵。

注意到它和布尔代数的相似性,我们猜测它应该也可以通过弗洛伊德算法计算传递闭包。

至少我们猜测当模糊矩阵退化成布尔矩阵时成立。

幸运的是,有人证明了这个过程的正确性,具体可以通过谷歌搜索相关内容。 所以我们最终可以实现一个相对高效的求传递闭包的办法,至少比不断地求自身复合的复杂度稳定。

代码如下:

def floyd_warshall(x: Tensor) -> Tensor:  # 计算传递闭包
    dp = x.clone()  # copy tensor
    n = len(x)
    for k in range(n):
        for i in range(n):
            for j in range(n):
                dp[i, j] = max(dp[i, j], min(dp[i, k], dp[k, j]))
    return dp