K-means 算法原理
程序员文章站
2022-07-14 19:22:24
...
1. 聚类
K-means算法是一种常用的聚类算法,所谓的聚类就是指给定个样本的数据集,需要构造 个簇(类),使得这 个簇之间的关系最小。
2. K-means算法基本步骤
- 随机初始化个点,作为聚类中心
- 在第次迭代中,对于每个样本点,选取距离最近的聚类中心,归为该类
- 遍历一遍之后,更新聚类中心,其中更新规则为:聚类中心取当前类的平均值
- 重复步骤2、3,直到满足迭代次数,或者聚类状态不发生改变
3. 算法优化
3.1 轮廓系数
轮廓系数(Silhouette Coefficient)结合了聚类的凝聚度(Cohesion)和分离度(Separation),用于评估聚类的效果。该值处于之间,值越大,表示聚类效果越好。具体计算方法如下:
- 对于每个样本点,计算点与其同一个簇内的所有其他元素距离的平均值,记作,用于量化簇内的凝聚度。
- 选取i外的一个簇,计算与中所有点的平均距离,遍历所有其他簇,找到最近的这个平均距离,记作,即为的邻居类,用于量化簇之间分离度。
- 对于样本点 ,轮廓系数
- 计算所有i的轮廓系数,求出平均值即为当前聚类的整体轮廓系数,度量数据聚类的紧密程度
3.2 K值的选择
方法一:轮廓系数法
可以通过枚举的方法,令 从 到 (随便的一个固定值,但不能太大),对于每一个 值进行 K-means 算法,然后取轮廓系数最大的那个 作为最终聚类的簇的数目。
方法二:误差平方和法
定义误差平方和公式如下:
其中 是第 个簇,其中 是 簇 的样本, 是第 个簇的聚类中心
随着聚类数 的增大,样本划分会更加精细,每个簇的聚合程度会逐渐提高,那么误差平方和SSE自然会逐渐变小。并且,当k小于真实聚类数时,由于的增大会大幅增加每个簇的聚合程度,故SSE的下降幅度会很大,而当到达真实聚类数时,再增加所得到的聚合程度回报会迅速变小,所以SSE的下降幅度会骤减,然后随着值的继续增大而趋于平缓,也就是说SSE和的关系图是一个手肘的形状,而这个肘部对应的值就是数据的真实聚类数。–转自手肘法理论
3.3 初始点的选择
- 从给定的样本集合中随机选择一个样本作为第一个聚类中心
- 然后对于样本集合中的每一个样本点 ,计算离该样本与最近的聚类中心的距离
- 概率的选择D(x)较大的点作为新的样本中心
- 重复步骤2和3,直到聚类中心达到 个为止
4. 代码
以鸢尾花数据为例,下面是k-means的代码
import numpy as np
import matplotlib.pyplot as plt
from sklearn.datasets import load_iris
# 加载数据
def loadData():
iris = load_iris()
#print(iris)
X = np.array(iris.data[:])
#print(X.shape)
# 以鸢尾花后两个特征作为聚类特征
# plt.scatter(X[:, 2], X[:, 3], c="red", marker='o', label='two features')
# plt.xlabel('petal length')
# plt.ylabel('petal width')
# plt.legend(loc=2)
# plt.show()
return X[:,2:]
# 第一次随机获取k个中心点
def getCenterPoints(X, k):
m, n = X.shape
centerPoints = np.zeros((k, n))
for i in range(k):
id = int(np.random.uniform(0, m))
centerPoints[i, :] = X[id, :]
return centerPoints
#得到两个数据点之间的欧氏距离
def getDis(x, y):
return np.sqrt(np.sum((x - y) **2 ))
# k-means算法
def KMeans(X, k):
m = X.shape[0]
cluster = np.mat(np.zeros((m, 2)))
#1. 随机获取中心点
centerPoints = getCenterPoints(X, k)
for times in range(100):
for i in range(m):
minDist, minID = 1000000.0, -1
for j in range(k):
dis = getDis(X[i, :], centerPoints[j, :])
if dis < minDist:
minDist, minID = dis, j
#2.对于每个样本点,选取最近的中心点,归为该类
cluster[i, :] = minID, minDist**2
#3. 更新中心点
for i in range(k):
pointsInCluster = X[np.nonzero(cluster[:, 0].A == i)[0]] # 获取簇类所有的点
centerPoints[i, :] = np.mean(pointsInCluster, axis=0) # 对矩阵的行求均值
return centerPoints, cluster
#对聚类好的数据进行画图
def showCluster(X, k, cluster, centerPoints):
m = X.shape[0]
mark = ['or', 'ob', 'og']
for i in range(m):
markIndex = int(cluster[i, 0])
plt.plot(X[i, 0], X[i, 1], mark[markIndex])
mark = ['Dr', 'Db', 'Dg']
# 绘制中心点
for i in range(k):
plt.plot(centerPoints[i, 0], centerPoints[i, 1], mark[i])
plt.show()
def main():
X, k = loadData(), 3
centerPoints, cluster = KMeans(X, k)
showCluster(X, k, cluster, centerPoints)
if __name__ == '__main__':
main()
分类效果:
上一篇: 混合属性聚类算法——以汽车属性为维度进行对汽车车型进行聚类 java实现
下一篇: 机器学习总结