聚类简介与基本概念

# 只需 shift+回车 运行本单元格,就可以让jupyter notebook宽屏显示
from IPython.core.display import display, HTML
display(HTML('<style>.container { width:100% !important; }</style>'))
# jupyter notebook 笔记高亮
# <div class="alert alert-block alert-success">
# 绿色警示框:成功 alert-success<br>
# 蓝色警示框:信息提示 alert-info<br>
# 红色警示框:高危 alert-danger<br>
# 黄色警示框:警告 alert-warning
# </div>

1 聚类简介

  • 物以类聚,人以群分,即为聚类。聚类是将样本集合中相似的样本分配到相同的类,不同的样本分配到不同的类。
  • 聚类分为硬聚类和软聚类。如果一个样本只能属于一个类为硬聚类,如果一个样本可以属于多个类则为软聚类。
  • 聚类属于无监督学习,因为只是根据样本的相似度或距离将其进行归类,而类或簇事先并不知道。

2 聚类的基本概念

2.1 相似度或距离

  • 聚类的核心就是相似度或距离,相似度直接影响聚类的结果,因此选择合适的相似度至关重要。

2.1.1 闵可夫斯基距离

  • 聚类中,将样本集合看作为向量空间中点的集合,以该空间的距离来表示样本之间的相似度。
  • 闵可夫斯基距离越大相似度越小,距离越小相似度越大。

给定样本集合 X X X, X X X m m m维实数向量空间 R m R^m Rm,其中 x i , x j ∈ X x_i,x_j\in X xi,xjX x i = ( x 1 i , x 2 i , … , x m i ) x_i=(x_{1i},x_{2i},\dots,x_{mi}) xi=(x1i,x2i,,xmi) x j = ( x 1 j , x 2 j , … , x m j ) x_j=(x_{1j},x_{2j},\dots,x_{mj}) xj=(x1j,x2j,,xmj),样本闵可夫斯基距离定义为:

d i j = ( ∑ k = 1 m ∣ x k i − x k j ∣ P ) 1 p (1) d_{ij}=\left(\sum_{k=1}^m|x_{ki}-x_{kj}|^P\right)^{\frac1p}\tag{1} dij=(k=1mxkixkjP)p1(1)

这里 p ≥ 1 p\geq1 p1。当 p = 2 p=2 p=2时称为欧氏距离,即:

d i j = ( ∑ k = 1 m ∣ x k i − x k j ∣ 2 ) 1 2 (2) d_{ij}=\left(\sum_{k=1}^m|x_{ki}-x_{kj}|^2\right)^{\frac12}\tag{2} dij=(k=1mxkixkj2)21(2)

P = 1 P=1 P=1时称为曼哈顿距离,即:

d i j = ( ∑ k = 1 m ∣ x k i − x k j ∣ ) (3) d_{ij}=\left(\sum_{k=1}^m|x_{ki}-x_{kj}|\right)\tag{3} dij=(k=1mxkixkj)(3)

p = ∞ p=\infty p=时称为切比雪夫距离,取各个坐标值差的绝对值的最大值,即:

d i j = max ⁡ k ∣ x k i − x k j ∣ (4) d_{ij}=\max \limits_{k} \left|x_{ki}-x_{kj}\right| \tag{4} dij=kmaxxkixkj(4)

import numpy as np
test = np.random.randint(0,10,(2,3))
a = test[1]
b = test[0]
print(a,b)
[7 5 1] [7 0 8]
def d_HM(p,x_ki,x_kj):
    # p为选择的距离算法;x_ki,x_kj均为一行的二维数组
    # 曼哈顿距离
    if p == 1:
        distance = np.fabs(x_ki - x_kj).sum()
    # 欧式距离
    elif p == 2:
        a = x_ki - x_kj
        distance = np.dot(a,a.T)**0.5
    # 切比雪夫距离
    elif p >= 99:
        distance = np.fabs(x_ki - x_kj).max()
    else:
        a = x_ki - x_kj
        d = 0
        for i in range(len(a)):
            c = abs(a[i]) ** p
            d = d + c
        distance = d ** (1 / p)
    return distance.round(3)

d_HM(2,a,b)
8.602

2.1.2 马哈拉诺比斯距离

  • 马哈拉诺比斯距离简称为马氏距离
  • 考虑了各个分量(特征)之间的相关性与各个分量的尺度无关。
  • 马氏距离越大相似度越小,越小相似度越大。

给定样本集合 X X X X = ( x i j ) m × n X=\left(x_{ij}\right)_{m\times n} X=(xij)m×n,其协方差矩阵记为 S S S。样本 x i x_i xi与样本 x j x_j xj之间马氏距离 d i j d_{ij} dij定义为:

d i j = [ ( x i − x j ) T S − 1 ( x i − x j ) ] 1 2 (5) d_{ij}=\left[\left(x_i-x_j\right)^T S^{-1}\left(x_i-x_j\right) \right]^\frac12 \tag{5} dij=[(xixj)TS1(xixj)]21(5)

其中:

x i = ( x 1 i , x 2 i , … , x m i ) T ; x j = ( x 1 j , x 2 j , … , x m j ) (6) x_i=\left(x_{1i},x_{2i},\dots,x_{mi}\right)^T ; x_j=\left(x_{1j},x_{2j},\dots,x_{mj}\right)\tag{6} xi=(x1i,x2i,,xmi)T;xj=(x1j,x2j,,xmj)(6)

S S S为单位矩阵时,即样本数据的各个分量相互独立且各个分量的方差为 1 1 1,由(5)式可知,马氏距离即为欧式距离,是欧式距离的推广。

from scipy import linalg
def d_PCM(S,xi,xj):
    d = np.dot(xi - xj,linalg.inv(S))
    distance = np.dot(d,(xi-xj).T) ** 0.5
    return distance.round(3)
# 当协方差阵为单位矩阵时
S = np.eye(3)
d_PCM(S,a,b)
8.602

2.1.3 相关系数

  • 样本之间的相似度也可以用相关系数来表示。
  • 相关系数的绝对值接近于 1 1 1时,表示样本越相似;接近于 0 0 0时,样本就越不相似。

样本 x i x_i xi与样本 x j x_j xj之间的相关系数定义为:

r i j = ∑ k = 1 m ( x k i − x i ˉ ) ( x k j − x j ˉ ) [ ∑ k = 1 m ( x k i − x ˉ i ) 2 ∑ k = 1 m ( x k j − x ˉ j ) 2 ] 1 2 (7) r_{ij}=\frac{\sum_{k=1}^{m}(x_{ki}-\bar{x_i})(x_{kj}-\bar{x_j})}{\left[\sum_{k=1}^m{\left(x_{ki}-\bar{x}_i\right)^2}\sum_{k=1}^m{\left(x_{kj}-\bar{x}_j\right)^2}\right]^\frac12}\tag{7} rij=[k=1m(xkixˉi)2k=1m(xkjxˉj)2]21k=1m(xkixiˉ)(xkjxjˉ)(7)

其中:

x ˉ i = 1 m ∑ k = 1 m x k i ; x ˉ j = 1 m ∑ k = 1 m x k j (8) \bar{x}_i=\frac1m\sum_{k=1}^m{x_{ki}} ; \bar{x}_j=\frac1m\sum_{k=1}^m{x_{kj}}\tag{8} xˉi=m1k=1mxki;xˉj=m1k=1mxkj(8)

def r(xi,xj):
    a,b,c = [],[],[]
    for i in range(len(xi)):
        x_i = xi[i] - xi.mean()
        x_j = xj[i] - xj.mean()
        a.append(x_i * x_j)
        b.append(x_i**2)
        c.append(x_j**2)
    a,b,c = sum(a),sum(b),sum(c)
    r = a / ((b * c) ** (1 / 2)) 
    return r.round(3)
r(a,b)
-0.3

2.1.4 夹角余弦

  • 夹角余弦接近于 1 1 1时,表示样本越相似;接近于 0 0 0时,样本就越不相似。

样本 x i x_i xi与样本 x j x_j xj之间的夹角余弦定义为:

s i j = ∑ k = 1 m x k i x k j [ ∑ k = 1 m x k i 2 ∑ k = 1 m x k j 2 ] 1 2 (9) s_{ij}=\frac{\sum_{k=1}^m{x_{ki}x_{kj}}}{\left[\sum_{k=1}^{m}{x_{ki}^2}\sum_{k=1}^m{x_{kj}^2}\right]^{\frac12}}\tag{9} sij=[k=1mxki2k=1mxkj2]21k=1mxkixkj(9)

def s(xi,xj):
    s = np.dot(xi,xj.T) / (np.dot(xi,xi.T) * np.dot(xj,xj.T) ** 0.5)
    return s.round(3)
s(a,b)
0.071

2.1.5 总结

  • 距离度量相似度时,距离越小样本越相似;用相关系数时,相关系数越大样本越相似。
  • 不同相似度度量得到的结果并不一定相同,可能存在着差异。

2.2 类或簇

  • 聚类得到的类或簇,为样本的子集。当样本只属于一个类或类的交集为空集,则该方法为硬聚类;反之则为软聚类。

  • G G G表示类或簇; x i , x j x_i,x_j xi,xj表示类中的样本,用 n G n_G nG表示 G G G中的样本个数; d i j d_{ij} dij表示样本 x i , x j x_i,x_j xi,xj之间的距离。

T T T为给定正数, G G G中任意两个样本 x i , x j x_i,x_j xi,xj,有 d i j ≤ T d_{ij}\leq T dijT,则称 G G G为一个类或簇。

T T T为给定正数, G G G中任意样本 x i x_i xi,一定存在样本 x j x_j xj,有 d i j ≤ T d_{ij}\leq T dijT,则称 G G G为一个类或簇。

T T T为给定正数, G G G中任意样本 x i x_i xi,另一个样本 x j x_j xj满足, 1 n G − 1 ∑ x j ∈ G d i j ≤ T \frac1{n_G-1}\sum_{x_j\in G}{d_{ij}}\leq T nG11xjGdijT,则称 G G G为一个类或簇。

T , V T,V T,V为给定正数, G G G中任意两个样本 x i , x j x_i,x_j xi,xj满足, 1 n G ( n G − 1 ) ∑ x i ∈ G ∑ x j ∈ G d i j ≤ T \frac1{n_G(n_G-1)}\sum_{x_i\in G}{\sum_{x_j\in G}{d_{ij}}}\leq T nG(nG1)1xiGxjGdijT d i j ≤ V d_{ij}\leq V dijV,则称 G G G为一个类或簇。

  • 这四种定义,第一个较为常用,由此可推出下面的三个定义。
""" 
据定义①,并根据欧式距离进行归类
"""
# 导入库
import numpy as np
import pandas as pd
from scipy import linalg

# 创建数据
test = np.random.randint(0,100,(40,2))
df = pd.DataFrame(test,columns=list("XY"))
# 用pandas查看数据
df.head(3)
XY
05284
12067
2936
# 随机选取两个样本,并计算其他样本分别与这两个样本的距离
test = np.random.randint(0,40,2)
c = [] # 与df.loc[test[0]] 一类
d = [] # 与tdf.loc[test[1]] 一类
d_c = [] # 与df.loc[test[0]] 一类的距离
d_d = [] # 与df.loc[test[1]] 一类的距离
for i in df.index:
    if i not in test:
        a = d_HM(2,df.loc[i].values,df.loc[test[0]])
        d_c.append(a)
        b = d_HM(2,df.loc[i].values,df.loc[test[1]])
        d_d.append(b)
        # 根据距离的大小进行分类
        if a < b:
            c.append(i)
        else:
            d.append(i)
print("第一类:",test[0],c,"最大距离为:{}".format(max(d_c)),"\n","第二类:",test[1],d,"最大距离为:{}".format(max(d_d)))
第一类: 10 [0, 1, 4, 6, 7, 8, 11, 12, 13, 14, 18, 19, 22, 24, 25, 28, 29, 30, 31, 33, 34, 36, 37, 38, 39] 最大距离为:94.921 
第二类: 32 [2, 3, 5, 9, 15, 16, 17, 20, 21, 23, 26, 27, 35] 最大距离为:127.279
# 可视化
import matplotlib.pyplot as plt
import matplotlib
# matplotlib.style.use("ggplot")
%matplotlib inline

df1 = df.loc[c]
df2 = df.loc[d]
plt.figure(figsize=(14,8))
plt.scatter(df1["X"],df1["Y"],s=200,c="blue",marker="*")
plt.scatter(df2["X"],df2["Y"],s=200,c="green",marker="o")
plt.scatter(df.loc[test[0]]["X"],df.loc[test[0]]["Y"],s=900,c="blue",marker="*")
plt.scatter(df.loc[test[1]]["X"],df.loc[test[1]]["Y"],s=900,c="green",marker="o")
<matplotlib.collections.PathCollection at 0x1af898db8d0>

在这里插入图片描述

  • 类的特征:

① 类的均值,即类的中心: x ˉ G = 1 n G ∑ i = 1 n G x i \bar{x}_G=\frac1{n_G}\sum_{i=1}^{n_G}{x_i} xˉG=nG1i=1nGxi

② 类的直径(任意两个样本之间的最大距离): D G = max ⁡ x i , x j ∈ G d i j D_G=\max \limits_{x_i,x_j\in G}d_{ij} DG=xi,xjGmaxdij

③ 类的样本散步矩阵 A G A_G AG和样本协方差矩阵 S G S_G SG A G = ∑ i = 1 n G ( x i − x ˉ G ) ( x i − x ˉ G ) T A_G=\sum_{i=1}^{n_G}(x_i-\bar{x}_G)(x_i-\bar{x}_G)^T AG=i=1nG(xixˉG)(xixˉG)T S G = 1 m − 1 A G S_G=\frac1{m-1}A_G SG=m11AG m m m为样本的维数

c.append(test[0])
d.append(test[1])
G1 = df.loc[c]
G1.reset_index(drop=True,inplace=True)
G2 = df.loc[d]
G2.reset_index(drop=True,inplace=True)
# 查看G1的聚类中心点
aa = (G1["X"].sum() / len(G1)).round(3)
bb = (G1["Y"].sum() / len(G1)).round(3)
print("G1的聚类中心点为:",(aa,bb))
# 查看G2的聚类中心点
cc = (G2["X"].sum() / len(G2)).round(3)
dd = (G2["Y"].sum() / len(G2)).round(3)
print("G2的聚类中心点为:",(cc,dd))
G1的聚类中心点为: (30.269, 55.077)
G2的聚类中心点为: (74.143, 45.214)
# 查看类G1的直径
d_G1 = []
for i in G1.index:
    for j in G1.index:
        if i != j:
            d_G1.append(d_HM(2,G1.loc[i].values,G1.loc[j].values))
D_G1 = max(d_G1)
print("G1类的直径为:",D_G1)
# 查看类G2的直径
d_G2 = []
for i in G2.index:
    for j in G2.index:
        if i != j:
            d_G2.append(d_HM(2,G2.loc[i].values,G2.loc[j].values))
D_G2 = max(d_G2)
print("G2类的直径为:",D_G2)
G1类的直径为: 93.638
G2类的直径为: 92.087
# G1类散步矩阵
x_G1 = np.array([aa,bb]) # 聚类中心点
A_G = np.mat([[0,0],
           [0,0]])
for i in G1.index:
    a = G1.loc[i].values - x_G1
    b = np.mat(a).T * np.mat(a)
    A_G = A_G + b
print("G1类散步矩阵为:","\n",A_G)
# G1类样本协方差矩阵
S_G = A_G / (len(G1) - 1)
print("G1类样本协方差矩阵为:","\n",S_G)
G1类散步矩阵为: 
 [[ 8433.115386  3932.461538]
 [ 3932.461538 22535.846154]]
G1类样本协方差矩阵为: 
 [[337.32461544 157.29846152]
 [157.29846152 901.43384616]]
# G2类散步矩阵
x_G2 = np.array([cc,dd]) # 聚类中心点
A_G = np.mat([[0,0],
           [0,0]])
for i in G2.index:
    a = G2.loc[i].values - x_G2
    b = np.mat(a).T * np.mat(a)
    A_G = A_G + b
print("G2类散步矩阵为:","\n",A_G)
# G2类样本协方差矩阵
S_G = A_G / (len(G2) - 2)
print("G2类样本协方差矩阵为:","\n",S_G)
G2类散步矩阵为: 
 [[ 2787.714286  1014.571428]
 [ 1014.571428 10510.357144]]
G2类样本协方差矩阵为: 
 [[232.30952383  84.547619  ]
 [ 84.547619   875.86309533]]

2.3 类与类之间的距离

  • G p G_p Gp G q G_q Gq之间的距离 D ( p , q ) D_{(p,q)} D(p,q),也称为连接。
  • 设类类 G p G_p Gp包含 n p n_p np个样本,类 G q G_q Gq包含 n q n_q nq个样本,分别用 x ˉ p \bar{x}_p xˉp x ˉ q \bar{x}_q xˉq表示 G p G_p Gp G q G_q Gq的均值,即类的中心。

① 最短距离或单连接: D p q = m i n { d i j ∣ x i ∈ G p , x j ∈ G q } D_{pq}=min \{ d_{ij}|x_i \in G_p,x_j \in G_q \} Dpq=min{dijxiGp,xjGq}

② 最长距离或完全连接: D p q = m a x { d i j ∣ x i ∈ G p , x j ∈ G q } D_{pq}=max \{ d_{ij}|x_i \in G_p,x_j \in G_q \} Dpq=max{dijxiGp,xjGq}

③ 中心距离: D p q = d x ˉ p x ˉ q D_{pq}=d_{\bar{x}_p\bar{x}_q} Dpq=dxˉpxˉq

④ 平均距离: D p q = 1 n p n q ∑ x i ∈ G p ∑ x j ∈ G q d i j D_{pq}=\frac1{n_p n_q}\sum_{x_i \in G_p}{\sum_{x_j \in G_q}{d_{ij}}} Dpq=npnq1xiGpxjGqdij

# ① 最短距离或单连接
# 查看类G1的直径
d = []
for i in df.index:
    for j in range(i+1,len(df)):
        if i != j:
            d.append(d_HM(2,df.loc[i].values,df.loc[j].values))
print("最短距离或单连接为:",min(d))
print("最长距离或完全连接为:",max(d))

# 中心距离
d_center = d_HM(2,x_G1,x_G2)
print("两类的中心距离为:",d_center)
# 平均距离
d_G1_G2 = []
for i in G1.index:
    for j in G2.index:
        d_G1_G2.append(d_HM(2,G1.loc[i].values,G2.loc[j].values))
mean_d_G1_G2 = sum(d_G1_G2) / (len(G1) * len(G2))
print("两类的平均距离为:",mean_d_G1_G2.round(3))
最短距离或单连接为: 1.414
最长距离或完全连接为: 127.279
两类的中心距离为: 44.969
两类的平均距离为: 60.621
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

而又何羡乎

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值