笔记|聚类分析基础《Python数学实验与建模》

发布时间 2023-08-07 17:09:53作者: LateSpring

参考图书为:《Python数学实验与建模》司守奎,孙玺菁

定义

将相似元素聚为一类
通常分为Q型聚类(样本聚类)、R型聚类(指标聚类)。

数据变换

\(A= \begin{pmatrix}a_{11}&a_{12}&a_{13}&\cdots&a_{1p}\\ a_{21}&a_{22}&a_{23}&\cdots&a_{2p}\\ a_{31}&a_{32}&a_{33}&\cdots&a_{3p}\\\cdots&\cdots&\cdots&\cdots&\cdots&\\a_{n1}&a_{n2}&a_{n3}&\cdots&a_{np}\end{pmatrix}\)
通常不同指标有不同量纲,所以要数据变换

1.规格化变换

IMG_20220209_153954-01.jpeg

2.标准化变换

IMG_20220209_154248-01.jpeg

变换后矩阵为
\(B= \begin{pmatrix}b_{11}&b_{12}&b_{13}&\cdots&b_{1p}\\ b_{21}&b_{22}&b_{23}&\cdots&b_{2p}\\ b_{31}&b_{32}&b_{33}&\cdots&b_{3p}\\\cdots&\cdots&\cdots&\cdots&\cdots&\\b_{n1}&b_{n2}&b_{n3}&\cdots&b_{np}\end{pmatrix}\)

样本间亲疏程度的测度计算

1.算常用距离

1)闵式距离

2)马氏距离

2.相似系数计算

1)夹角余弦

IMG_20220209_155425_edit_322843791260112.jpg
IMG_20220209_155551_edit_322929786421036.jpg

2)皮尔逊相关系数

IMG_20220209_155858_edit_323135256217359.jpg

基于类间距离的层次聚类

基本操作

1)将每个样品独自聚成一类,构造n个类
2)由两两距离构造距离矩阵
3)把距离最近的两个样品归为一类
4)计算新类与当前其他类的距离,将距离最近的两类聚成新类,重复第四步,直到所有样品聚成一类
5)画聚类谱系图
6)决定类的个数以及各类的样品数,并对类做出解释
类与类之间用不同的方法定义距离,可以用两类间最近样品的距离,也可以是两类间最远样品的距离,也可以是两类样本重心之间的距离

1.最短距离法

代码实现

import numpy as np
from sklearn import preprocessing as pp
import scipy.cluster.hierarchy as sch
import matplotlib.pyplot as plt
a=np.loadtxt("Pdata11_11.txt")
b=pp.minmax_scale(a.T)   #数据规格化
d = sch.distance.pdist(b)  #求对象之间的两两距离向量
dd = sch.distance.squareform(d)  #转换为矩阵格式
z=sch.linkage(d); print(z) #进行聚类并显示
s=[str(i+1) for i in range(7)]; plt.rc('font',size=16)
sch.dendrogram(z,labels=s); plt.show()  #画聚类图

输出结果

[[ 3.          4.          0.16258132  2.        ]
 [ 0.          2.          0.27853564  2.        ]
 [ 1.          8.          0.35618248  3.        ]
 [ 5.          6.          0.37626539  2.        ]
 [ 7.          9.          0.47781458  5.        ]
 [10.         11.          1.01602914  7.        ]]

figure11_11.png

2.最长距离法

import numpy as np
from sklearn import preprocessing as pp
import scipy.cluster.hierarchy as sch
import matplotlib.pyplot as plt
a=np.loadtxt("Pdata11_11.txt")
b=pp.minmax_scale(a.T)   #数据规格化
d = sch.distance.pdist(b)  #求对象之间的两两距离向量
z=sch.linkage(d,'complete'); print(z)  #进行聚类并显示
s=[str(i+1) for i in range(7)]; plt.rc('font',size=16)
sch.dendrogram(z,labels=s); plt.show()  #画聚类图

输出结果

[[ 3.          4.          0.16258132  2.        ]
 [ 0.          2.          0.27853564  2.        ]
 [ 5.          6.          0.37626539  2.        ]
 [ 1.          8.          0.54290736  3.        ]
 [ 7.         10.          1.01397033  5.        ]
 [ 9.         11.          1.57203348  7.        ]]

figure11_12.png

K均值聚类

先粗略分类,最后优化
假定全体样本可分成C类,并选出C个初始聚类中心,然后根据距离最小原则分配样本点,同时迭代各类的聚类中心,最后直到迭代收敛或聚类中心不再改变
IMG_20220209_180624_edit_328850851196175.jpg

K均值聚类确定k值

此处k值即之前的C值

1.簇内离差平方和拐点法

在该拐点之后增加簇的个数,簇内离差平方和趋于平稳,在之前增加簇的个数,离差平方和大幅降低

代码实现

import numpy as np  
import matplotlib.pyplot as plt; from sklearn.cluster import KMeans
mean=np.array([[-2, -2],[2, 2], [6,6]])
cov=np.array([[[0.3, 0], [0, 0.3]],[[0.4, 0], [0, 0.4]],[[0.5, 0], [0, 0.5]]])
x0=[]; y0=[];
for i in range(3):
    x,y=np.random.multivariate_normal(mean[i], cov[i],1000).T
    x0=np.hstack([x0,x]); y0=np.hstack([y0,y])
plt.rc('font',size=16); plt.rc('font',family='SimHei')
plt.rc('axes',unicode_minus=False); plt.subplot(121)
plt.scatter(x0,y0,marker='.')  #画模拟数据散点图
X=np.vstack([x0,y0]).T
np.save("Pzdata11_1.npy",X)  #保存数据供下面使用
TSSE=[]; K=10
for k in range(1,K+1):
    SSE = []
    md = KMeans(n_clusters=k); md.fit(X)
    labels = md.labels_; centers = md.cluster_centers_
    for label in set(labels):
        SSE.append(np.sum((X[labels == label,:]-centers[label,:])**2))
    TSSE.append(np.sum(SSE))
plt.subplot(122); plt.style.use('ggplot')
plt.plot(range(1,K+1), TSSE, 'b*-')
plt.xlabel('簇的个数'); plt.ylabel('簇内离差平方和之和'); plt.show()

Figure_1.png

2.轮廓系数法

IMG_20220209_182023_edit_329697099021566.jpg
k个簇的总轮廓系数定义为所有样本点轮廓系数的平均值
总轮廓系数<0,聚类效果不佳;而越接近1越理想。
但是这种方法计算量较大

import numpy as np; import matplotlib.pyplot as plt
from sklearn.cluster import KMeans; from sklearn import metrics
X=np.load("Pzdata11_1.npy")
S=[]; K=10
for k in range(2,K+1):
    md = KMeans(k); md.fit(X)
    labels = md.labels_;
    S.append(metrics.silhouette_score(X,labels,metric='euclidean'))  #计算轮廓系数
plt.rc('font',size=16); plt.rc('font',family='SimHei')
plt.plot(range(2,K+1), S, 'b*-')
plt.xlabel('簇的个数'); plt.ylabel('轮廓系数'); plt.show()

Figure_1.png
可见选择3最好