首页 > 编程笔记 > Python笔记 阅读:41

k均值聚类算法(非常详细,附带实例)

k 均值聚类算法是一种迭代求解的聚类分析算法。

在各种聚类算法中,k 均值聚类算法可以说是最简单的。但是简单不代表不好用,k 均值聚类算法绝对是在聚类中用的最多的算法。

k 均值聚类算法的工作原理是,假设数据集中的样本因为特征不同,像小沙堆一样散布在地面上,k 均值算法会在小沙堆上插上旗子。而第一遍插的旗子并不能很完美地代表沙堆的分布,所以 k 均值还要继续,让每个旗子能够插到每个沙堆最佳的位置上,也就是数据点的均值上,这也是k均值聚类算法名字的由来。接下来一直重复上述的动作,直到找不出更好的位置。

k均值聚类算法步骤

k 均值聚类算法的步骤如下:
  1. 输入 k 的值,即我们希望将数据集经过聚类得到 k 分组;
  2. 从数据集中随机选择 k 个数据点作为初始聚类中心,对任意一个样本点,求其到 k 个聚类中心的距离,将样本点归类到距离最小的中心的聚类,如此迭代 n 次;
  3. 每次迭代过程中,利用均值等方法更新各个聚类的中心点;
  4. 对 k 个聚类中心,利用步骤 2 和步骤 3 迭代更新后,如果位置点变化很小,则认为达到稳定状态,对不同的聚类块和聚类中心可选择不同的颜色标注。

在实际应用中,由于 k 均值一般用于数据预处理或者用于辅助分类贴标签。所以 k 的值一般不会设置很大。

对于 k 值的选取,一般采用以下两种方法。

1) 手肘法

手肘法的核心指标是 SSE(sum of the squared errors,误差平方和)。聚类数 k 增大,数据划分就会更精细,每个簇的聚合程度也会提高,从而 SSE 会逐渐变小:
由此可见,SSE 和 k 的关系图是一个手肘的形状,而这个肘部对应的 k 值就是数据的真实聚类数。

具体做法是让 k 从 1 开始取值直到取到你认为合适的上限,对每个 k 值进行聚类并记下对应的 SSE,然后画出 k 和 SSE 的关系图,最后选取肘部对应的 k 作为最佳聚类数。

对葡萄酒数据集 wine.data,用 sklearn 库中自带的 k 均值算法对 k 值的选取进行可视化操作,如下图所示。


图 1 手肘图

2) 轮廓系数法

轮廓系数(silhouette coefficient)是簇的密集与分散程度的评价指标:
轮廓系数的值在 -1 和 1 之间,该值越接近于 1,簇越紧凑,聚类越好。当轮廓系数接近 1 时,簇内紧凑,并远离其他簇。其中,轮廓系数的计算如下所示:

k均值聚类算法优缺点

经过以上分析,可总结出k均值聚类算法的优缺点。

k 均值聚类算法的优点主要表现在:
k均值聚类算法的缺点主要表现在:

k均值聚类算法实战

下面直接通过实例来演示 k 均值的实战过程。

【实例】利用 k 均值聚类算法对给定篮球运动员比赛数据进行聚类。
from sklearn.cluster import Birch #从sklearn.cluster机器学习聚类包中导入Birch聚类
from sklearn.cluster import KMeans #从sklearn.cluster机器学习聚类包中导入KMeans聚类
"""
数据集:
X表示二维矩阵数据,篮球运动员比赛数据
总共20行,每行两列数据
第一列表示球员每分钟助攻数:x1
第二列表示球员每分钟得分数:x2
"""
X = [[0.0888,0.5885],[0.1399,0.8291],[0.0747,0.4974],[0.0983,0.5772],[0.1276,0.5703],
[0.1671,0.5835],[0.1906,0.5276],[0.1061,0.5523],[0.2446,0.4007],[0.1670,0.4770],
[0.2485,0.4313],[0.1227,0.4909],[0.1240,0.5668],[0.1461,0.5113],[0.2315,0.3788],
[0.0494,0.5590],[0.1107,0.4799],[0.2521,0.2735],[0.1007,0.6318],[0.1067,0.4326],
[0.1456,0.8280]
]
"""
k均值聚类
clf = KMeans(n_clusters = 3)表示类簇数为3,聚成3类数据,clf即赋值为KMeans
y_pred = clf.fit_predict(X)载入数据集X,并且将聚类的结果赋值给y_pred
"""
clf = KMeans(n_clusters = 3) #聚类算法,参数n_clusters = 3,聚成3类
y_pred = clf.fit_predict(X) #直接对数据进行聚类,聚类不需要进行预测
#输出完整k均值函数,包括很多省略参数
print('k均值模型:\n',clf)
#输出聚类预测结果,20行数据,每个y_pred对应X一行或一个球员,聚成3类,类标为0、1、2
print('聚类结果:\n',y_pred)

"""
可视化绘图
Python导入Matplotlib包,专门用于绘图
import matplotlib.pyplot as plt此处as相当于重命名,plt用于显示图像
"""
import numpy as np
import matplotlib.pyplot as plt
% matplotlib inline

plt.rcParams['font.sans-serif'] = ['SimHei']  #显示中文
#获取第一列和第二列数据使用for循环获取n[0]表示X第一列
x1 = [n[0]for n in X]
x2 = [n[1]for n in X]
#绘制散点图——参数:x横轴y纵轴c = y_pred聚类预测结果marker类型o表示圆点 * 表示
#星形x表示点
plt.scatter(x1,x2,c = y_pred,marker = 'x')
#绘制标题
plt.title("k均值篮球数据")
#绘制x轴和y轴坐标
plt.xlabel("x1")
plt.ylabel("x2")
#显示图形
plt.show()
运行程序,输出如下:
k均值模型:
KMeans(algorithm = 'auto',copy_x = True,init = 'k-means ++ ',max_iter = 300,
    n_clusters = 3,n_init = 10,n_jobs = 1,precompute_distances = 'auto',
    random_state = None,tol = 0.0001,verbose = 0)
聚类结果:
[0 1 0 0 0 0 0 0 2 0 2 0 0 0 2 0 0 2 0 0 1]
效果如下图所示:


图 3 篮球数据聚类效果

小批量k均值算法

小批量 k 均值是 k 均值算法的一个变体,它使用小批量(mini-batch)来减少计算时间,同时仍然尝试优化相同的目标函数。

小批量是输入数据的子集,在每次训练迭代中随机抽样。这些小批量大大减少了融合到本地解决方案所需的计算量。与其他降低 k 均值收敛时间的算法相反,小批量 k 均值产生的结果通常只比标准算法略差。

该算法在两个主要步骤之间进行迭代:
与 k 均值相反,这是在每个样本的基础上完成的。对于 mini-batch 中的每个样本,通过取样本的流平均值(streaming average)和分配给该质心的所有先前样本来更新分配的质心。这具有随时间降低质心的变化率的效果。执行这些步骤直到达到收敛或达到预定次数的迭代。

【实例】 k 均值聚类和小批量 k 均值聚类对比实例。
import time
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import MiniBatchKMeans, KMeans
from sklearn.metrics.pairwise import pairwise_distances_argmin
from sklearn.datasets.samples_generator import make_blobs

# 产生样本数据
np.random.seed(0)
batch_size = 45
centers = [[1, 1], [-1, -1], [1, -1]]  # 三种聚类的中心
n_clusters = len(centers)
X, labels_true = make_blobs(n_samples = 3000, centers = centers, cluster_std = 0.7)  # 生成样本随机数

# k 均值聚类
k_means = KMeans(init = 'k-means++', n_clusters = 3, n_init = 10)
begin_time = time.time()  # 记录训练开始时间
k_means.fit(X)
t_batch = time.time() - begin_time  # 记录训练用时
print('k 均值聚类时长:', t_batch)

# 小批量 k 均值聚类
# batch_size 为每次更新使用的样本数
mbk = MiniBatchKMeans(init = 'k-means++', n_clusters = 3, batch_size = batch_size,
                     n_init = 10, max_no_improvement = 10, verbose = 0)
begin_time = time.time()  # 记录训练开始时间
mbk.fit(X)
t_mini_batch = time.time() - begin_time  # 记录训练用时
print('小批量 k 均值聚类时长:', t_mini_batch)

# 结果可视化
fig = plt.figure(figsize = (16, 6))  # 窗口大小
fig.subplots_adjust(left = 0.02, right = 0.98, bottom = 0.05, top = 0.9)  # 窗口四周留白
colors = ['#4EACC5', '#FF9C34', '#4E9A06']  # 三种聚类的颜色

# 绘制 k-Means
ax = fig.add_subplot(1, 3, 1)
for k, col in zip(range(n_clusters), colors):
    my_members = k_means.labels_ == k
    cluster_center = k_means.cluster_centers_[k]
    ax.plot(X[my_members, 0], X[my_members, 1], 'w', markerfacecolor = col, marker = '.')
    ax.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor = col, markeredgecolor = 'k', markersize = 6)
ax.set_title('k-Means')
ax.set_xticks(())
ax.set_yticks(())
plt.text(-3.5, 1.8, 'train time: %.2f s\ninertia: %f' % (t_batch, k_means.inertia_))
plt.rcParams['font.sans-serif'] = ['SimHei']  # 显示中文

# 绘制 MiniBatchKMeans
ax = fig.add_subplot(1, 3, 2)
for k, col in zip(range(n_clusters), colors):
    my_members = mbk_means_labels == k
    cluster_center = mbk_means_cluster_centers_[k]
    ax.plot(X[my_members, 0], X[my_members, 1], 'w', markerfacecolor = col, marker = '.')
    ax.plot(cluster_center[0], cluster_center[1], 'o', markerfacecolor = col, markeredgecolor = 'k', markersize = 6)
ax.set_title('MiniBatchKMeans')
ax.set_xticks(())
ax.set_yticks(())
plt.text(-3.5, 1.8, 'train time: %.2f s\ninertia: %f' % (t_mini_batch, mbk.inertia_))

# 初始化两次结果
different = (mbk_means_labels == 4)
ax = fig.add_subplot(1, 3, 3)
for k in range(n_clusters):
    different += ((k_means_labels == k) != (mbk_means_labels == order[k]))
    # 向量取反,也就是聚类结果相同设置为 true,聚类结果不相同设置为 false
    indic = np.logical_not(different)
    # 绘制聚类结果相同的样本点
    ax.plot(X[indic, 0], X[indic, 1], 'w', markerfacecolor = '#bbbbbb', marker = '.')
    ax.plot(X[different, 0], X[different, 1], 'w', markerfacecolor = 'm', marker = '.')
ax.set_title('差别')
ax.set_xticks(())
ax.set_yticks(())
plt.show()
运行程序,输出如下:
k均值聚类时长:0.05260491371154785
小批量k均值聚类时长:0.03690028190612793
效果如下图所示:


图 4 k均值与小批量k均值效果图

相关文章