Python机器学习聚类算法

2016/11/16 Python scikitlearn

Python机器学习聚类算法

聚类是指自动识别具有相似属性的给定对象,并将具有相似属性的对象合并为同一个集合。聚类属于无监督学习的范畴,最常见的应用场景包括顾客细分和试验结果分组。根据聚类思想的不同,分为多种聚类算法,如基于质心的、基于密度的、基于分层的聚类等。Scikit-learn中最常用的聚类算法包括k均值聚类、谱聚类、均值漂移聚类、层次聚类、基于密度的空间聚类等。

k均值聚类

k均值(k-means)聚类通常被视为聚类的“入门算法”,其算法原理非常简单。首先从X数据集中选择k个样本作为质心,然后重复以下两个步骤来更新质心,直到质心不再显著移动为止:第一步将每个样本分配到距离最近的质心,第二步根据每个质心所有样本的平均值来创建新的质心。

基于质心的聚类是通过把样本分离成多个具有相同方差的类的方式来聚集数据的,因此我们总是希望簇是凸(convex)的和各向同性(isotropic)的,但这并非总是能够得到满足。例如,对细长、环形或交叉等具有不规则形状的簇,其聚类效果不佳。

KMeans类和MiniBatchKMeans类是Scikit-learn聚类子模块cluster提供的基于质心的聚类算法。MiniBatchKMeans类是KMeans类的变种,它使用小批量来减少计算时间,而多个批次仍然尝试优化相同的目标函数。小批量是输入数据的子集,是每次训练迭代中的随机抽样。小批量大大减少了收敛到局部解所需的计算量。与其他降低k均值收敛时间的算法不同,MiniBatchKMeans类产生的结果通常只比标准算法略差。

>>> from sklearn import datasets as dss
>>> from sklearn.cluster import KMeans
>>> import matplotlib.pyplot as plt
>>> plt.rcParams['font.sans-serif'] = ['FangSong']
>>> plt.rcParams['axes.unicode_minus'] = False
>>> X_blob, y_blob = dss.make_blobs(n_samples=[300,400,300], n_features=2)
>>> X_circle, y_circle = dss.make_circles(n_samples=1000, noise=0.05, factor=0.5)
>>> X_moon, y_moon = dss.make_moons(n_samples=1000, noise=0.05)
>>> y_blob_pred = KMeans(init='k-means++', n_clusters=3).fit_predict(X_blob)
>>> y_circle_pred = KMeans(init='k-means++', n_clusters=2).fit_predict(X_circle)
>>> y_moon_pred = KMeans(init='k-means++', n_clusters=2).fit_predict(X_moon)
>>> plt.subplot(131)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180AFDECB88>
>>> plt.title('团状簇')
Text(0.5, 1.0, '团状簇')
>>> plt.scatter(X_blob[:,0], X_blob[:,1], c=y_blob_pred)
<matplotlib.collections.PathCollection object at 0x00000180C495DF08>
>>> plt.subplot(132)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180C493FA08>
>>> plt.title('环状簇')
Text(0.5, 1.0, '环状簇')
>>> plt.scatter(X_circle[:,0], X_circle[:,1], c=y_circle_pred)
<matplotlib.collections.PathCollection object at 0x00000180C499B888>
>>> plt.subplot(133)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180C4981188>
>>> plt.title('新月簇')
Text(0.5, 1.0, '新月簇')
>>> plt.scatter(X_moon[:,0], X_moon[:,1], c=y_moon_pred)
<matplotlib.collections.PathCollection object at 0x00000180C49DD1C8>
>>> plt.show()

均值漂移聚类

均值漂移(Mean Shift)聚类是另一种基于质心的算法,旨在发现一个样本密度平滑的blobs。它的工作原理与k均值聚类十分相似,但也存在一些明显差异。首先,均值漂移聚类不需要像k均值聚类那样指定集群数量;其次,均值漂移聚类会寻找密集区域并将其作为集群中心;最后,均值漂移聚类将稀疏区域视为噪声或异常点。

均值漂移类MeanShift包含在Scikit-learn聚类子模块cluster内。下面以8.6.1小节的新月数据集为例,演示MeanShift类的主要参数cluster_all和bandwidth对聚类结果的影响。

>>> from sklearn import datasets as dss
>>> from sklearn.cluster import MeanShift
>>> import matplotlib.pyplot as plt
>>> plt.rcParams['font.sans-serif'] = ['FangSong']
>>> plt.rcParams['axes.unicode_minus'] = False
>>> X, y = dss.make_moons(n_samples=1000, noise=0.05)
>>> msm_1 = MeanShift() # 默认参数
>>> msm_2 = MeanShift(cluster_all=False) # 允许噪声和异常点
>>> msm_3 = MeanShift(cluster_all=False, bandwidth=0.5) # 指定RBF内核带宽
>>> msm_1.fit(X)
MeanShift(bandwidth=None, bin_seeding=False, cluster_all=True, max_iter=300,
          min_bin_freq=1, n_jobs=None, seeds=None)
>>> msm_2.fit(X)
MeanShift(bandwidth=None, bin_seeding=False, cluster_all=False, max_iter=300,
          min_bin_freq=1, n_jobs=None, seeds=None)
>>> msm_3.fit(X)
MeanShift(bandwidth=0.5, bin_seeding=False, cluster_all=False, max_iter=300,
          min_bin_freq=1, n_jobs=None, seeds=None)
>>> cneter_x1 = msm_1.cluster_centers_[:,0] # 模型1的质心x坐标
>>> cneter_y1 = msm_1.cluster_centers_[:,1] # 模型1的质心y坐标
>>> cneter_x2 = msm_2.cluster_centers_[:,0] # 模型2的质心x坐标
>>> cneter_y2 = msm_2.cluster_centers_[:,1] # 模型2的质心y坐标
>>> cneter_x3 = msm_3.cluster_centers_[:,0] # 模型3的质心x坐标
>>> cneter_y3 = msm_3.cluster_centers_[:,1] # 模型3的质心y坐标
>>> plt.subplot(131)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180C49DDE88>
>>> plt.title('默认参数')
Text(0.5, 1.0, '默认参数')
>>> plt.scatter(X[:,0], X[:,1], c=msm_1.labels_)
<matplotlib.collections.PathCollection object at 0x00000180C4C1CC08>
>>> plt.scatter(cneter_x1, cneter_y1, marker='x', c='r')
<matplotlib.collections.PathCollection object at 0x00000180C4C1CB88>
>>> plt.subplot(132)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180C4773748>
>>> plt.title('允许噪声和异常点')
Text(0.5, 1.0, '允许噪声和异常点')
>>> plt.scatter(X[:,0], X[:,1], c=msm_2.labels_)
<matplotlib.collections.PathCollection object at 0x00000180C49B7948>
>>> plt.scatter(cneter_x2, cneter_y2, marker='x', c='r')
<matplotlib.collections.PathCollection object at 0x00000180C4C1CA48>
>>> plt.subplot(133)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180C49DA688>
>>> plt.title('允许噪声和异常点,指定内核带宽')
Text(0.5, 1.0, '允许噪声和异常点,指定内核带宽')
>>> plt.scatter(X[:,0], X[:,1], c=msm_3.labels_)
<matplotlib.collections.PathCollection object at 0x00000180C49B7CC8>
>>> plt.scatter(cneter_x3, cneter_y3, marker='x', c='r')
<matplotlib.collections.PathCollection object at 0x00000180C49B7C48>
>>> plt.show()

基于密度的空间聚类

基于密度的空间聚类全称是基于密度的带噪声的空间聚类应用算法,英文简写为DBSCAN。DBSCAN将簇视为被低密度区域分隔的高密度区域,这与K均值聚类假设簇是凸的这一条件完全不同,因此DBSCAN可以发现任何形状的簇。DBSCAN的工作原理是将集群定义为紧密相连的点的最大集合。

DBSCAN类是Scikit-learn聚类子模块cluster提供的基于密度的空间聚类算法,该类有两个重要参数eps和min_samples。要理解DBSCAN类的参数,需要先理解核心样本。如果一个样本的eps距离范围内存在不少于min_sample个样本(包括这个样本),则该样本称为核心样本。可见,参数eps和min_samples定义了簇的稠密度。

>>> from sklearn import datasets as dss
>>> from sklearn.cluster import DBSCAN
>>> import matplotlib.pyplot as plt
>>> plt.rcParams['font.sans-serif'] = ['FangSong']
>>> plt.rcParams['axes.unicode_minus'] = False
>>> X, y = dss.make_moons(n_samples=1000, noise=0.05)
>>> dbs_1 = DBSCAN() # 默认核心样本半径0.5,核心样本邻居5
>>> dbs_2 = DBSCAN(eps=0.2) # 核心样本半径0.2,核心样本邻居5
>>> dbs_3 = DBSCAN(eps=0.1) # 核心样本半径0.1,核心样本邻居5
>>> dbs_1.fit(X)
DBSCAN(algorithm='auto', eps=0.5, leaf_size=30, metric='euclidean',
       metric_params=None, min_samples=5, n_jobs=None, p=None)
>>> dbs_2.fit(X)
DBSCAN(algorithm='auto', eps=0.2, leaf_size=30, metric='euclidean',
       metric_params=None, min_samples=5, n_jobs=None, p=None)
>>> dbs_3.fit(X)
DBSCAN(algorithm='auto', eps=0.1, leaf_size=30, metric='euclidean',
       metric_params=None, min_samples=5, n_jobs=None, p=None)
>>> plt.subplot(131)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180C4C5D708>
>>> plt.title('eps=0.5')
Text(0.5, 1.0, 'eps=0.5')
>>> plt.scatter(X[:,0], X[:,1], c=dbs_1.labels_)
<matplotlib.collections.PathCollection object at 0x00000180C4C46348>
>>> plt.subplot(132)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180C4C462C8>
>>> plt.title('eps=0.2')
Text(0.5, 1.0, 'eps=0.2')
>>> plt.scatter(X[:,0], X[:,1], c=dbs_2.labels_)
<matplotlib.collections.PathCollection object at 0x00000180C49FC8C8>
>>> plt.subplot(133)
<matplotlib.axes._subplots.AxesSubplot object at 0x00000180C49FCC08>
>>> plt.title('eps=0.1')
Text(0.5, 1.0, 'eps=0.1')
>>> plt.scatter(X[:,0], X[:,1], c=dbs_3.labels_)
<matplotlib.collections.PathCollection object at 0x00000180C49FC4C8>
>>> plt.show()

谱聚类

谱聚类(spectral clustering)是从图论中演化出来的聚类算法,主要思想是把所有的样本看作空间中的点,点之间以线相连成为一体,以线长计算权重,线越长权重越低;将指定的簇数切分为多个子图,让不同子图间的权重和尽可能低,而各个子图内的权重和尽可能高,从而达到聚类的目的。

谱聚类和k均值聚类一样,也需要指定簇的数量(默认都是8),但谱聚类对簇的形状没有特殊要求,对样本分布的适应性更强,更重要的是,它比k均值聚类的计算量小很多。可以说,谱聚类是一项非常优秀的聚类算法,实现起来也非常简单。Scikit-learn聚类子模块cluster提供了SpectralClustering类来实现谱聚类。

>>> from sklearn import datasets as dss
>>> from sklearn.cluster import SpectralClustering
>>> import matplotlib.pyplot as plt
>>> plt.rcParams['font.sans-serif'] = ['FangSong']
>>> plt.rcParams['axes.unicode_minus'] = False
>>> X, y = dss.make_circles(n_samples=1000, noise=0.05, factor=0.5)
>>> scm_1 = SpectralClustering() # 默认参数
>>> scm_2 = SpectralClustering(n_clusters=2) # 指定簇数为2
>>> scm_3 = SpectralClustering(affinity='nearest_neighbors', n_clusters=2)
>>> scm_1.fit(X)
SpectralClustering(affinity='rbf', assign_labels='kmeans', coef0=1, degree=3,
                   eigen_solver=None, eigen_tol=0.0, gamma=1.0,
                   kernel_params=None, n_clusters=8, n_components=None,
                   n_init=10, n_jobs=None, n_neighbors=10, random_state=None)
>>> scm_2.fit(X)
SpectralClustering(affinity='rbf', assign_labels='kmeans', coef0=1, degree=3,
                   eigen_solver=None, eigen_tol=0.0, gamma=1.0,
                   kernel_params=None, n_clusters=2, n_components=None,
                   n_init=10, n_jobs=None, n_neighbors=10, random_state=None)
>>> scm_3.fit(X)
SpectralClustering(affinity='nearest_neighbors', assign_labels='kmeans',
                   coef0=1, degree=3, eigen_solver=None, eigen_tol=0.0,
                   gamma=1.0, kernel_params=None, n_clusters=2,
                   n_components=None, n_init=10, n_jobs=None, n_neighbors=10,
                   random_state=None)
>>> plt.subplot(131)
<matplotlib.axes._subplots.AxesSubplot object at 0x0000016FBEFB0CC8>
>>> plt.title('默认参数')
Text(0.5, 1.0, '默认参数')
>>> plt.scatter(X[:,0], X[:,1], c=scm_1.labels_)
<matplotlib.collections.PathCollection object at 0x0000016FBF00F5C8>
>>> plt.subplot(132)
<matplotlib.axes._subplots.AxesSubplot object at 0x0000016FBEFE8788>
>>> plt.title('指定簇数')
Text(0.5, 1.0, '指定簇数')
>>> plt.scatter(X[:,0], X[:,1], c=scm_2.labels_)
<matplotlib.collections.PathCollection object at 0x0000016FBE47C948>
>>> plt.subplot(133)
<matplotlib.axes._subplots.AxesSubplot object at 0x0000016FBF03F708>
>>> plt.title('指定簇数和亲和矩阵构造方式')
Text(0.5, 1.0, '指定簇数和亲和矩阵构造方式')
>>> plt.scatter(X[:,0], X[:,1], c=scm_3.labels_)
<matplotlib.collections.PathCollection object at 0x0000016FBF05B9C8>
>>> plt.show()

层次聚类

从原理上讲,层次聚类(Hierarchical clustering)是一种非常简单、直观的聚类算法,层次聚类通过不断的合并(凝聚式)或分割(分裂式)内置聚类来构建最终聚类。以凝聚式为例,其具体实现过程如下:将每一个样本点视为一个簇,并计算各簇之间的距离,将距离最近的两个簇聚合成一个新簇。重复这个过程,直至簇数满足预设值。

当聚类样本数量巨大时,如果样本之间没有添加连接约束,AgglomerativeClustering类的计算代价会很大,因为每一步都要考虑所有可能的合并。

AgglomerativeClustering类是Scikit-learn聚类子模块cluster中用于凝聚式层次聚类的方法。AgglomerativeClustering类的主要参数是linkage,其用于指定合并策略(计算簇间距离),选项有以下4种。

  • ward:所有聚类内的平方差总和最小。
  • complete:两个聚类间最远样本距离值最小。
  • average:两个聚类间平均样本距离值最小。
  • single:两个聚类间最近样本距离值最小。 以下代码针对圆环数据样本演示了这4种合并策略的聚类效果。 ```json

    from sklearn import datasets as dss from sklearn.cluster import AgglomerativeClustering import matplotlib.pyplot as plt plt.rcParams[‘font.sans-serif’] = [‘FangSong’] plt.rcParams[‘axes.unicode_minus’] = False X, y = dss.make_circles(n_samples=1000, noise=0.05, factor=0.5) agg_1 = AgglomerativeClustering(n_clusters=2, linkage=’ward’) agg_2 = AgglomerativeClustering(n_clusters=2, linkage=’complete’) agg_3 = AgglomerativeClustering(n_clusters=2, linkage=’average’) agg_4 = AgglomerativeClustering(n_clusters=2, linkage=’single’) agg_1.fit(X) AgglomerativeClustering(affinity=’euclidean’, compute_full_tree=’auto’, connectivity=None, distance_threshold=None, linkage=’ward’, memory=None, n_clusters=2) agg_2.fit(X) AgglomerativeClustering(affinity=’euclidean’, compute_full_tree=’auto’, connectivity=None, distance_threshold=None, linkage=’complete’, memory=None, n_clusters=2) agg_3.fit(X) AgglomerativeClustering(affinity=’euclidean’, compute_full_tree=’auto’, connectivity=None, distance_threshold=None, linkage=’average’, memory=None, n_clusters=2) agg_4.fit(X) AgglomerativeClustering(affinity=’euclidean’, compute_full_tree=’auto’, connectivity=None, distance_threshold=None, linkage=’single’, memory=None, n_clusters=2) plt.subplot(221)

<matplotlib.axes._subplots.AxesSubplot object at 0x0000016FC1BE9448>

plt.title(‘ward:所有聚类内的平方差总和最小’) Text(0.5, 1.0, ‘ward:所有聚类内的平方差总和最小’) plt.scatter(X[:,0], X[:,1], c=agg_1.labels_)

<matplotlib.collections.PathCollection object at 0x0000016FBEF622C8>

plt.subplot(222)

<matplotlib.axes._subplots.AxesSubplot object at 0x0000016FBEE76908>

plt.title(‘complete:两个聚类间最远样本距离值最小’) Text(0.5, 1.0, ‘complete:两个聚类间最远样本距离值最小’) plt.scatter(X[:,0], X[:,1], c=agg_2.labels_)

<matplotlib.collections.PathCollection object at 0x0000016FBEF62208>

plt.subplot(223)

<matplotlib.axes._subplots.AxesSubplot object at 0x0000016FC1C18CC8>

plt.title(‘average:两个聚类间平均样本距离值最小’) Text(0.5, 1.0, ‘average:两个聚类间平均样本距离值最小’) plt.scatter(X[:,0], X[:,1], c=agg_3.labels_)

<matplotlib.collections.PathCollection object at 0x0000016FC1C18448>

plt.subplot(224)

<matplotlib.axes._subplots.AxesSubplot object at 0x0000016FBF070C88>

plt.title(‘single:两个聚类间最近样本距离值最小’) Text(0.5, 1.0, ‘single:两个聚类间最近样本距离值最小’) plt.scatter(X[:,0], X[:,1], c=agg_4.labels_)

<matplotlib.collections.PathCollection object at 0x0000016FC1B0BD88>

plt.show() ```

Search

    微信好友

    博士的沙漏

    Table of Contents