1. 聚类概念
一种典型的无监督学习算法,主要用于将相似的样本自动归到一个类别中。
在聚类算法中根据样本之间的相似性,将样本划分到不同的类别中,对于不同的相似度计算方法,会得到不同的聚类结果,常用的相似度计算方法有欧式距离法。
聚类算法和分类算法最大的区别是:聚类是无监督学习算法,而分类算法是监督学习算法。
2. 聚类算法的实现流程
- 随机选择 K 个样本点作为初始聚类中心
- 计算每个样本到 K 个中心的距离,选择最近的聚类中心点作为标记类别
- 根据每个类别中的样本点,重新计算出新的聚类中心点(平均值)
- 如果计算得出的新中心点与原中心点一样则停止聚类
- 否则重新进行第 2 步过程,直到聚类中心不再变化
3. K-means算法
k-means其实包含两层内容:
- K : 初始中心点个数(计划聚类数)
- means:求中心点到其他数据点距离的平均值
通过下图解释实现流程:
代码实现:
# 1 导入模块和包
import matplotlib.pyplot as plt
from sklearn.datasets import make_blobs
from sklearn.cluster import KMeans
from sklearn.metrics import calinski_harabasz_score,silhouette_score
# 2 生成数据
X, y = make_blobs(n_samples=1000, n_features=2, centers=[
[-1, -1], [0, 0], [1, 1], [2, 2]], cluster_std=[0.4, 0.2, 0.2, 0.2], random_state=9)
# 3 数据可视化
plt.figure(figsize=(20, 8),dpi=100)
plt.scatter(X[:,0],X[:, 1])
plt.show()
用K-means算法对模型进行训练,设置不同的中心点,查看输出结果
当n_clusters = 2 时:
# 1、模型训练
y_pre = KMeans(n_clusters = 2).fit_predict(X)
# 2、图形展示
plt.figure(figsize=(20, 8),dpi=100)
plt.scatter(X[:,0],X[:, 1],c=y_pre)
plt.show()
# 3、模型评估
calinski_harabasz_score(X, y_pre)
输出结果:3116.1706763322227
当n_clusters = 3 时:
# 1、模型训练
y_pre = KMeans(n_clusters = 3).fit_predict(X)
# 2、图形展示
plt.figure(figsize=(20, 8),dpi=100)
plt.scatter(X[:,0],X[:, 1],c=y_pre)
plt.show()
# 3、模型评估
calinski_harabasz_score(X, y_pre)
输出结果:2931.543778093064
当n_clusters = 4 时:
# 1、模型训练
y_pre = KMeans(n_clusters = 4).fit_predict(X)
# 2、图形展示
plt.figure(figsize=(20, 8),dpi=100)
plt.scatter(X[:,0],X[:, 1],c=y_pre)
plt.show()
# 3、模型评估
calinski_harabasz_score(X, y_pre)
输出结果:5924.050613480169
4 评估方法
4.1 聚类效果评估标准
- 簇内内聚程度如何
- 簇外分离程度如何
- 簇内越内聚,簇外越分散越好
4.2 误差平方和SSE
评估公式:
S
S
E
=
∑
i
=
1
k
∑
p
∈
C
i
∣
p
−
m
i
∣
2
SSE=\sum_{i=1}^{\mathrm{k}} \sum_{p \in C_{i}}\left|p-m_{i}\right|^{2}
SSE=i=1∑kp∈Ci∑∣p−mi∣2
- 考虑簇内的内聚程度
- k 表示质心的个数
- p 表示某个簇内的样本
- m 表示质心点
- SSE 的值越大说明聚类效果越不好
先计算一个簇内所有点到质心的距离平方和,再对所有簇距离平方和求和。
公式内各部分内容:
上图中: k=2
SSE图最终的结果,对图松散度的衡量:(eg: SSE(左图)<SSE(右图))
SSE随着聚类迭代,其值会越来越小,直到最后趋于稳定。
注意:SSE算法内质心的选取时随机的,因此,在质心选取时,当两个质心初始距离较近时,可能产生不好的结果,因此SSE最后的结果是局部内最优解,而不是全局最优解。如下图所示:
- 如果质心的初始值选择不好,SSE只会达到一个不怎么好的局部最优解
代码实现:
# 1、创建空列表
sse_list = []
# 2、设置中心点个数,查看SSE的变化范围
for clu_num in range(1, 100):
# 初始化迭代器一次的Kmeans
my_kmeans = KMeans(n_clusters=clu_num, max_iter=100, random_state=0)
# 模型训练
my_kmeans.fit(X)
# 将SSE的每一次迭代结果添加到空列表内
sse_list.append(my_kmeans.inertia_)
# 3、图像可视化
plt.figure(figsize=(20, 8), dpi=100)
plt.scatter(range(1, 100), sse_list)
plt.plot(range(1, 100), sse_list)
x_ticks = range(1, 100, 2)
plt.xticks(x_ticks)
plt.xlabel('中心点个数')
plt.ylabel('误差平方和')
plt.grid()
plt.show()
从上图可得: 当中心点个数为4时,SSE系数达到最大值,聚合效果最好
4.3 轮廓系数法(Silhouette Coefficient)
轮廓系数法考虑簇内的内聚程度,簇外的分离程度。其计算过程如下:
-
计算每一个样本 i 到同簇内其他样本的平均距离 a,该值越小,说明簇内的相似程度越大
-
计算每一个样本 i 到最近簇 j 内的所有样本的平均距离 b,该值越大,说明该样本越不属于其他簇 j
-
根据下面公式计算该样本的轮廓系数:
s = b − a max ( a , b ) s=\frac{b-a}{\max (a, b)} s=max(a,b)b−a -
计算所有样本的平均轮廓系数
-
轮廓系数的范围为:[-1, 1],值越大聚类效果越好
代码实现:
# 1、创建空列表
sc_list = []
# 2、设置中心点个数,查看SC的变化范围
for clu_num in range(2, 100):
# 初始化迭代器一次的Kmeans
my_kmeans = KMeans(n_clusters=clu_num, max_iter=100, random_state=0)
# 模型训练
my_kmeans.fit(X)
# 将SC的每一次迭代结果添加到空列表内
sc_list.append(silhouette_score(X, y_pre))
# 3、图像可视化
plt.figure(figsize=(20, 8), dpi=100)
plt.scatter(range(2, 100), sc_list)
plt.plot(range(2, 100), sc_list)
x_ticks = range(1, 100, 2)
plt.xticks(x_ticks)
plt.xlabel('中心点个数')
plt.ylabel('轮廓系数')
plt.grid()
plt.show()
从上图可得: 当中心点个数为4时,SC系数达到最大值,聚合效果最好
4.4 CH 系数
CH 系数考虑簇内的内聚程度、簇外的离散程度、质心的个数
类别内部数据的距离平方和越小越好,类别之间的距离平方和越大越好。
C
H
(
k
)
=
S
S
B
S
S
W
m
−
k
k
−
1
S
S
W
=
∑
i
=
1
m
∥
x
i
−
C
p
i
∥
2
S
S
B
=
∑
j
=
1
k
n
j
∥
C
j
−
X
ˉ
∥
2
\begin{array}{l} \mathrm{CH}(\mathrm{k})=\frac{S S B}{S S W}\frac{m-k}{k-1} \\ \\ S S W=\sum_{i=1}^{m}\left\|x_{i}-C_{p i}\right\|^{2} \\ S S B=\sum_{j=1}^{k} n_{j}\left\|C_{j}-\bar{X}\right\|^{2} \end{array}
CH(k)=SSWSSBk−1m−kSSW=∑i=1m∥xi−Cpi∥2SSB=∑j=1knj∥∥Cj−Xˉ∥∥2
SSW 的含义:
- Cpi 表示质心
- xi 表示某个样本
- SSW 值是计算每个样本点到质心的距离,并累加起来
- SSW 表示表示簇内的内聚程度,越小越好
SSB 的含义:
- Cj 表示质心,X 表示质心与质心之间的中心点,nj 表示样本的个数
- SSB 表示簇与簇之间的分离程度,SSB 越大越好
-
m 表示样本数量
-
k 表示质心个数
从以上公式可知:当质心越少,CH越大;SSB越大,说明簇与簇越分散,CH越大;SSW越小,簇内越聚集,CH越大。
代码实现:
# 1、创建空列表
CH_list = []
# 2、设置中心点个数,查看CH的变化规律
for clu_num in range(2, 100):
# 初始化迭代器一次的Kmeans
my_kmeans = KMeans(n_clusters=clu_num, max_iter=100, random_state=0)
# 模型训练
y_pre = my_kmeans.fit_predict(X)
# # 将CH的每一次迭代结果添加到空列表内
CH_list.append(calinski_harabasz_score(X, y_pre))
# 3、图像可视化
plt.figure(figsize=(20, 8), dpi=100)
plt.scatter(range(2, 100), CH_list)
plt.plot(range(2, 100), CH_list)
x_ticks = range(1, 100, 2)
plt.xticks(x_ticks)
plt.xlabel('中心点个数')
plt.ylabel('CH系数')
plt.grid()
plt.show()
从上图可得: 当中心点个数为4时,CH系数达到最大值,聚合效果最好
4.5肘方法
“肘” 方法通过 SSE 确定 n_clusters 的值
- 对于n个点的数据集,迭代计算 k from 1 to n,每次聚类完成后计算 SSE
- SSE 是会逐渐变小的,因为每个点都是它所在的簇中心本身。
- SSE 变化过程中会出现一个拐点,下降率突然变缓时即认为是最佳 n_clusters 值。
- 在决定什么时候停止训练时,肘形判据同样有效,数据通常有更多的噪音,在增加分类无法带来更多回报时,我们停止增加类别。