1.5 聚类

聚类指的是将数据集合中相似的对象分成多个类的过程,与分类不同的是,聚类的训练数据是没有类别标签的,这种没有预设标签的机器学习任务被称为非监督学习,而分类和回归这种有标签的机器学习任务称为监督学习。

在聚类任务中,预先并不知道有多少个类别、每个类别是什么,我们的目的只是将相似的样本归入同一类,不同的样本归入不同的类,组内的样本相似度越大,组间的样本相似度越小,聚类效果就越好。

在商铺价格评估的研究项目中,会根据商铺的地理位置将商铺划入不同的商圈,然而商圈的边界往往是不规则的,很难人工划定,这时就可以使用无监督学习的方式,根据商铺距离商业中心的距离或交通时间等属性进行聚类,在一个城市中划分出几个不同的商圈。

sklearn中提供的聚类算法有:K-means、Affinity Propagation、Meanshift、DBSCAN、Gaussian Mixtures等,下面介绍两种比较常用的聚类算法,分别是K-means和DBSCAN。

1.5.1 K-means

K-means聚类算法是一种迭代求解的聚类分析算法。K-means算法需要预先设定总类别数量n_clusters。如果类别数量设置得不够好的话,最终的聚类结果可能会不太理想。

K-means的训练思路如下。

(1) 随机选定n_clusters个中心点(因为K-means的聚类效果受初始点的位置影响很大,所以可以使用特殊的初始化策略,如K-means++)。

(2) 将数据集中的数据根据到各中心点的距离归入不同聚类(靠近哪个中心点就归为哪一类)。

(3) 根据聚类结果重新计算每个聚类的中心点。

(4) 重复第(2)步~第(3)步,直到每个聚类的内部元素不再变化为止,最后得到的所有中心点坐标即为训练得到的模型参数。

1.5.2 DBSCAN

DBSCAN是一种基于密度的聚类算法,不需要设置类别数量,但是需要设置类内样本的最大可接受距离,这个算法对空间样本聚类效果较好。另外,DBSCAN聚类过程中不一定能把所有的样本都划入到聚类中去,可能会存在一些无法聚类的离群点。

DBSCAN的训练思路如下。

(1) 先设定好DBSCAN中的最短聚类距离eps,从数据集中任一点开始,寻找周围到此点距离小于eps的点,加入当前聚类。

(2) 加入新的数据点之后,再从新的数据点出发继续寻找距离小于eps的点,如此循环往复。

(3) 如果当前点的eps半径范围内没有未加入聚类的数据点,则跳到当前聚类外任意未被聚类的点,继续搜索新的聚类。

(4) 对于周围eps范围内没有任何数据点的数据,归为离群点。

1.5.3 聚类实例

为了展示两种算法的区别,这里分别选择make_moonsmake_blobs生成的数据集进行聚类演示,代码如下:

>>> import matplotlib.pyplot as plt
>>> from sklearn.datasets import make_moons,make_blobs
>>> from sklearn.cluster import KMeans,DBSCAN
>>> # 创建数据集
>>> # data = make_moons()
... data = make_blobs(centers = 2)
>>> model_km = KMeans(n_clusters=2)
>>> model_db = DBSCAN()
>>> x = data[0]
>>> # 模型预测
>>> y_pred_km = model_km.fit_predict(x)
>>> y_pred_db = model_db.fit_predict(x)
>>> markers = ["x","s","^","h","*","<"]
>>> colors = ['r','g','b','y','o','tomato']
>>> plt.subplot(121)
<matplotlib.axes._subplots.AxesSubplot object at 0x000000000D8A8668>
>>> plt.title("KMeans")
Text(0.5, 1.0, 'KMeans')
>>> for i,y in enumerate(y_pred_km):
...     plt.scatter(x[i,0],x[i,1],marker=markers[y],color = colors[y])
...>>> plt.subplot(122)
<matplotlib.axes._subplots.AxesSubplot object at 0x000000000FB7ECF8>
>>> plt.title("DBSCAN")
Text(0.5, 1.0, 'DBSCAN')
>>> for i,y in enumerate(y_pred_db):
...     if y != -1:
...         plt.scatter(x[i,0],x[i,1],marker=markers[y],color = colors[y])
...
...     else:
...         plt.scatter(x[i,0],x[i,1],marker=markers[y],color = "black")

上述代码使用了make_moonsmake_blob函数生成的数据集进行了聚类实验,利用生成的数据集训练了两个聚类模型——K-means模型和DBSCAN模型,利用聚类模型对数据进行了聚类,最后将属于不同聚类的数据使用不同的标记在图中绘出,结果如图1-9和图1-10所示。

图 1-9 make_moons聚类结果1

图 1-10 make_blobs聚类结果2

从图1-9和图1-10中可以看出以下两点。

  • K-means比较适合对呈团聚形态的数据进行聚类,对形状不规则的数据进行聚类的效果较差。
  • DBSCAN对数据的聚集形式有较好的适应性,但是DBSCAN的距离阈值设置不合理的话,难以得到很好的聚类效果。这一点跟K-means的聚类中心数量选择比较类似,都依赖于对样本的了解。