首页 > Python机器学习 阅读数:31

Python sklearn模板实现k均值聚类算法

聚类操作得有数据才行,这里我们先用 sklearn 的数据生成工具 make_blobs( ) 来合成所需的数据。make_blobs( ) 方法常被用来生成聚类算法的测试数据,简单来说,make_blobs( ) 会根据用户指定的样本数量、特征数量、簇中心数量、生成数据的波动范围等来生成数据,这些数据可用于测试聚类算法的效果。

make_blobs( ) 方法的原型如下:
sklearn.datasets.make_blobs(n_samples=100, n_features=2,centers=None, cluster_std=1.0, center_box=(-10.0, 10.0), shuffle=True, random_state=None)

主要参数 n_samples 是待生成的样本总数,默认值为 100;n_features 是每个样本的特征数量,默认值为 2;centers 表示要生成的样本中心(类别)数,或是确定的中心点数量,默认值为 3;cluster_std 是每个类别的方差。

该方法有两个返回值。X 返回维度为 [n_samples, n_features] 的特征数据;y 返回维度为 [n_samples] 的标签数据。从返回的数据可以看出,make_blobs( ) 同样可用于监督学习的分类算法中,因为它也提供了标签(分类)信息。

对这个方法有了基本的认知之后,下面我们就“牛刀小试”,生成一些数据并将它们可视化输出,看看它们长成什么模样。

我们先导入必要的包或方法,包括绘图的 Matplotlib 和生成数据的 make_blobs。
In [1]:
import matplotlib.pyplot as plt
#导入生成数据的方法
from sklearn.datasets import make_blobs

然后生成数据,方法如下:
In [2]:
#生成合成数据
blobs = make_blobs(n_samples = 200, random_state =1, centers = 4)
需要注意的是,make_blobs( ) 方法返回两个数据,实际上这两个数据会被打包成一个匿名的元组。

如果我们用一个变量来接收它,那么这个变量就是一个包含两个元素的元组,上面的 blobs 就是这样的。所以,如果我们想提取特征数据,必须按照提取元组元素的方式来完成。
In [3]:
X_blobs = blobs[0]   #提取特征数据

在 In [2] 处,由于我们并没有设置 make_blobs( ) 的特征数 n_features,参考该方法的原型可知,n_features 的默认值为 2,即合成的数据是二维的。二维数据是很容易被绘制出来的。
In [4]:
plt.scatter(X_blobs[:, 0], X_blobs[:, 1])
plt.show()

运行结果如图 1 所示,可以看到所有簇都被渲染成了同一种颜色,辨识度不是很高。

生成数据的聚类图
图 1:生成数据的聚类图

事实上,make_blobs( ) 还返回了标签信息,对于聚类算法而言,它基本没有用。但在绘制图形时,标签信息可用于区分不同簇。例如,如果我们把上述代码稍微修改一下,用不同的标签信息来标识不同簇,就会发现这些簇的颜色泾渭分明,清晰可辨。
In [5]:
plt.scatter(X_blobs[:, 0], X_blobs[:, 1], c = blobs[1])
plt.show()
上述代码中,散点图绘制方法 scatter( ) 中的参数 c 表示颜色(color)。blobs[1] 表示的是标签信息 y。

程序运行结果如图 2 所示:

用标签信息染色的聚类图
图 2:用标签信息染色的聚类图

有了数据,就可用利用 sklearn 的标准流程实施聚类分析了。首先导入相应的聚类模型。
In [6]:
# (1)导入KMeans工具包
from sklearn.cluster import KMeans

需要说明的是,聚类模型非常之多,而 k 均值聚类仅仅是其中的一种。所以我们是通过 sklearn.cluster 导入 KMeans 工具包的。接下来,我们要构建 KMeans 模型对象。
In [7]:
#(2)构建 KMeans 模型对象,设定 k=4
kmeans = KMeans(n_clusters = 4)

为了更好地使用这个模型,下面我们来说明一下实现 KMeans 模型的方法原型,如下所示:
sklearn.cluster.KMeans(n_clusters=8, init= 'k-means++', n_init=10, max_iter=300, ...,  random_state=None, ...)
KMeans 中常用的参数解释如下。
  • n_clusters:指定簇中心的个数。这个是超参数,人为设定。
  • init:簇中心初始化方法。任意指定的参数为 random,默认值为 k-means++,它是一种特殊的初始化方法,可在很大程度上提高算法的收敛速度。
  • n_init:初始化的次数。模型会多次初始化不同的簇中心得到不同的结果,并择优选定。
  • max_iter:得到最终簇中心的迭代次数。
  • random_state:相当于随机种子。在开始运行时,k 均值聚类需要从众多数据中随机挑选 k 个点作为簇中心,random_state 就是为挑选 k 个簇中心而准备的随机种子。

前面提及的训练集和测试集的分割方法— train_test_split( ) 也涉及随机种子的设置。与之类似的是,如果我们将随机种子指定为某个值,实际上就是固化了随机数的生成,这样做的好处在于,便于进行性能评估和调参。如果不设置,sklearn 会以时间作为随机种子,因为时间在每时每刻都是不同的,所以基本上能保证初始簇中心也是不同的。

当 KMeans 模型生成以后,就可以训练模型了。如前所述,sklearn 中的所有模型训练都称为拟合(fit)。
In [8]:
#(3)训练模型(拟合,懒惰算法)
kmeans.fit(X_blobs)

下面,我们就可以用可视化的方式绘制出每个簇的边界(势力范围)及簇中心了。为了便于说明,我们把下面的代码进行编号。
In [9]:
01    #(4)绘制可视化图
02    import numpy as np
03    x_min, x_max = X_blobs[:, 0].min() - 0.5, X_blobs[:, 0].max() + 0.5
04    y_min, y_max = X_blobs[:, 1].min() - 0.5, X_blobs[:, 1].max() + 0.5
05    #(5)生成网格点矩阵
06    xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.02), np.arange(y_min, y_max, 0.02))
07    Z = kmeans.predict(np.c_[xx.ravel(), yy.ravel()])
08    Z = Z.reshape(xx.shape)
09    plt.figure(1)
10    plt.clf()
11    plt.imshow(Z, interpolation = 'hermite', extent = (xx.min(), xx.max(), yy.min(), yy.max()),  cmap = plt.cm.winter, aspect = 'auto', origin = 'lower')
12    plt.plot(X_blobs[:, 0], X_blobs[:, 1], 'w.', markersize = 5)
13    #用红色的x表示簇中心
14    centroids = kmeans.cluster_center_
15    plt.scatter(centroids[:, 0], centroids[:, 1], marker = "x", s = 150, linewidths = 3, color = 'r', zorder = 10)
16    plt.xlim(x_min, x_max)
17    plt.ylim(y_min, y max)
18    plt.xticks()
19    plt.yticks()
20    plt.show()
程序执行结果如图 3 所示:
k均值聚类的簇边界和簇中心
图 3:k 均值聚类的簇边界和簇中心

上述代码的核心功能就是实现聚类,特别之处是画出了每个簇的“势力范围”(用不同的颜色标识),也就是说,落到这个所谓的“势力范围”内的点,就属于这个簇。如何画出这个“势力范围”呢?

首先,找到数据集的最大值、最小值,并稍稍扩展这个极值边界,即比最小值还要小 0.5,比最大值还要大 0.5(代码 03~04 行)。

然后利用 NumPy 中的 meshgrid( ) 方法返回一个网格矩阵,它就像一张密集的网,覆盖整个坐标轴(代码第 06 行)。然后,我们把这个密集的网格坐标点当作一个测试集,把这些坐标点一一拿去预测,看它们分别属于哪个簇(代码第 07 行)。

而后,根据每个网格点所属的簇不同,渲染不同的颜色,如果这样的网格点分布足够密集,那么不同簇的“势力范围”就生动地展现出来了(代码第 11 行)。

然后,我们就利用常规方法画出数据的散点图(代码第 12 行),接着根据拟合得到各个簇中心的坐标(代码第 14 行)。如前所述,簇中心坐标属于 sklearn 拟合而出的重要参数,它有自己专门的命名规则,即常规英文单词后面加一个下画线,如 cluster_centers_。然后我们用标记“×”将簇中心标识出来即可(代码第 15 行)。

以上就是利用 sklearn 实施k均值聚类的流程。在上述范例中,为了辅助说明,我们添加了很多解释性的代码。而实际上,如果我们有了预处理好的数据,并熟悉 sklearn 框架的用法,实现一个 k 均值聚类算法,只需要十几行代码就够了。