0.我们导师的土味理解
均值聚类算法通俗解释
有一个黑社会,总共有10个人,分别是p1~p10,每个人都有智商,力量,情商,颜值四项打分。
现在要选两个大佬,
首先,p1与p2自高奋勇要当大佬,这时,其他人开始评估自己和两位大佬的各项差距,一部分人觉得他和p1差距较小,就成p1的小弟,另一部分人觉得和p2差距较小,就成了p2的小弟,
这时分别计算两群人各项属性的均值,获得的均值就成为虚拟的大佬v1和v2,这时拿v1 v2分别和p1 p2做比较,如果各项相等,就说明p1和p2确实是公认的大佬
如果不相等,就说明选的大佬不合适,再计算这群人和虚拟大佬v1 v2的差距,这时v1和v2就成为指定大佬,再计算每人和指定大佬的差距,推算出新的虚拟大老v3 v4,如果虚拟大佬与指定大佬相吻合,选举大佬结束,这样,10个人就分成两组,完成聚类。如果不吻合,继续选举。Kmeans算法(百度百科)
K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一。K-means算法的基本思想是:以空间中k个点为形心进行聚类,对最靠近他们的对象归类。通过迭代的方法,逐次更新各簇的形心的值,直至得到最好的聚类结果。(形心可以是实际的点、或者是虚拟点)
假设要把样本集分为c个簇,算法描述如下:
(1)适当选择c个簇的初始形心;
(2)在第k次迭代中,对任意一个样本,求其到c个形心的欧氏距离或曼哈顿距离,将该样本归类到距离最小的形心所在的簇;
(3)利用均值等方法更新该簇的形心值;
(4)对于所有的c个簇形心,如果利用(2)(3)的迭代法更新后,当形心更新稳定或误差平方和最小时,则迭代结束,否则继续迭代。(误差平方和即簇内所有点到形心的距离之和)
该算法的最大优势在于简洁和快速。算法的关键在于初始中心的选择和距离公式。
2.伪代码(我的理解)
'''随机选择k个初始质心while(true){计算每个点到最近距离的质心,归为该类。重新计算每个类的质心。if(质心与上一次质心一样or达到最大迭代次数)break;}'''
3.代码(Python 3 语言实现)
from numpy import *
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
#dataSet:聚类数据集
#k:指定的k个类(大佬)
def kmeans(dataSet, k):
#得到数据样本的维度n
sampleNum, col = dataSet.shape
#初始化为一个(k,n)的矩阵=簇
cluster = mat(zeros((sampleNum, 2)))
#生成全零阵
centroids = zeros((k, col))
#选择质心
for i in range(k):
#索引为随机生成的int类型的且在0-sampleNum间的数
index = int(random.uniform(0, sampleNum))
centroids[i, :] = dataSet[index, :]
#设置flag,查看聚类结果是否发生变化
clusterChanged = True
#只要聚类结果一直发生变化,就一直执行聚类算法,直至所有数据点聚类结果不变化
while clusterChanged:
#聚类结果变化布尔类型置为false
clusterChanged = False
#遍历数据集每一个样本向量
for i in range(sampleNum):
#使用sqrt函数(二分法)
minDist = sqrt(sum(power(centroids[0, :] - dataSet[i, :], 2)))
minIndex = 0
#计算点到质心的距离
for j in range(1,k):
distance = sqrt(sum(power(centroids[j, :] - dataSet[i, :], 2)))
#当前最小距离一定时,索引为J
if distance < minDist:
minDist = distance
minIndex = j
# 当前聚类结果中第i个样本的聚类结果发生变化:布尔类型置为true,继续聚类算法
if cluster[i, 0] != minIndex:
clusterChanged = True
#更新聚类结果和平方误差
cluster[i, :] = minIndex, minDist**2
#遍历每一个质心
for j in range(k):
#筛选出属于当前质心类的所有样本
pointsInCluster = dataSet[nonzero(cluster[:, 0].A == j)[0]]
#计算列的均值(使用axis=0:求列的均值)
centroids[j, :] = mean(pointsInCluster, axis = 0)
return centroids, cluster
#创建简单数据集以及进行可视化
dataSet = [[1,1],[3,1],[1,4],[2,5],[11,12],[14,11],[13,12],[11,16],[17,12],[28,10],[26,15],[27,13],[28,11],[29,15]]
dataSet = mat(dataSet)
k = 3
centroids, cluster = kmeans(dataSet, k)
sampleNum, col = dataSet.shape
mark = ['or', 'ob', 'og']
for i in range(sampleNum):
markIndex = int(cluster[i, 0])
plt.plot(dataSet[i, 0], dataSet[i, 1], mark[markIndex])
mark = ['+r', '+b', '+g']
for i in range(k):
plt.plot(centroids[i, 0], centroids[i, 1], mark[i], markersize=12)
plt.show()
简单可视化展示由于每次的K值是随机,所以可视化图不一需要注意的是: Kmeans中判断循环是否结束,应该就是判断第N次计算的聚类的中心点是否和原聚类中心点一致,但是有个问题,我用的Python语言,在做数值相等判断中(尤其是flaot类型时数据并不可能完全一致比如
),实际运算会因为小数点后的些许差距导致判断为Flase,所以应该有允许范围内的误差,这一点需要大家在实际应用中体验,在此不再一一赘述。
代码仅供交流。