模糊聚类的操作Ⅲ

132 阅读2分钟

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

前面的传递闭包是为了得到一个模糊等价关系。举个具体的例子:

对于某个模糊相似矩阵,通过前面的传递闭包就可以得到一个这样的关系矩阵。

[
[1,0.3,0.6],
[0.3,1,0.9],
[0.6,0.9,1]
]

它具有自反性对称性传递性,我们称之为模糊等价矩阵。

而我们知道在布尔代数中,等价关系是可以用来划分集合。如果能把这里理论应用到模糊等价矩阵,那我们就可以实现聚类操作了。

为此我们引入一个称之为 λ 截取操作。把所有的大于λ的值取1,小于λ的值取0。

具体的代码操作可能更清晰:

(x > 0.7).astype(int)

这里我们相当于让λ取值为0.7。

由此矩阵变成了这样:

[[1 0 0]
 [0 1 1]
 [0 1 1]]
 

可以发现一个神奇的现象,模糊等价矩阵便成了一个严格的等价关系。

由此我们可以将第一行和第二、三分类成两个类别。 这就是我们的聚类操作。

可以发现这里λ任取皆可实现分类操作。

不同的取值之间的区别是什么呢?答案就在得到的等价划分矩阵中。

其中的不同的值让我们在取λ的值时有了不同的结果。

因此将不同值各试一遍可以得到相应的不同结果的聚类输出。

这个过程就被称之为动态聚类。

幸运的是 numpy 中自带了一些好用的方法让我们做这件事。 比如通过 unique 运算得到λ的待取值列表。

然后之间通过上述的比较操作得到等价关系。

最后再由等价关系得到聚类结果即可。

最终我们可以写出如下操作:

def get_class(x: Tensor) -> Tuple[Set[Tuple[str]], Tensor]:
    return {tuple(f'x_{i + 1}' for i, v in enumerate(line) if v) for line in x}, x  # for readable format


def classify(x: Tensor): # 
    mark = np.unique(x)
    # st.write(mark)
    return [[i, *get_class((x >= i).astype(int))] for i in mark]  # i is lambda λ