01 概念
聚类与分类的不同在于,聚类所要求划分的类是未知的。
聚类是将数据分类到不同的类或者簇这样的一个过程,所以同一个簇中的对象有很大的相似性,而不同簇间的对象有很大的相异性。
从机器学习的角度讲,簇相当于隐藏模式。聚类是搜索簇的无监督学习过程。与分类不同,无监督学习不依赖预先定义的类或带类标记的训练实例,需要由聚类学习算法自动确定标记,而分类学习的实例或数据对象有类别标记。聚类是观察式学习,而不是示例式的学习。
聚类分析是一种探索性的分析,在分类的过程中,人们不必事先给出一个分类的标准,聚类分析能够从样本数据出发,自动进行分类。聚类分析所使用方法的不同,常常会得到不同的结论。不同研究者对于同一组数据进行聚类分析,所得到的聚类数未必一致。
从实际应用的角度看,聚类分析是数据挖掘的主要任务之一。而且聚类能够作为一个独立的工具获得数据的分布状况,观察每一簇数据的特征,集中对特定的聚簇集合作进一步地分析。聚类分析还可以作为其他算法(如分类和定性归纳算法)的预处理步骤。
聚类分析(cluster analysis)是一组将研究对象分为相对同质的群组(clusters)的统计分析技术。
聚类分析也叫分类分析(classification analysis)或数值分类(numerical taxonomy)
变量类型:定类变量、定量(离散和连续)变量
02 聚类方法分类
1,层次聚类
合并法、分解法、树状图
2. 非层次聚类
划分聚类、谱聚类
03 代码解析
使用kmeans算法
<code>### 产生三类随机样本# In[]:from sklearn.datasets import make_blobs# 随机产生150个样本,每个样本有两个特征,形成3个簇# cluster_std 是簇内特征值的标准差X, y = make_blobs(n_samples=150, n_features=2, centers=3, cluster_std=0.5, shuffle=True, random_state=0)# In[]:X.shape,y.shape# In[]:# y的范围是0,1,2,表示每个x样本所属的簇y# In[]:# 查看X的5个值,X是二维,150行2列,行表示样本个数# 列表示特征个数# i是行索引,表示样本索引,第0列是特征1,第1列是特征2for i in range(5): print("%f,%f" % (X[i,0], X[i,1]))# In[]:import matplotlib.pyplot as plt# 画散点图,横坐标和纵坐标分别对应两个不同的特征# X[:, 0]表示所有的特征1值# X[:, 1]表示所有的特征2值,两个特征值对应坐标一个点# s是size的意思,表示点的大小,可以改变50到100尝试plt.scatter(X[:, 0], X[:, 1], c='white', marker='o', edgecolor='black', s=50)# 显示网格plt.grid()# tight_layout会自动调整子图参数,使之填充整个图像区域# 具体例子可以看下:# https://blog.csdn.net/du_shuang/article/details/84139716plt.tight_layout()# 也可以将图像保存#plt.savefig('path/e1.png', dpi=300)plt.show()### 使用sklearn的kmeans方法# In[]:from sklearn.cluster import KMeanskm = KMeans(n_clusters=3, init='random', n_init=10, max_iter=300, tol=1e-04, random_state=0)y_km = km.fit_predict(X)# 每个样本所属于的簇,0,1,2三个簇y_km# In[]:# 对三簇进行画图# In[]:y_km.shape, type(y_km)# In[]:# y_km是一个一维数组,有0,1,2三个值# y_km == 0返回值是一个bool数组,0值位置是Truey_km == 0# In[]:# 下面方法是数组的过滤功能,将y_km == 0返回True# 的值保留,就是说只是保留150行中y值是0的样本X[y_km == 0, 0]# In[]:# 分别对3个不同簇的样本进行绘制plt.scatter(X[y_km == 0, 0], X[y_km == 0, 1], s=50, c='lightgreen', marker='s', edgecolor='black', label='cluster 1')plt.scatter(X[y_km == 1, 0], X[y_km == 1, 1], s=50, c='orange', marker='o', edgecolor='black', label='cluster 2')plt.scatter(X[y_km == 2, 0], X[y_km == 2, 1], s=50, c='lightblue', marker='v', edgecolor='black', label='cluster 3')plt.scatter(km.cluster_centers_[:, 0], km.cluster_centers_[:, 1], s=250, marker='*', c='red', edgecolor='black', label='centroids')# legend是图标说明的意思,一般显示在右上角或右下角# 对不同形状颜色图标进行一个解释plt.legend(scatterpoints=1)plt.grid()plt.tight_layout()#plt.savefig('path/2.png', dpi=300)plt.show()/<code>
基于距离矩阵进行层次聚类算法
<code># In[]:import pandas as pdimport numpy as npimport matplotlib.pyplot as pltnp.random.seed(123)variables = ['X', 'Y', 'Z']labels = ['ID_0', 'ID_1', 'ID_2', 'ID_3', 'ID_4']# 生成5个样本,每个样本3个特征# 一般来说,行表示样本索引,列表示特征索引X = np.random.random_sample([5, 3])*10df = pd.DataFrame(X, columns=variables, index=labels)df# ## Performing hierarchical clustering on a distance matrix# In[]:from scipy.spatial.distance import pdist, squareform# 生成所有样本的距离矩阵,欧式距离进行度量row_dist = pd.DataFrame(squareform(pdist(df, metric='euclidean')), columns=labels, index=labels)# 注意!这是一个对称矩阵,上三角与下三角值一样row_dist# We can either pass a condensed distance matrix (upper triangular) from the `pdist` function, or we can pass the "original" data array and define the `metric='euclidean'` argument in `linkage`. However, we should not pass the squareform distance matrix, which would yield different distance values although the overall clustering could be the same.# In[]:# 1. incorrect approach: Squareform distance matrix# 这是一个错误的调用方法,不能把整个的距离矩阵row_dist作为输入参数from scipy.cluster.hierarchy import linkagerow_clusters = linkage(row_dist, method='complete', metric='euclidean')pd.DataFrame(row_clusters, columns=['row label 1', 'row label 2', 'distance', 'no. of items in clust.'], index=['cluster %d' % (i + 1) for i in range(row_clusters.shape[0])])# In[]:# 正确的调用方法1from scipy.cluster.hierarchy import linkage# 2. correct approach: Condensed distance matrix# 这里的method='complete',指的就是度量簇之间距离的方法# complete就是全链接的方式row_clusters = linkage(pdist(df, metric='euclidean'), method='complete')pd.DataFrame(row_clusters, columns=['row label 1', 'row label 2', 'distance', 'no. of items in clust.'], index=['cluster %d' % (i + 1) for i in range(row_clusters.shape[0])])# In[]:# 正确的调用方法2# 3. correct approach: Input sample matrixrow_clusters = linkage(df.values, method='complete', metric='euclidean')pd.DataFrame(row_clusters, columns=['row label 1', 'row label 2', 'distance', 'no. of items in clust.'], index=['cluster %d' % (i + 1) for i in range(row_clusters.shape[0])])# In[]:# 对分层聚类进行可视化from scipy.cluster.hierarchy import dendrogram# make dendrogram black (part 1/2)# from scipy.cluster.hierarchy import set_link_color_palette# set_link_color_palette(['black'])# 下面函数会产生一个树状的分层聚类图row_dendr = dendrogram(row_clusters, labels=labels, # make dendrogram black (part 2/2) # color_threshold=np.inf )# plt函数可以对上面的图进行添加相关的内容和调整# 比如下面对图的布局进行自动调整,以及增加y轴的文字说明等# 也可以对产生的图像进行保存等,就是说plt可以增加更多对生成图的操作plt.tight_layout()plt.ylabel('Euclidean distance')#plt.savefig('images/xxx.png', dpi=300, # bbox_inches='tight')# 如果不使用jupiter notebook的交互式操作,而是在命令行下运行# 必须调用下面命令才会显示图像,但是在交互模式下,可以直接显示图像对象的。plt.show()# ## 将热图与分层聚类的树状图进行结合# ## Attaching dendrograms/树状图 to a heat map# In[]:# 先产生一个图的对象fig = plt.figure(figsize=(8, 8), facecolor='white')# 关于建立坐标轴的概念,参考example3-1.py例子# 在图像的对象中增加一个坐标系,注意在一个图中是可以增加多个坐标系的# 这个坐标系是用来显示聚类树状图的axd = fig.add_axes([0.09, 0.1, 0.2, 0.6])# 对原有的树状图进行旋转,旋转的目的是为了和产生的热图对应起来# 并且显示到同一个figure对象row_dendr = dendrogram(row_clusters, orientation='left')# 获取聚类后样本的数据,数据的排序顺序和树状图从上向下的顺序是一致的df_rowclust = df.iloc[row_dendr['leaves'][::-1]]df_rowclust.shape, df_rowclust"""将下面数据与dendrogram旋转后的树状图数据进行对照,样本顺序是一致的,这个结果是一个dataframe格式,下面将这些数据以热图的方式展示,并于对应树状分支进行对应 X Y ZID_44.3857220.5967793.980443ID_06.9646922.8613932.268515ID_33.9211753.4317807.290497ID_29.8076426.8482974.809319ID_15.5131487.1946904.231065"""# 设置坐标轴相关属性axd.set_xticks([])axd.set_yticks([])# 隐藏刻度值for i in axd.spines.values(): i.set_visible(False)# 在figure对象中增加一个新的坐标系画热图,位于树状图的右边# 分析下第一个图的位置:axd = fig.add_axes([0.09, 0.1, 0.2, 0.6])# 第一个图占的宽度是figure的0.2,所以下面热图的起始x是0.23,在树状图右边# 中间还有figure宽度0.03的间隙axm = fig.add_axes([0.23, 0.1, 0.6, 0.6]) # x-pos, y-pos, width, height# 下面是把热图画出cax = axm.matshow(df_rowclust, interpolation='nearest', cmap='hot_r')fig.colorbar(cax)axm.set_xticklabels([''] + list(df_rowclust.columns))axm.set_yticklabels([''] + list(df_rowclust.index))plt.show()# ## Applying agglomerative clustering via scikit-learn# In[]:from sklearn.cluster import AgglomerativeClusteringac = AgglomerativeClustering(n_clusters=3, affinity='euclidean', linkage='complete')labels = ac.fit_predict(X)print('Cluster labels: %s' % labels)# In[]:ac = AgglomerativeClustering(n_clusters=2, affinity='euclidean', linkage='complete')labels = ac.fit_predict(X)print('Cluster labels: %s' % labels)/<code>
DBSCAN
<code># # Locating regions of high density via DBSCAN# In[]:import matplotlib.pyplot as pltfrom sklearn.datasets import make_moonsX, y = make_moons(n_samples=200, noise=0.05, random_state=0)plt.scatter(X[:, 0], X[:, 1])plt.tight_layout()plt.show()# K-means and hierarchical clustering:# In[]:from sklearn.cluster import KMeansfrom sklearn.cluster import AgglomerativeClusteringf, (ax1, ax2) = plt.subplots(1, 2, figsize=(8, 3))km = KMeans(n_clusters=2, random_state=0)y_km = km.fit_predict(X)ax1.scatter(X[y_km == 0, 0], X[y_km == 0, 1], edgecolor='black', c='lightblue', marker='o', s=40, label='cluster 1')ax1.scatter(X[y_km == 1, 0], X[y_km == 1, 1], edgecolor='black', c='red', marker='s', s=40, label='cluster 2')ax1.set_title('K-means clustering')ac = AgglomerativeClustering(n_clusters=2, affinity='euclidean', linkage='complete')y_ac = ac.fit_predict(X)ax2.scatter(X[y_ac == 0, 0], X[y_ac == 0, 1], c='lightblue', edgecolor='black', marker='o', s=40, label='cluster 1')ax2.scatter(X[y_ac == 1, 0], X[y_ac == 1, 1], c='red', edgecolor='black', marker='s', s=40, label='cluster 2')ax2.set_title('Agglomerative clustering')plt.legend()plt.tight_layout()plt.show()# Density-based clustering:# In[]:from sklearn.cluster import DBSCAN# eps就是指定的半径距离,min_samples为范围内指定样本数量db = DBSCAN(eps=0.2, min_samples=5, metric='euclidean')y_db = db.fit_predict(X)plt.scatter(X[y_db == 0, 0], X[y_db == 0, 1], c='lightblue', marker='o', s=40, edgecolor='black', label='cluster 1')plt.scatter(X[y_db == 1, 0], X[y_db == 1, 1], c='red', marker='s', s=40, edgecolor='black', label='cluster 2')plt.legend()plt.tight_layout()plt.show()/<code>
figure对象
<code># In[]:import matplotlib.pyplot as plt# 产生一个画图对象,就是右边演示显示的黑色背景区域fig = plt.figure()# 生成坐标轴的位置,就是说在同一个图像figure对象中,# 是可以有多个坐标系的,添加坐标系的四个参数都是比例值,都是# figure对象,即显示的黑色底色的比例值,建设图像对象的宽是w,高是h,# 0.1, 0.1 表示建立坐标系的原点位置为图像对象大小的0.1*w和0.1h,# 0.8, 0.8 表示建立坐标系的空间区域大小(宽和高),0.8*w和0.8h# 这四个值都是图像空间大小(宽和高)的比例值,0-1之间。ax1 = fig.add_axes([0.1, 0.1, 0.8, 0.8])ax2 = fig.add_axes([0.05, 0.2, 0.5, 0.5])line1 = ax1.plot([0,1], [0,1])ax1.set_title("a straight line (OO)")ax1.set_xlabel("x value")ax1.set_ylabel("y value")line2 = ax2.plot([0,1], [0,1])plt.show()/<code>
閱讀更多 天天面試題 的文章