【机器学习】算法原理详细推导与实现(六):k-means算法
之前几个章节都是介绍有监督学习,这个章节介绍无监督学习,这是一个被称为k-means
的聚类算法,也叫做k均值聚类算法。
聚类算法
在讲监督学习的时候,通常会画这样一张图:
这时候需要用logistic
回归或者SVM
将这些数据分成正负两类,这个过程称之为监督学习,是因为对于每一个训练样本都给出了正确的类标签。
在无监督学习中,经常会研究一些不同的问题。假如给定若干个点组成的数据集合:
所有的点都没有像监督学习那样给出类标签和所谓的学习样本,这时候需要依靠算法本身来发现数据中的结构。在上面的这张图中,可以很明显的发现这些数据被分成了两簇,所以一个无监督学习算法将会是聚类算法,算法会将这样的数据聚集成几个不同的类。
聚类算法很多应用场景,举几个最常用的:
- 在生物学应用中,经常需要对不同的东西进行聚类,假设有很多基因的数据,你希望对它们进行聚类以便更好的理解不同种类的基因对应的生物功能
- 在市场调查中,假设你有一个数据库,里面保存了不同顾客的行为,如果对这些数据进行聚类,可以将市场分为几个不同的部分从而可以对不同的部分指定相应的销售策略
- 在图片的应用中,可以将一幅照片分成若干个一致的像素子集,去尝试理解照片的内容
- 等等...
聚类的基本思想是:给定一组数据集合,聚集成若干个属性一致的类。
k-means聚类
这个算法被称之为k-means聚类算法,用于寻找数据集合中的类,算法的输入是一个无标记的数据集合
k-means
聚类算法是将样本聚类成
(cluster)
,具体算法步骤如下:
step 1 随机选取k
个聚类质心点(cluster centroids)
,那么就等于存在了
step 2 对于每一个
step 3 对于每一个类
之后需要重复step 2和step 3直到算法收敛,下面图中对上述步骤进行解释,存在数据点如下所示:
假设我们取
分别计算每一个
下一步是更新簇
再次重复计算每一个
这里涉及到一个问题,如何保证k-means是收敛的?前面算法强调的是结束条件是收敛,为了保证算法完全收敛,这里引入畸变函数(distortion function):
由于畸变函数
k-means
对随机取的质心的初始位置比较敏感。一般达到局部最优已经满足分类的需求了,如果比较介意的话,可以多跑几次
k-means
算法,然后取
k值确定
很多人不知道怎么确定数据集需要分多少个类(簇),因为数据是无监督学习算法,k
值需要认为的去设定。所以这里会提供两种方法去确定k
值。
第一种方法:
观察法,本文的例子可以看出,把数据集画在图中显示,就能很明显的看到应该划分2
个类(簇):
并非所有的数据都像上面的数据一样,一眼可以看出来分2
个类(簇),所以介绍一般比较常用的第二种方法。
第二种方法:
轮廓系数(Silhouette Coefficient),是聚类效果好坏的一种评价方式。最早由 Peter J. Rousseeuw 在 1986 提出。它结合内聚度和分离度两种因素。可以用来在相同原始数据的基础上用来评价不同算法、或者算法不同运行方式对聚类结果所产生的影响。
按照上面计算k-means
算法的步骤计算完后,假设
-
,计算与同一簇中其他点的平均距离,代表与同一簇中其他点不相似的程度
-
,计算与另一个与最近的簇,与簇内所有点平均距离,代表与最相邻簇的不相似程度
最终轮廓系数的计算公式为:
轮廓系数的范围为
1
代表内聚度和分离度都相对较优。
所以可以在k-means
算法开始的时候,先设置k
值的范围
k
取每一个值的轮廓系数,轮廓系数最小的那个
k
值就是最优的分类总数。
实例
假设存在数据集为如下样式:
import matplotlib.pyplot as plt
import numpy as np
from sklearn.cluster import KMeans
from sklearn import metrics
# figsize绘图的宽度和高度,也就是像素
plt.figure(figsize=(8, 10))
x1 = np.array([1, 2, 3, 1, 5, 6, 5, 5, 6, 7, 8, 9, 7, 9])
x2 = np.array([1, 3, 2, 2, 8, 6, 7, 6, 7, 1, 2, 1, 1, 3])
X = np.array(list(zip(x1, x2))).reshape(len(x1), 2)
# print(X)
# x,y轴的绘图范围
plt.xlim([0, 10])
plt.ylim([0, 10])
plt.title('sample')
plt.scatter(x1, x2)
# 点的颜色
colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k', 'b']
# 点的形状
markers = ['o', 's', 'D', 'v', '^', 'p', '*', '+']
plt.show()
虽然观察法可以知道这个数据集合只要设置
k
值。假设不知道的情况下,这里取
# 测试的k值
tests = [2, 3, 4, 5, 8]
subplot_counter = 1
for t in tests:
subplot_counter += 1
plt.subplot(3, 2, subplot_counter)
kmeans_model = KMeans(n_clusters=t).fit(X)
for i, l in enumerate(kmeans_model.labels_):
plt.plot(x1[i], x2[i], color=colors[l], marker=markers[l], ls='None')
# 每个点对应的标签值
# print(kmeans_model.labels_)
plt.xlim([0, 10])
plt.ylim([0, 10])
plt.title('K = %s, Silhouette Coefficient = %.03f' % (t, metrics.silhouette_score(X, kmeans_model.labels_, metric='euclidean')))
得到的结果为:
可以看到当
0.722
数据和代码下载请关注公众号【 机器学习和大数据挖掘 】,后台回复【 机器学习 】即可获取