一、基本原理
将m个样本数据分为K个簇(类别)
每个类别至少有一个样本
流程:
1、首先人为给定k个簇中心(你想分几类),簇中心可以理解为各个类别的代表(一般是随机初始化的) ------随机挑几个代表
2、逐个计算每个样本到簇中心的距离,把离簇中心距离近的归为一类。-------先随波逐流
3、计算每个簇内的均值,更新簇中心。-------换能力强的代表
4、循环迭代步骤3直到达标。-------------不断选出能力更强的代表,直到带领的团队业绩达标
动态演示:
问题来了业绩是否达标看什么?
损失函数:
∑ i = 0 n min μ j ∈ C ( ∣ ∣ x i − μ j ∣ ∣ 2 ) \sum\limits_{i=0}^{n}\underset{\mu_j \in C}\min(||x_i - \mu_j||^2) i=0∑nμj∈Cmin(∣∣xi−μj∣∣2)
-
其中 μ j = 1 ∣ C j ∣ ∑ x ∈ C j x \mu_j = \frac{1}{|C_j|}\sum\limits_{x \in C_j}x μj=∣Cj∣1x∈Cj∑x是簇的均值向量,或者说是质心。
-
其中 ∣ ∣ x i − μ j ∣ ∣ 2 ||x_i - \mu_j||^2 ∣∣xi−μj∣∣2代表每个样本点到均值点的距离(其实也是范数)。
意思就是:团队足够团结—>平均水平就提高—>业绩提高
优缺点:
优点:简单、快速、适用于常规的数据集
缺点:k值难确定、对异常值敏感、对初始值敏感(初始的代表,不同的初始代表将演变成最终不同的团队)、对某些分布聚类效果不好
上面这种簇分布情况就不适合用kmeans,kmeans会把它聚类成:(基于距离)
二、代码实现并展示效果演示
参考:
手敲实现kmeans
三、Kmeans的评估指标
Kmeans一开始要人为的给定一个k值,但对于样本是什么样的分布我们并不清楚,此时要怎么确定一个合适的k值?
指定不同的k值,看根据评估指标的优劣来选择合适的k值。
1、轮廓系数
针对某个样本的轮廓系数s为:
s
=
b
−
a
m
a
x
(
a
,
b
)
s= \frac{b - a}{max(a, b)}
s=max(a,b)b−a
a:某个样本与其所在簇内其他样本的平均距离------->是否团结
b:某个样本与其他簇样本的平均距离--------->与其它对于越不同,越特别
当a = 0,时,S = 1。说明,S越接近1聚类的效果越好!
聚类总的轮廓系数SC为: S C = 1 N ∑ i = 1 N s i SC = \frac{1}{N}\sum\limits_{i = 1}^Ns_i SC=N1i=1∑Nsi,所有样本的 s i s_i si的均值称为聚类结果的轮廓系数,是该聚类是否合理、有效的度量。
代码:
import numpy as np
from sklearn import datasets
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from sklearn.metrics import silhouette_score #轮廓系数
import warnings
warnings.filterwarnings("ignore")
# 创建数据
# 假数据,数据X划分成3类
plt.figure(figsize=(8,4))
X,y = datasets.make_blobs(centers=3)
plt.scatter(X[:,0],X[:,1],c = y)
# 指定不同的k,寻找最佳聚类类别数目
plt.rcParams['font.family'] = 'STKaiti'
plt.rcParams["font.size"]= 20
plt.figure(figsize=(4,3))
scores = []
for k in range(2,7):
keams = KMeans(n_clusters=k)
keams.fit(X)
y_pre = keams.predict(X)
score = silhouette_score(X,y_pre)
scores.append(score)
plt.plot(range(2,7),scores,color='green')
index = np.argmax(scores)
plt.scatter(range(2,7)[index],scores[index],color='red',s=50)
print("轮廓系数最大的k值:",range(2,7)[index])
plt.xticks(np.arange(2, 7, step=1))
plt.xlabel("K值")
plt.ylabel("轮廓系数",c='red')
轮廓系数最大的k值: 3
2、兰德系数
RI = a + b C 2 n s a m p l e s \text{RI} = \frac{a + b}{C_2^{n_{samples}}} RI=C2nsamplesa+b
用C表示实际的类别划分,K表示聚类结果。
定义a 为在C中被划分为同一类,在K中被划分为同一簇的实例对数量。
定义b为在C中被划分为不同类别,在K中被划分为不同簇的实例对数量。
兰德系数范围是[0,1]
调整兰德系数为:
ARI = RI − E [ RI ] max ( RI ) − E [ RI ] \text{ARI} = \frac{\text{RI} - E[\text{RI}]}{\max(\text{RI}) - E[\text{RI}]} ARI=max(RI)−E[RI]RI−E[RI]
范围为[-1,1]
代码:
#用调整兰德系数选k值
from sklearn.metrics import adjusted_rand_score# 调整兰德系数
score = []
plt.figure(figsize=(4,3))
for i in range(2,7):
kmeans = KMeans(n_clusters=i)
kmeans.fit(X)
y_ = kmeans.predict(X)# 预测类别 == 标签
score.append(adjusted_rand_score(y,y_))
plt.plot(range(2,7),score)
plt.xticks(np.arange(2, 7, step=1))
plt.xlabel('K值')
plt.ylabel('调整兰德系数',c = 'red')