Module 8: 聚类分析 Cluster Analysis

聚类分析试图将输入数据划分为紧密相关的实例组(簇,cluster),以使属于同一簇的实例彼此之间的相似性高于与属于其他群集的实例之间的相似性。 在本教程中,我们将提供使用scikit-learn库软件包提供的不同聚类技术的示例。

8.1 K均值聚类 K-means Clustering

k均值聚类算法使用簇的质心(centroid)表示每个簇。该算法通过迭代应用以下两个步骤将输入数据划分为 *k* 个不相交的簇:

1. 通过将每个实例(数据点)分配给最近的质心来形成 *k* 个簇。

2. 重新计算每个簇的质心。

任务:

1. 运行下述代码,并通过查阅sckit-learn文档等方式了解K均值聚类的实现原理和使用过程;

2. 尝试修改cluster.KMeans中的参数,观察是否会影响实验结果。

思考:

对以下数据集使用K均值聚类算法

1)观察实验结果是否符合预期;

2)利用SSE标准确定K值;

3)自行调参并观察对聚类结果的影响。

注意:需要把类别信息去掉。

1. “tutorial3_Data Exploration”中的鸢尾花数据集“iris.data”

2. “tutorial4_Data Preprocessing”中的癌症数据集“breast-cancer-wisconsin.data”

在本节中,我们对电影评分数据集的一个示例使用k均值聚类。 我们首先按如下方式创建数据集。

import pandas as pd

ratings = [['john',5,5,2,1],['mary',4,5,3,2],['bob',4,4,4,3],['lisa',2,2,4,5],['lee',1,2,3,4],['harry',2,1,5,5]]

titles = ['user','Jaws','Star Wars','Exorcist','Omen']

movies = pd.DataFrame(ratings,columns=titles)

movies

在此示例数据集中,前3个用户喜欢动作片(《大白鲨Jaws》和《星球大战Star Wars》),而后3个用户喜欢恐怖片(《驱魔人Exorcist》和《凶兆Omen》)。 我们的目标是对用户应用k均值聚类,以识别具有相似电影偏好的用户组。

下面的示例显示了如何在电影评分数据上应用k均值聚类(k=2)。 在应用聚类算法之前,我们必须先删除“用户”列。 每个用户的簇分配显示为数据框对象(dataframe object)。

from sklearn import cluster

data = movies.drop('user',axis=1)

k_means = cluster.KMeans(n_clusters=2, max_iter=50, random_state=1)

k_means.fit(data)

labels = k_means.labels_

pd.DataFrame(labels, index=movies.user, columns=['Cluster ID'])

k均值聚类算法将前三个用户分配给第一个簇,将后三个用户分配给第二个簇。 结果符合我们的预期。 我们还可以显示两个簇的质心。

centroids = k_means.cluster_centers_

pd.DataFrame(centroids,columns=data.columns)

import numpy as np

testData = np.array([[4,5,1,2],[3,2,4,4],[2,3,4,1],[3,2,3,3],[5,4,1,4]])

labels = k_means.predict(testData)

labels = labels.reshape(-1,1)

usernames = np.array(['paul','kim','liz','tom','bill']).reshape(-1,1)

cols = movies.columns.tolist()

cols.append('Cluster ID')

newusers = pd.DataFrame(np.concatenate((usernames, testData, labels), axis=1),columns=cols)

newusers

为了确定数据中的簇数,我们可以应用簇数从1到6的k均值,并计算其对应的平方和误差(sum-of-squared errors, SSE),如下例所示。 SSE相对于簇数的图中的“拐点(elbow)”可用于估计簇数。

import matplotlib.pyplot as plt

%matplotlib inline

numClusters = [1,2,3,4,5,6]

SSE = []

for k in numClusters:

k_means = cluster.KMeans(n_clusters=k)

k_means.fit(data)

SSE.append(k_means.inertia_)

plt.plot(numClusters, SSE)

plt.xlabel('Number of Clusters')

plt.ylabel('SSE')

8.2 层次聚类 Hierarchical Clustering

本节演示将层次聚类应用于模块6(分类)中使用的脊椎动物数据集的示例。 具体来说,我们说明了使用Python scipy库提供的3种层次聚类算法的结果:

(1)单链接(MIN)

(2)全链接(MAX)和

(3)组平均值(group average)。 该库还提供了一些其他分层聚类算法,包括基于质心(centroid-based)和Ward方法。

任务:

1. 运行下述代码,查阅文档资料并结合聚类结果对比分析三种算法的原理和效果;

2. 查阅scipy文档,尝试使用基于质心(centroid-based)和Ward方法,观察实验结果并分析这两类算法的原理。

思考:

1. 结合你的生物知识,分析五种算法的结果是否符合你对生物分类体系的理解;

2. 对比五种算法的结果的异同,并结合其工作原理分析原因。

import pandas as pd

data = pd.read_csv('vertebrate.csv',header='infer')

data

8.2.1 单链接 (MIN)

from scipy.cluster import hierarchy

import matplotlib.pyplot as plt

%matplotlib inline

names = data['Name']

Y = data['Class']

X = data.drop(['Name','Class'],axis=1)

# NDFrame.as_matrix is deprecated. Use NDFrame.values instead (:issue:18458).

# Z = hierarchy.linkage(X.as_matrix(), 'single')

Z = hierarchy.linkage(X.values, 'single')

dn = hierarchy.dendrogram(Z,labels=names.tolist(),orientation='right')

8.2.2 全链接 (MAX) 

Z = hierarchy.linkage(X.values, 'complete')

dn = hierarchy.dendrogram(Z,labels=names.tolist(),orientation='right')

 8.3.3 组平均值 Group Average

Z = hierarchy.linkage(X.values, 'average')

dn = hierarchy.dendrogram(Z,labels=names.tolist(),orientation='right')

8.3 基于密度的聚类 Density-Based Clustering

基于密度的聚类方法将各个簇标识为被低密度区域分隔的高密度区域。 DBScan是最流行的基于密度的聚类算法之一。 在DBScan中,数据点根据其局部邻域的密度(density of their local neighborhood)分为三类-核心点(core points),边界点(border points)和噪声点(noise points)。 局部邻域密度是根据以下两个参数定义的:邻域大小的半径(eps)和邻域中的最小点数(min_samples)。

对于这种方法,我们将使用由Karypis等人[最初创建的包含噪声的二维数据集评估他们提出的CHAMELEON算法。下面显示的示例代码将加载并绘制数据分布。

任务:

1. 运行下述代码,查阅文档资料并结合聚类结果对比分析不同算法的原理和效果;

2. 查阅scipy文档,尝试修改各个算法的超参数,并观察其对实验结果的影响。

思考:

1. 查阅scikit-learn文档中的数据生成器(Samples generator,https://scikit-learn.org/stable/modules/classes.html#module-sklearn.datasets )请至少生成5种不同(形状或者分布)的数据集,并使用DBScan和谱聚类进行聚类分析,观察实验结果,结合算法原理进行分析。

import pandas as pd

data = pd.read_csv('chameleon.data', delimiter=' ', names=['x','y'])

data.plot.scatter(x='x',y='y')

 

通过将邻域半径(eps)设置为15.5,将最小点数(min_samples)设置为5,我们对数据应用DBScan聚类算法。将簇分配给0到8之间的ID,而将噪声点分配给ID为-1的簇。

from sklearn.cluster import DBSCAN

db = DBSCAN(eps=15.5, min_samples=5).fit(data)

core_samples_mask = np.zeros_like(db.labels_, dtype=bool)

core_samples_mask[db.core_sample_indices_] = True

labels = pd.DataFrame(db.labels_,columns=['Cluster ID'])

result = pd.concat((data,labels), axis=1)

result.plot.scatter(x='x',y='y',c='Cluster ID', colormap='jet')

8.4 谱聚类 Spectral Clustering

K均值聚类算法的主要局限之一是其寻求球状簇的趋势。因此,针对具有任意形状的簇的数据集或簇的质心彼此重叠时,K均值聚类算法效果较差。 谱聚类可以通过利用相似度图的属性来克服这种限制,从而克服这种限制。为了说明这一点,请考虑以下二维数据集。

import pandas as pd

data1 = pd.read_csv('2d_data.txt', delimiter=' ', names=['x','y'])

data2 = pd.read_csv('elliptical.txt', delimiter=' ', names=['x','y'])

fig, (ax1,ax2) = plt.subplots(nrows=1, ncols=2, figsize=(12,5))

data1.plot.scatter(x='x',y='y',ax=ax1)

data2.plot.scatter(x='x',y='y',ax=ax2)

from sklearn import cluster

k_means = cluster.KMeans(n_clusters=2, max_iter=50, random_state=1)

k_means.fit(data1)

labels1 = pd.DataFrame(k_means.labels_,columns=['Cluster ID'])

result1 = pd.concat((data1,labels1), axis=1)

k_means2 = cluster.KMeans(n_clusters=2, max_iter=50, random_state=1)

k_means2.fit(data2)

labels2 = pd.DataFrame(k_means2.labels_,columns=['Cluster ID'])

result2 = pd.concat((data2,labels2), axis=1)

fig, (ax1,ax2) = plt.subplots(nrows=1, ncols=2, figsize=(12,5))

result1.plot.scatter(x='x',y='y',c='Cluster ID',colormap='jet',ax=ax1)

ax1.set_title('K-means Clustering')

result2.plot.scatter(x='x',y='y',c='Cluster ID',colormap='jet',ax=ax2)

ax2.set_title('K-means Clustering')

上图显示了k均值聚类的性能较差。 接下来,我们将谱聚类应用于数据集。 谱聚类将数据转换为相似度图,并应用归一化切割图分区算法(normalized cut graph partitioning algorithm)生成簇。 在下面的示例中,我们将高斯径向基函数(Gaussian radial basis function)用作我们的亲和度(affinity,类似于相似度)度量。 用户需要调整内核参数(gamma)值,以获得针对给定数据集的合适的簇。

from sklearn import cluster

import pandas as pd

spectral = cluster.SpectralClustering(n_clusters=2,random_state=1,affinity='rbf',gamma=5000)

spectral.fit(data1)

labels1 = pd.DataFrame(spectral.labels_,columns=['Cluster ID'])

result1 = pd.concat((data1,labels1), axis=1)

spectral2 = cluster.SpectralClustering(n_clusters=2,random_state=1,affinity='rbf',gamma=500)

spectral2.fit(data2)

labels2 = pd.DataFrame(spectral2.labels_,columns=['Cluster ID'])

result2 = pd.concat((data2,labels2), axis=1)

fig, (ax1,ax2) = plt.subplots(nrows=1, ncols=2, figsize=(12,5))

result1.plot.scatter(x='x',y='y',c='Cluster ID',colormap='jet',ax=ax1)

ax1.set_title('Spectral Clustering')

result2.plot.scatter(x='x',y='y',c='Cluster ID',colormap='jet',ax=ax2)

ax2.set_title('Spectral Clustering')

8.5 总结 Summary

本教程说明了使用不同的Python聚类算法实现的示例。 k均值、谱聚类和DBScan之类的算法旨在创建数据的不相交分区,而单链接,完全链接和组平均算法则旨在生成簇的层次结构。

参考文献:

[1] George Karypis, Eui-Hong Han, and Vipin Kumar. CHAMELEON: A Hierarchical Clustering Algorithm Using Dynamic Modeling. IEEE Computer 32(8): 68-75, 1999.

相关链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: