k-means 聚类中使用余弦距离 cos distance

本文在 知乎 发布

k-means 聚类算法中使用欧氏距离作为判别标准,本文讨论使用余弦距离作为判别的方法和理论基础。

先说结论:使用欧氏距离聚类结果等价于使用余弦距离聚类结果

首先看余弦的计算 ,

可以看做两个归一化后的单位向量的内积,同时理解对样本向量进行归一化并不改变余弦距离的计算。

而在欧氏距离的计算中,

如果向量已经是单位向量,那么

也即使用余弦距离和使用欧氏距离进行判别的聚类结果是等价。

所以使用余弦距离进行聚类的方式是先将样本进行归一化,然后使用常规方法和工具(如 scikit-learn)进行计算。

余下的问题则是余弦聚类的中心和距离怎么计算?

对于维度为 m 的 n 个样本

求样本余弦中心 使得

其中

把问题等价重写为目标

和约束

则使用 Lagrange multiplier 方法有,

于是 , 令

推出

带回约束条件中,由

得到

于是

至此,就得到了余弦中心的计算方法。

注意到这个余弦中心向量的方向和模长并没有关系,这也和余弦距离的特性相符合。

当对样本进行归一化,同时假定余弦中心向量归一化后,

即余弦中心为欧氏中心归一化后的结果

附:使用 scikit-learn 进行计算的代码

# 归一化
nm = np.sqrt((X**2).sum(axis=1))[:,None]
X = X / nm

kmeans = KMeans(n_clusters=2, random_state=0).fit(X)

# 其实也是在计算归一化
mm = np.sqrt(np.square(kmeans.cluster_centers_).sum(axis=1)[:,None])
cos_centers = kmeans.cluster_centers_ / mm

distance = 1 - np.dot(cos_centers, X.T)