kmeans的算法原理其实很简单
我用一个最简单的二维散点图来做解释
如上图,我们直观的看到该图可聚成两个分类,我们分别用红点和蓝点表示
下面我们模拟一下Kmeans是怎么对原始的二维散点图做聚类的
首先,随机初始化2个聚类中心,至于什么是聚类中心呢,我们暂且压下不表,现在就把它当成一个点就好。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SK81vA5t-1636722491932)(C:Usersli554AppDataRoamingTyporatypora-user-imagesimage-20211112203412124.png)]
然后我们就去把所有离红色点进的样本点标成红色,把离蓝色点近的样本点标成蓝色
然后我们重新设定聚类中心的位置,设在哪呢。红色聚类中心就设在现在的红色点的中心(均值),蓝色聚类中心就设在现在的蓝色点的中心(均值),样本颜色重新设为黑色
然后我们继续把所有离红色点进的样本点标成红色,把离蓝色点近的样本点标成蓝色
其实我们现在看来,红色和蓝色已经很分明了,已经达到最初的效果了,但是机器没有我们的眼睛,机器没办法直观的看到现在已经可以停止了。
所以它会继续按照计算均值的方法重新设定聚类中心
然后继续把所有离红色点进的样本点标成红色,把离蓝色点近的样本点标成蓝色
然后继续按照计算均值的方法重新设定聚类中心,但到这里机器会发现我们设定的聚类中心和之前的聚类中心的位置几乎没有改变,这说明我们的算法收敛了,每个样本的类别基本已经确定了。于是算法终止,聚类完成
算法步骤-
选定K个聚类中心
-
计算每个样本点到K个聚类中心的距离,将样本添加到距离最小的聚类中心对应的分类中
-
计算每个分类集合的样本均值,并将其作为新的聚类中心
-
重复2,3步骤,直到新的聚类中心与原聚类中心的距离小于设定的阈值即可
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
class KMeans:
def __init__(self, k, threshold):
self.k = k
self.threshold = threshold
def train(self, X):
# 初始化聚类中心
# 随机选取K个样本作为聚类中心
self.centers = X[np.random.choice(X.shape[0], size=self.k)]
while True:
# 按照聚类中心分类
clusters = []
for i in range(self.k):
clusters.append([])
for i, x in enumerate(X):
# clusters之所以存的是样本索引而不是样本本身是为了减小空间损耗
clusters[self.predict(x)].append(i)
new_centers = self.centers.copy()
# 计算新的聚类中心
for i, cluster in enumerate(clusters):
new_centers[i] = X[cluster].mean()
# 如果聚类中心基本没有变化,那么终止
if np.max(np.abs(new_centers - self.centers)) < self.threshold:
break
# 否则更新聚类中心,重复上述步骤
self.centers = new_centers
# 返回聚类结果
y_pred = np.zeros(shape=(X.shape[0],))
for cluster_index, cluster in enumerate(clusters):
for i in cluster:
y_pred[i] = cluster_index
return y_pred
def predict(self, x):
dis = []
# 计算每个样本与中心的距离
for c in self.centers:
dis.append(np.linalg.norm(x - c))
# 将样本索引添加到距离最小的中心对应的分类中
return np.argmin(dis)
def main():
model = KMeans(3, 1e-2)
X, y = make_blobs(n_samples=1000, n_features=2, centers=3)
y_pred = model.train(X)
plt.scatter(X[:, 0], X[:, 1], c=y)
plt.show()
plt.scatter(X[:, 0], X[:, 1], c=y_pred)
plt.show()
main()
优化改进
好讲完Kmeans算法,我们再想一想Kmeans算法有什么问题.
聚类中心初始化看下面两张图,它是上面的程序偶尔可能运行出来的结果,左边是原数据,右边是聚类的数据
虽然聚类出来的数据非常的分明,但是它跟原数据的分布是极度不吻合的,这其实是聚类中心初始化的问题。
比如我们前面介绍的例子,假如我们的聚类中心是在这个地方
于是,绿线下方都被分到红色,绿线上方都分到蓝色,我们一求均值,重新设定聚类中心,发现位置也没有太大改变,于是我们得到的聚类就是这样的
也很分明,但是显然不是我们希望的聚类
那么这个问题怎么解决,也就是说,随机初始化聚类中心是不好的。
。。。待补充。。。



