聚类与分类不同,聚类是针对给定的样本,依据他们的相似程度或距离,将其归为若干个类或簇的数据分析问题,属于无监督学习。聚类算法是在聚类之前并没有标签,之后聚类之后才会知道它属于哪个类别。本博客仅介绍两种常见的聚类算法:层次聚类和Kmeans聚类。
层次聚类具有聚合(自下而上)和分裂(自上而下)两种方法。聚合法是将样本各自分到一个类,之后将相距最近的两类合并成新的类,重复此步骤直至满足条件,得到层次化的类别。分裂法是将所以样本分到一个类,之后将距离最远的样本分到两个新的类,重复此步骤直至满足条件,得到层次化的类别。
给定5个样本的集合,样本间的欧氏距离如下矩阵D所示:其中 d i j d_ij dij为第i个样本与第j个样本间的欧氏距离。显然D为对称矩阵。利用聚合层次聚类法对五个样本进行聚类。
D = [ d i j ] 5 ∗ 5 [ 0 7 2 9 3 7 0 5 4 6 2 5 0 8 1 9 4 8 0 5 3 6 1 5 0 ] D = [d_{ij}]_{5*5} \begin{bmatrix} 0 & 7 & 2 & 9 & 3\\ 7 & 0 & 5 & 4 & 6\\ 2 & 5 & 0 & 8 & 1\\ 9 & 4 & 8 & 0 & 5\\ 3 & 6 & 1 & 5 & 0\\ \end{bmatrix} D=[dij]5∗5⎣⎢⎢⎢⎢⎡0729370546250819480536150⎦⎥⎥⎥⎥⎤
(1)首先用5个样本构成5个类, G i = x i , i = 1 , 2 , 3 , 4 , 5 G_i={x_i},i=1,2,3,4,5 Gi=xi,i=1,2,3,4,5,这样,样本间的距离即为类别间距。
(2)由矩阵D可知 d 3 5 d_35 d35= d 5 3 d_53 d53=1最小,所以把 G 3 G_3 G3和 G 5 G_5 G5合并为一个新类,记为 G 6 = { x 3 , x 5 } G_6=\{x_3,x_5\} G6={x3,x5}
(3)继续计算新类与其余类间的距离: d 61 = 2 , d 62 = 5 , d 64 = 5 , d 12 = 7 , d 14 = 9 , d 24 = 4 d_{61}=2,d_{62}=5,d_{64}=5,d_{12}=7,d_{14}=9,d_{24}=4 d61=2,d62=5,d64=5,d12=7,d14=9,d24=4,最小的是类6和类1间距离为2,因此将类6和类1归为新的类,记为 G 7 = { x 1 , x 3 , x 5 } G_7=\{x_1,x_3,x_5\} G7={x1,x3,x5}。这里简单说一下 d 61 = 2 d_{61}=2 d61=2的由来:因为 d 13 = 2 , d 15 = 3 d_{13}=2,d_{15}=3 d13=2,d15=3,2<3,所以 d 61 = 2 d_{61}=2 d61=2= d 31 d_{31} d31。其余同理。
(4)计算 G 7 G_7 G7与 x 2 , x 4 x_2,x_4 x2,x4间的距离, d 72 = 5 , d 74 = 5 , d 24 = 4 d_{72}=5,d_{74}=5,d_{24}=4 d72=5,d74=5,d24=4,将 x 2 , x 4 x_2,x_4 x2,x4归为一类,即 G 8 = { x 2 , x 4 } G_8=\{x_2,x_4\} G8={x2,x4}。
(5)到现在为止,5个样本形成了两个类,分别为 G 7 = { x 1 , x 3 , x 5 } G_7=\{x_1,x_3,x_5\} G7={x1,x3,x5}, G 8 = { x 2 , x 4 } G_8=\{x_2,x_4\} G8={x2,x4},继续将 G 7 , G 8 G_7,G_8 G7,G8归为一类,记为 G 9 G_9 G9。全部样本已经归为同一类,终止聚类。
k均值聚类是基于中心的聚类算法,通过迭代,将样本分到k个类中,使每个样本与其所属类的中心或均值最近,得到k个非层次化的类别,构成对空间的划分。
给定含有5个样本的集合:
X = [ 0 0 1 5 5 2 0 0 0 2 ] X = \begin{bmatrix} 0 & 0 & 1 & 5 & 5\\ 2 & 0 & 0 & 0 & 2\\ \end{bmatrix} X=[0200105052]
试用Kmeans均值聚类算法将样本聚类到两个类别中。
解:
(1)先确定两个初始聚类中心,假设选择 x 1 = ( 0 , 2 ) T , x 2 = ( 0 , 0 ) T x_1=(0,2)^T,x_2=(0,0)^T x1=(0,2)T,x2=(0,0)T,分别为类别 G 1 , G 2 G_1,G_2 G1,G2;
(2)计算各样本到聚类中心的欧式距离的平方(方便计算)并进行归类:
d 13 = 5 , d 23 = 1 d_{13}=5,d_{23}=1 d13=5,d23=1,将 x 3 x_3 x3划分到 G 2 G_2 G2类中;
d 14 = 29 , d 24 = 25 d_{14}=29,d_{24}=25 d14=29,d24=25,将 x 4 x_4 x4划分到 G 2 G_2 G2类中;
d 15 = 25 , d 25 = 29 d_{15}=25,d_{25}=29 d15=25,d25=29,将 x 5 x_5 x5划分到 G 1 G_1 G1类中;
得到新的类别: G 1 = { x 1 , x 5 } G_1=\{x_1,x_5\} G1={x1,x5}, G 2 = { x 2 , x 3 , x 4 } G_2=\{x_2,x_3,x_4\} G2={x2,x3,x4}
(3)计算新的聚类中心。 G 1 = ( 2.5 , 2 ) T , G 2 = ( 2 , 0 ) T G1=(2.5,2)^T,G2=(2,0)^T G1=(2.5,2)T,G2=(2,0)T
(4)计算各样本到新聚类中心的距离: 现在的G类为空了,但是有聚类中心,重新聚类
d 11 = 6.25 , d 12 = 8 d_{11}=6.25,d_{12}=8 d11=6.25,d12=8,将 x 1 x_1 x1划分到 G 1 G_1 G1类中;
d 21 = 10.25 , d 22 = 4 d_{21}=10.25,d_{22}=4 d21=10.25,d22=4,将 x 2 x_2 x2划分到 G 2 G_2 G2类中;
d 31 = 6.25 , d 32 = 1 d_{31}=6.25,d_{32}=1 d31=6.25,d32=1,将 x 3 x_3 x3划分到 G 2 G_2 G2类中;
d 41 = 10.25 , d 42 = 9 d_{41}=10.25,d_{42}=9 d41=10.25,d42=9,将 x 4 x_4 x4划分到 G 2 G_2 G2类中;
d 51 = 6.25 , d 52 = 13 d_{51}=6.25,d_{52}=13 d51=6.25,d52=13,将 x 5 x_5 x5划分到 G 1 G_1 G1类中;
得到新的类别: G 1 = { x 1 , x 5 } G_1=\{x_1,x_5\} G1={x1,x5}, G 2 = { x 2 , x 3 , x 4 } G_2=\{x_2,x_3,x_4\} G2={x2,x3,x4} 聚类结果不变,聚类终止。
最终聚类结果即为 G 1 = { x 1 , x 5 } G_1=\{x_1,x_5\} G1={x1,x5}, G 2 = { x 2 , x 3 , x 4 } G_2=\{x_2,x_3,x_4\} G2={x2,x3,x4}。
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import scipy.cluster.hierarchy as sch #
from sklearn.cluster import AgglomerativeClustering
disMat = np.array([[0,7,2,9,3],
[7,0,5,4,6],
[2,5,0,8,1],
[9,4,8,0,5],
[3,6,1,5,0]])
Z = sch.linkage(disMat,method='ward')
sch.dendrogram(Z,labels=list(['x1','x2','x3','x4','x5']))
plt.text(15,3.8,'G6',fontdict={'size':12})
plt.text(10,6,'G7',fontdict={'size':12})
plt.text(35,7,'G8',fontdict={'size':12})
plt.text(25,18,'G9',fontdict={'size':12})
plt.yticks(range(0,23,5))
plt.show() # 图即为上面的层次聚类图
# # euclidean欧式距离 ward合并的类的方差最小化 n_clusters=3 分为三类
ac = AgglomerativeClustering(n_clusters=3, affinity='euclidean', linkage='ward')
ac.fit(disMat)
labels = ac.fit_predict(disMat)
print(labels) # [0 2 0 1 0] x1,x3,x5为一类;x2为一类;x4为一类; 与上面我们计算的分类一致。
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from sklearn import preprocessing
df = pd.read_csv('K-Means数据集.txt',sep='\t',header=None,usecols=[0,1,2],names=['a','b','c'])
x = preprocessing.StandardScaler().fit_transform(df[['a','b']]) # 只要两个特征
klist = []
for k in range(1,10):
kmn=KMeans(n_clusters=k)
kmn.fit_predict(x)
klist.append(kmn.inertia_) # 误差平方和
plt.plot(range(1,10),klist,marker='o') # 当k= 4的时候逐渐平缓 所以我们选择k=4
kmn=KMeans(n_clusters=4)
res=kmn.fit_predict(x)
lable_pred=kmn.labels_ # 聚类的标签即类别
centers=kmn.cluster_centers_ # 聚类中心
print(centers)
# 四个类别的聚类中心
[[-0.9961586 -0.87182378]
[ 1.60044603 0.90738041]
[-0.11462682 0.86531506]
[ 0.57360717 -0.76353259]]
# 对两个点进行预测 类别分别为0 和 2 下面可视化 将两个点也加了进去 预测准确
kmn.predict([[0,2],[1,-0.5]]) # array([0, 2])
plt.scatter(x[x['y']==0]['a'],x[x['y']==0]['b'],label=0)
plt.scatter(x[x['y']==1]['a'],x[x['y']==1]['b'],label=1)
plt.scatter(x[x['y']==2]['a'],x[x['y']==2]['b'],label=2)
plt.scatter(x[x['y']==3]['a'],x[x['y']==3]['b'],label=3)
plt.scatter(x=0,y=2,marker='o',color='k',s=100)
plt.scatter(x=1,y=-0.5,marker='o',color='k',s=100)
plt.legend()
plt.show()
from mpl_toolkits.mplot3d import Axes3D # 空间三维画图
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
df = pd.read_csv('K-Means数据集.txt',sep='\t',header=None,usecols=[0,1,2],names=['a','b','c'])
x = preprocessing.StandardScaler().fit_transform(df)
estimator=KMeans(n_clusters=4)
res=estimator.fit_predict(x)
lable_pred=estimator.labels_
centers=estimator.cluster_centers_
inertia=estimator.inertia_
print(centers) # 聚类中心
[[-0.67604892 -0.78556506 0.90579587]
[ 0.50573115 0.70181006 0.90113919]
[ 0.78663516 0.87904113 -0.80456021]
[-0.61783656 -0.78968316 -0.84178368]]
x = pd.DataFrame(x)
x.columns = ['a','b','c']
x['y'] = lable_pred
x = pd.DataFrame(x)
x.columns = ['a','b','c']
x['y'] = lable_pred
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(x[x['y']==0]['a'],x[x['y']==0]['b'],x[x['y']==0]['c'],color='red')
ax.scatter(x[x['y']==1]['a'],x[x['y']==1]['b'],x[x['y']==1]['c'],color='blue')
ax.scatter(x[x['y']==2]['a'],x[x['y']==2]['b'],x[x['y']==2]['c'],color='green')
ax.scatter(x[x['y']==3]['a'],x[x['y']==3]['b'],x[x['y']==3]['c'],color='pink')
# 添加坐标轴(顺序是Z, Y, X)
ax.set_zlabel('Z', fontdict={'size': 15, 'color': 'red'})
ax.set_ylabel('Y', fontdict={'size': 15, 'color': 'red'})
ax.set_xlabel('X', fontdict={'size': 15, 'color': 'red'})
# 展示
plt.show()