You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在基于Z-score矩阵的KMeans聚类中同时检测相关性与反相关性?

解决KMeans无法识别反相关聚类的问题

我明白你的需求——标准KMeans基于欧氏距离计算相似度,只会把数值完全匹配的行(比如你示例里的前两行)归为一类,但你希望它能识别出反相关的行(比如符号完全相反的向量),把这类行也划分到同一聚类中。下面我会给你几个实用的解决方案,附代码示例:

为什么标准KMeans做不到?

标准KMeans用欧氏距离衡量样本间的相似度,反相关向量的欧氏距离会非常大(比如你示例里的[0,-1,1,0]和[0,1,-1,0],欧氏距离是√[(0)^2 + (-2)^2 + (2)^2 + 0] = √8),远大于相同向量的距离(0),所以KMeans会把它们分到不同簇。


解决方案1:将向量转换为“规范形式”

最简单的思路是把反相关的向量转换成完全相同的形式,这样标准KMeans就能直接处理。比如我们可以为每个向量定义一个“规范版本”:让向量的第一个非零元素为正,如果原向量第一个非零元素是负的,就取它的相反数。

代码示例

import numpy as np
from sklearn.cluster import KMeans

# 你的示例数据
X = np.array([
    [0, -1, 1, 0],
    [0, -1, 1, 0],
    [0, 1, -1, 0],
    [1, 1, -1, -1],
    [-1, -1, 1, 1]
])

# 定义向量规范化函数
def normalize_vector(row):
    # 找到第一个非零元素的位置
    first_non_zero_idx = np.argmax(row != 0)
    # 如果第一个非零元素为负,取向量的相反数
    if row[first_non_zero_idx] < 0:
        return -row
    return row

# 转换所有向量为规范形式
X_normalized = np.array([normalize_vector(row) for row in X])
print("转换后的矩阵:\n", X_normalized)

# 用标准KMeans聚类
kmeans = KMeans(n_clusters=2, random_state=42)
cluster_labels = kmeans.fit_predict(X_normalized)

print("\n聚类结果标签:", cluster_labels)

结果说明

转换后,原反相关的[0,-1,1,0]会变成[0,1,-1,0],和第三行完全一致;[-1,-1,1,1]会变成[1,1,-1,-1],和第四行一致。最终KMeans会把前3行归为一类,后2行归为一类,完全符合你的需求。

优缺点

  • ✅ 简单快速,直接兼容标准KMeans
  • ❌ 依赖第一个非零元素的符号,如果数据存在噪声导致第一个非零元素不稳定,可能影响结果

解决方案2:基于余弦相似度的聚类

余弦相似度衡量的是向量的方向相似性,相同方向的向量余弦相似度为1,反方向的为-1。我们可以基于余弦相似度的绝对值来定义距离(即忽略符号差异),再用支持自定义距离的聚类算法(比如层次聚类或谱聚类)来实现。

方法2a:层次聚类+自定义距离

import numpy as np
from sklearn.cluster import AgglomerativeClustering
from sklearn.metrics.pairwise import cosine_distances

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

# 自定义距离:1 - |余弦相似度|(余弦相似度=1 - cosine_distances)
def cosine_abs_distance(X):
    cosine_sim = 1 - cosine_distances(X)
    return 1 - np.abs(cosine_sim)

# 计算距离矩阵
distance_matrix = cosine_abs_distance(X)

# 用层次聚类
cluster = AgglomerativeClustering(n_clusters=2, affinity='precomputed', linkage='average')
cluster_labels = cluster.fit_predict(distance_matrix)

print("聚类结果标签:", cluster_labels)

方法2b:谱聚类(适合复杂数据)

谱聚类基于相似度矩阵进行聚类,能更好地处理非线性的聚类结构:

import numpy as np
from sklearn.cluster import SpectralClustering
from sklearn.metrics.pairwise import cosine_distances

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

# 构建相似度矩阵:取余弦相似度的绝对值
similarity_matrix = np.abs(1 - cosine_distances(X))

# 谱聚类
spectral = SpectralClustering(n_clusters=2, affinity='precomputed', random_state=42)
cluster_labels = spectral.fit_predict(similarity_matrix)

print("聚类结果标签:", cluster_labels)

优缺点

  • ✅ 更通用,不依赖向量的元素位置,直接基于方向判断
  • ❌ 层次聚类和谱聚类的计算复杂度比KMeans高,大数据集下速度较慢

总结

如果你的数据量不大,解决方案1是最便捷的选择;如果数据复杂或希望更通用的方向匹配,解决方案2会更合适。这两种方法都能让聚类算法识别出反相关的行,把它们归为同一聚类。

内容的提问来源于stack exchange,提问作者JVonKorff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:13:06