-
层次聚类
- 虽然基于划分的聚类方法如k-means可以较好的将对象集分成互斥的若干类,但有时我们想把数据划分成不同层上的组群。比如对于手写数字的识别,我们先把它聚类成每个区域只含一种数字,之后对于每个区域,我们还可以继续按手写字体划分成新的区域。
- 层次聚类分为凝聚方法和分裂方法
- 凝聚方法:自底向上。从假设每一个对象都是一个单独的簇开始,迭代合并,形成更大的簇
- 分裂方法:自顶向下。开始令所有对象都在一个簇,迭代分裂,形成较小的簇、
- 凝聚方法每次将两个最接近(依据某种相似性度量)的族合并。
-
距离度量
四个常用距离:
- 最小距离:即将两个簇中距离最近的两个对象间的距离作为这两个簇之间的距离
- 最大距离:即将两个簇中距离最远的两个对象间的距离作为这两个簇之间的距离
- 均值距离:求出两个簇分别的均值m1,m2,将这两个“对象”间的距离作为这两个簇之间的距离
- 平均距离:将两簇中对象间距离的平均值作为这两个簇之间的距离
-
实例:
import pandas as pd
import numpy as np
from scipy.spatial.distance import pdist,squareform
from scipy.cluster.hierarchy import linkage
if __name__ == "__main__":
np.random.seed(1)
# 设置特征的名称
variables = ["x", "y", "z"]
# 设置编号
labels = ["s1", "s2", "s3", "s4", "s5"]
# 产生一个(5,3)的数组
data = np.random.random_sample([5, 3]) * 10
# 通过pandas将数组转换成一个DataFrame
df = pd.DataFrame(data, columns=variables, index=labels)
# 查看数据
print(df)
#获取距离矩阵
'''
pdist:计算两两样本间的欧式距离,返回的是一个一维数组
squareform:将数组转成一个对称矩阵
'''
dist_matrix = pd.DataFrame(squareform(pdist(df,metric="euclidean")),
columns=labels,index=labels)
print(dist_matrix)
#以全连接作为距离判断标准,获取一个关联矩阵
row_clusters = linkage(dist_matrix.values,method="complete",metric="euclidean")
#将关联矩阵转换成为一个DataFrame
clusters = pd.DataFrame(row_clusters,columns=["label 1","label 2","distance","sample size"],
index=["cluster %d"%(i+1) for i in range(row_clusters.shape[0])])
print(clusters)
from scipy.cluster.hierarchy import dendrogram
import matplotlib.pyplot as plt
row_dendr = dendrogram(row_clusters,labels=labels)
plt.tight_layout()
plt.ylabel("欧式距离")
plt.show()
#创建一个figure对象
fig = plt.figure(figsize=(8,8))
#设置x轴的位置、y轴位置、树状图的宽度、树状图的高度
axd = fig.add_axes([0.08,0.1,0.2,0.6])
#将树状图旋转90度
row_dendr = dendrogram(row_clusters,orientation="left")
#根据树状图的簇标重排初始化数据框
df_rowclust = df.ix[row_dendr["leaves"][::-1]]
#绘制热力图
axm = fig.add_axes([0.1,0.1,0.6,0.6])
cax = axm.matshow(df_rowclust,interpolation="nearest",cmap="hot_r")
#删除树状图x轴和y轴的刻度
axd.set_xticks([])
axd.set_yticks([])
for i in axd.spines.values():
i.set_visible(False)
fig.colorbar(cax)
#设置热力图的x轴和y轴标记
axm.set_xticklabels([''] + list(df_rowclust.columns))
axm.set_yticklabels([''] + list(df_rowclust.index))
plt.show()
用sklearn库中的AgglomerativeClustering()函数
from sklearn.cluster import AgglomerativeClustering
# n_clusters:设置簇的个数
# linkage:设置判定标准
ac = AgglomerativeClustering(n_clusters=2,affinity="euclidean",linkage="complete")
labels = ac.fit_predict(data)
print(labels)
#[1 0 0 0 1]