摘要: 聚类是针对给定的样本,依据它们特征的相似度或距离,将其归并到若干个“类”或“簇”的数据分析问题。一个类是样本的一个子集。直观上,相似的样本聚集在相同的类,不相似的样本分散在不同的类。这里,样本之间的相似度或距离起着重要作用。
聚类的基本概念
首先定义一个矩阵X
用来表示n
个样本的m
个属性。
X
=
[
x
i
j
]
m
×
n
=
[
x
11
x
12
⋯
x
1
n
x
21
x
22
⋯
x
2
n
⋮
⋮
⋮
x
m
1
x
m
2
⋯
x
m
n
]
X = [x_{ij}]_{m\times n}= \begin{bmatrix} x_{11} & x_{12} & \cdots & x_{1n}\\ x_{21} & x_{22} & \cdots & x_{2n}\\ \vdots & \vdots & & \vdots\\ x_{m1} & x_{m2} & \cdots & x_{mn}\\ \end{bmatrix}
X=[xij]m×n=⎣⎢⎢⎢⎡x11x21⋮xm1x12x22⋮xm2⋯⋯⋯x1nx2n⋮xmn⎦⎥⎥⎥⎤
这里矩阵X
的定义是按照书上来的,1列代表一个样本,当然还有另外一种常见的写法是1行代表一个样本,怎么写都行。
相似度或距离
1)闵可夫斯基距离(距离越大相似度越小,距离越小相似度越大)
给定样本集合X
,X
是m
维实数向量空间
R
m
R^m
Rm中点的集合,其中
x
i
,
x
j
∈
X
,
x
i
=
(
x
1
i
,
x
2
i
,
⋯
,
x
m
i
)
T
x_i,x_j\in X,x_i=(x_{1i},x_{2i},\cdots,x_{mi})^T
xi,xj∈X,xi=(x1i,x2i,⋯,xmi)T,
x
j
=
(
x
1
j
,
x
2
j
,
⋯
,
x
m
j
)
T
x_j=(x_{1j},x_{2j},\cdots,x_{mj})^T
xj=(x1j,x2j,⋯,xmj)T,样本
x
i
x_i
xi与样本
x
j
x_j
xj的闵可夫斯基距离定义为
d
i
j
=
(
∑
k
=
1
m
∣
x
k
i
−
x
k
j
∣
p
)
1
p
d_{ij}=\left( \sum_{k=1}^m{\mid x_{ki}-x_{kj} \mid}^p \right)^{\frac{1}{p}}
dij=(k=1∑m∣xki−xkj∣p)p1
这里
p
≥
1
p\ge 1
p≥1。当
p
=
2
p=2
p=2时称为欧式距离,即
d
i
j
=
(
∑
k
=
1
m
∣
x
k
i
−
x
k
j
∣
2
)
1
2
d_{ij}=\left( \sum_{k=1}^m{\mid x_{ki}-x_{kj} \mid}^2 \right)^{\frac{1}{2}}
dij=(k=1∑m∣xki−xkj∣2)21
当
p
=
1
p=1
p=1时称为曼哈顿距离,即
d
i
j
=
∑
k
=
1
m
∣
x
k
i
−
x
k
j
∣
d_{ij}= \sum_{k=1}^m |x_{ki}-x_{kj} |
dij=k=1∑m∣xki−xkj∣
当
p
=
∞
p=\infty
p=∞时称为切比雪夫距离,取各个坐标数值差的绝对值的最大值,即
d
i
j
=
m
a
x
k
∣
x
k
i
−
x
k
j
∣
d_{ij}= \mathop{max}_k|x_{ki}-x_{kj} |
dij=maxk∣xki−xkj∣
接下来举个简单的例子把,假设
x
1
=
(
1
,
2
)
,
x
2
=
(
5
,
6
)
x_1=(1,2),x_2=(5, 6)
x1=(1,2),x2=(5,6)
那么闵可夫斯基距离为: ( 5 − 1 ) p + ( 6 − 2 ) p p \sqrt[p]{(5-1)^p+(6-2)^p} p(5−1)p+(6−2)p
欧式距离为: ( 5 − 1 ) p + ( 6 − 2 ) 2 2 = 32 2 \sqrt[2]{(5-1)^p+(6-2)^2}=\sqrt[2]{32} 2(5−1)p+(6−2)2=232
曼哈顿距离为: ∣ 5 − 1 ∣ + ∣ 6 − 2 ∣ = 8 |5-1| + |6-2| = 8 ∣5−1∣+∣6−2∣=8
切比雪夫距离为: m a x ( ∣ 5 − 1 ∣ , ∣ 6 − 2 ∣ ) = 4 max(|5-1|, |6-2|)=4 max(∣5−1∣,∣6−2∣)=4
2)马哈拉诺比斯距离(距离越大相似度越小,距离越小相似度越大)
给定一个样本集合X,
X
=
(
x
i
j
)
m
×
n
X={(x_{ij})}_{m\times n}
X=(xij)m×n,其协方差矩阵记作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
d_{ij}=\left[ (x_i-x_j)^TS^{-1}(x_i-x_j) \right]^{\frac{1}{2}}
dij=[(xi−xj)TS−1(xi−xj)]21
其中
x
i
=
(
x
1
i
,
x
2
i
,
⋯
,
x
m
i
)
T
x
j
=
(
x
1
j
,
x
2
j
,
⋯
,
x
m
j
)
T
x_i=(x_{1i},x_{2i},\cdots,x_{mi})^T~~~~x_j=(x_{1j},x_{2j},\cdots,x_{mj})^T
xi=(x1i,x2i,⋯,xmi)T xj=(x1j,x2j,⋯,xmj)T
当S为单位矩阵时,即样本数据的各个分量相互独立且各个分量的方差为1时,上式提到的马氏距离 d i j d_{ij} dij也就是欧式距离了,所以马氏距离是欧式距离的推广。
证明如下:
当S为单位矩阵时,那么 S − 1 S^{-1} S−1也是单位矩阵,即 S = S − 1 S=S^{-1} S=S−1。假设 x i = ( 1 , 2 , 3 ) , x j = ( 5 , 4 , 6 ) x_i=(1,2,3),x_j=(5,4,6) xi=(1,2,3),xj=(5,4,6)则:
d
i
j
=
[
[
1
−
5
2
−
4
3
−
6
]
T
[
1
0
0
0
1
0
0
0
1
]
[
1
−
5
2
−
4
3
−
6
]
]
1
2
=
(
−
4
)
2
+
(
−
2
)
2
+
(
−
3
)
2
2
d_{ij}={\left[ \begin{bmatrix} 1-5 \\ 2-4 \\ 3-6 \end{bmatrix} ^T \begin{bmatrix} 1 & 0 & 0\\ 0 & 1 & 0\\ 0 & 0 & 1 \end{bmatrix} \begin{bmatrix} 1-5 \\ 2-4 \\ 3-6 \end{bmatrix} \right] }^{\frac{1}{2}}\\ =\sqrt[2]{(-4)^2+(-2)^2+(-3)^2}
dij=⎣⎢⎡⎣⎡1−52−43−6⎦⎤T⎣⎡100010001⎦⎤⎣⎡1−52−43−6⎦⎤⎦⎥⎤21=2(−4)2+(−2)2+(−3)2
上式最后得到的结果也就是欧式距离的结果了。
现在来解释下什么叫做协方差矩阵:
方差和协方差的定义:
在统计学中,方差是用来度量单个随机变量的离散程度,而协方差则一般用来刻画两个随机变量的相似程度,其中,方差的计算公式为
σ x 2 = 1 n − 1 ∑ i = 1 n ( x i − x ˉ ) 2 \sigma_x^2=\frac{1}{n-1}\sum_{i=1}^n(x_i-\bar x)^2 σx2=n−11∑i=1n(xi−xˉ)2
其中, n n n表示样本量,符号 x ˉ \bar x xˉ表示观测样本的均值。
在此基础上,协方差的计算公式被定义为
σ ( x , y ) = 1 n − 1 ∑ i = 1 n ( x i − x ˉ ) ( y i − y ˉ ) \sigma(x, y)=\frac{1}{n-1} \sum_{i=1}^{n}\left(x_{i}-\bar{x}\right)\left(y_{i}-\bar{y}\right) σ(x,y)=n−11∑i=1n(xi−xˉ)(yi−yˉ)
在公式中,符号 x ˉ , y ˉ \bar{x}, \bar{y} xˉ,yˉ 分别表示两个随机变量所对应的观测样本均值,据此, 我们发现:方差 σ x 2 \sigma_{x}^{2} σx2 可视作随机变量 x x x 关于其自身的协方差 σ ( x , x ) \sigma(x, x) σ(x,x)。
从方差/协方差到协方差矩阵:
根据方差的定义, 给定
d
d
d 个随机变量
x
k
,
k
=
1
,
2
,
…
,
d
,
x_{k}, k=1,2, \ldots, d,
xk,k=1,2,…,d, 则这些随机变量的方差为
σ
(
x
k
,
x
k
)
=
1
n
−
1
∑
i
=
1
n
(
x
k
i
−
x
ˉ
k
)
2
,
k
=
1
,
2
,
…
,
d
\sigma\left(x_{k}, x_{k}\right)=\frac{1}{n-1} \sum_{i=1}^{n}\left(x_{k i}-\bar{x}_{k}\right)^{2}, k=1,2, \ldots, d
σ(xk,xk)=n−11∑i=1n(xki−xˉk)2,k=1,2,…,d
其中, 为方便书写, x k i \quad x_{k i} xki 表示随机变量 x k x_{k} xk 中的第 i i i 个观测样本, n \quad n n 表示样本量,每个随机变量所对应的观测样本数量均为 n n n 。
对于这些随机变量,我们还可以根据协方差的定义,求出两两之间的协方差, 即
σ
(
x
m
,
x
k
)
=
1
n
−
1
∑
i
=
1
n
(
x
m
i
−
x
ˉ
m
)
(
x
k
i
−
x
ˉ
k
)
\sigma\left(x_{m}, x_{k}\right)=\frac{1}{n-1} \sum_{i=1}^{n}\left(x_{m i}-\bar{x}_{m}\right)\left(x_{k i}-\bar{x}_{k}\right)
σ(xm,xk)=n−11i=1∑n(xmi−xˉm)(xki−xˉk)
因此, 协方差矩阵为
Σ
=
[
σ
(
x
1
,
x
1
)
⋯
σ
(
x
1
,
x
d
)
⋮
⋱
⋮
σ
(
x
d
,
x
1
)
⋯
σ
(
x
d
,
x
d
)
]
∈
R
d
×
d
\Sigma=\left[\begin{array}{ccc} \sigma\left(x_{1}, x_{1}\right) & \cdots & \sigma\left(x_{1}, x_{d}\right) \\ \vdots & \ddots & \vdots \\ \sigma\left(x_{d}, x_{1}\right) & \cdots & \sigma\left(x_{d}, x_{d}\right) \end{array}\right] \in \mathbb{R}^{d \times d}
Σ=⎣⎢⎡σ(x1,x1)⋮σ(xd,x1)⋯⋱⋯σ(x1,xd)⋮σ(xd,xd)⎦⎥⎤∈Rd×d
其中,对角线上的元素为各个随机变量的方差, 非良角线上的元素为两两随机变量之间的协方差, 根据协方差的定义,我们可以认定:矩阵
Σ
\Sigma
Σ 为对称矩阵(symmetric matrix),其大小为
d
×
d
d \times d
d×d。
3)相关系数(相关系数的绝对值越接近于1,表示样本越相似;越接近于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
r_{i j}=\frac{\sum_{k=1}^{m}\left(x_{k i}-\bar{x}_{i}\right)\left(x_{k j}-\bar{x}_{j}\right)}{\left[\sum_{k=1}^{m}\left(x_{k i}-\bar{x}_{i}\right)^{2} \sum_{k=1}^{m}\left(x_{k j}-\bar{x}_{j}\right)^{2}\right]^{\frac{1}{2}}}
rij=[∑k=1m(xki−xˉi)2∑k=1m(xkj−xˉj)2]21∑k=1m(xki−xˉi)(xkj−xˉj)
其中
x
ˉ
i
=
1
m
∑
k
=
1
m
x
k
i
,
x
ˉ
j
=
1
m
∑
k
=
1
m
x
k
j
\bar{x}_{i}=\frac{1}{m} \sum_{k=1}^{m} x_{k i}, \quad \bar{x}_{j}=\frac{1}{m} \sum_{k=1}^{m} x_{k j}
xˉi=m1k=1∑mxki,xˉj=m1k=1∑mxkj
4)夹角余弦(夹角余弦越接近于1,表示样本越相似;越接近于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
s_{i j}=\frac{\sum_{k=1}^{m} x_{k i} x_{k j}}{\left[\sum_{k=1}^{m} x_{k i}^{2} \sum_{k=1}^{m} x_{k j}^{2}\right]^{\frac{1}{2}}}
sij=[∑k=1mxki2∑k=1mxkj2]21∑k=1mxkixkj
类或簇
类或簇的四个定义:
1)设
T
T
T 为给定的正牧, 若集合 G 中任意两个样本
x
i
,
x
j
,
x_{i}, x_{j},
xi,xj, 有
d
i
j
⩽
T
d_{i j} \leqslant T
dij⩽T
则称G为一个类或簇。
2)设 T 为给定的正牧,若对集合 G 的任意样本
x
i
,
x_{i},
xi, 一定存在 G 中的另 个样本
x
j
,
x_{j},
xj, 使得
d
i
j
⩽
T
d_{i j} \leqslant T
dij⩽T
则称G为一个类或簇。
3)设
T
T
T 为给定的正数,若对集合
G
G
G 中任意一个样本
x
i
,
G
x_{i}, G
xi,G 中的另一个 样本
x
j
x_{j}
xj 满足
1
n
G
−
1
∑
x
j
∈
G
d
i
j
⩽
T
\frac{1}{n_{G}-1} \sum_{x_{j} \in G} d_{i j} \leqslant T
nG−11xj∈G∑dij⩽T
其中
n
G
为
G
中样本的个数, 则称
G
为一个类或籍。
\text { 其中 } n_{G} \text { 为 } G \text { 中样本的个数, 则称 } G \text { 为一个类或籍。 }
其中 nG 为 G 中样本的个数, 则称 G 为一个类或籍。
4)设 T 和 V 为给定的两个正牧,如果集合 G 中任意两个样本
x
i
,
x
j
x_{i}, x_{j}
xi,xj 的 距离
d
i
j
d_{i j}
dij 满足
1
n
G
(
n
G
−
1
)
∑
x
i
∈
G
∑
x
j
∈
G
d
i
j
⩽
T
d
i
j
⩽
V
\begin{array}{l} \frac{1}{n_{G}\left(n_{G}-1\right)} \sum_{x_{i} \in G} \sum_{x_{j} \in G} d_{i j} \leqslant T \\ d_{i j} \leqslant V \end{array}
nG(nG−1)1∑xi∈G∑xj∈Gdij⩽Tdij⩽V
则称 G 为一个类或籍。
类的三个特征:
1)类的均值
x
ˉ
G
\bar{x}_{G}
xˉG, 又称为类的中心
x
ˉ
G
=
1
n
G
∑
i
=
1
n
G
x
i
\bar{x}_{G}=\frac{1}{n_{G}} \sum_{i=1}^{n_{G}} x_{i}
xˉG=nG1i=1∑nGxi
式中
n
G
n_{G}
nG 是类
G
G
G 的样本个数。
2)类的直径 (diameter)
D
G
D_{G}
DG
类的直径 D_ 是类中任意两个样本之间的最大距离, 即
D
G
=
max
x
i
,
x
j
∈
G
d
i
j
D_{G}=\max _{x_{i}, x_{j} \in G} d_{i j}
DG=xi,xj∈Gmaxdij
3)类的样本散布矩阵
A
G
A_G
AG与样本协方差矩阵
S
G
S_G
SG
类的样本散布矩阵
A
G
A_G
AG为
A
G
=
∑
i
=
1
n
G
(
x
i
−
x
ˉ
G
)
(
x
i
−
x
ˉ
G
)
T
A_{G}=\sum_{i=1}^{n_{G}}\left(x_{i}-\bar{x}_{G}\right)\left(x_{i}-\bar{x}_{G}\right)^{\mathrm{T}}
AG=i=1∑nG(xi−xˉG)(xi−xˉG)T
样本协方差矩阵 SG 为
S
G
=
1
m
−
1
A
G
=
1
m
−
1
∑
i
=
1
n
C
(
x
i
−
x
ˉ
G
)
(
x
i
−
x
ˉ
G
)
T
\begin{aligned} S_{G} &=\frac{1}{m-1} A_{G} \\ &=\frac{1}{m-1} \sum_{i=1}^{n_{C}}\left(x_{i}-\bar{x}_{G}\right)\left(x_{i}-\bar{x}_{G}\right)^{\mathrm{T}} \end{aligned}
SG=m−11AG=m−11i=1∑nC(xi−xˉG)(xi−xˉG)T
其中 m 为样本的维数(样本属性的个数)。
类与类之间的距离
设类 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 的 均值,即类的中心。
1)最短距离或单连接
定义类
G
p
G_{p}
Gp 的样本与
G
q
G_{q}
Gq 的样本之间的最短距离为两类之间的距离
D
p
q
=
min
{
d
i
j
∣
x
i
∈
G
p
,
x
j
∈
G
q
}
D_{p q}=\min \left\{d_{i j} \mid x_{i} \in G_{p}, x_{j} \in G_{q}\right\}
Dpq=min{dij∣xi∈Gp,xj∈Gq}
2)最长距离或完全连接
定义类
G
p
G_{p}
Gp 的样本与
G
q
G_{q}
Gq 的样本之间的最长距离为两类之间的距离
D
p
q
=
max
{
d
i
j
∣
x
i
∈
G
p
,
x
j
∈
G
q
}
D_{p q}=\max \left\{d_{i j} \mid x_{i} \in G_{p}, x_{j} \in G_{q}\right\}
Dpq=max{dij∣xi∈Gp,xj∈Gq}
3)中心距离
定义类
G
p
G_{p}
Gp 与类
G
q
G_{q}
Gq 的中心
x
ˉ
p
\bar{x}_{p}
xˉp 与
x
ˉ
q
\bar{x}_{q}
xˉq 之间的距离为两类之同的距离
D
p
q
=
d
x
p
x
q
D_{p q}=d_{x_{p} x_{q}}
Dpq=dxpxq
(4)半均距隨
定义类
G
p
G_{p}
Gp 与类
G
q
G_{q}
Gq 任套两个样本之但距离的平均值为两类之间的距离
D
p
q
=
1
n
p
n
q
∑
x
i
∈
G
p
∑
x
j
∈
G
q
d
i
j
D_{p q}=\frac{1}{n_{p} n_{q}} \sum_{x_{i} \in G_{p}} \sum_{x_{j} \in G_{q}} d_{i j}
Dpq=npnq1xi∈Gp∑xj∈Gq∑dij
聚类算法
层次聚类
输入: n n n 个样本组成的样本集合及样本之间的距离: 输出: 对样本集合的一个层次化聚类。
(1)计算 n 个样本两两之间的欧氏距离
{
d
i
j
}
,
\left\{d_{i j}\right\},
{dij}, 记作矩阵
D
=
[
d
i
j
]
n
×
n
D=\left[d_{i j}\right]_{n \times n}
D=[dij]n×n
(2)构造 n 个类,每个类只包含一个样本。
(3)合并类间距离最小的两个类,其中最短距离为类间距离,构建一个新类。
(4)计算新类与当前各类的距离。若类的个数为 1,终止计算, 否则回到步 (3)。
可以看出聚合层次政类算法的复杂度是 O ( n 3 m ) , O\left(n^{3} m\right), O(n3m), 其中 m m m 是样本的维数,n 是样本个数。
k均值聚类
输入: n n n 个样本的集合 X:
输出: 样本集合的款类 C”。
(1)初始化。令
t
=
0
,
t=0,
t=0, 随 机选择
k
k
k 个样本点作为初始聚类中心
m
(
0
)
=
m^{(0)}=
m(0)=
(
m
1
(
0
)
,
⋯
,
m
l
(
0
)
,
⋯
,
m
k
(
0
)
)
\left(m_{1}^{(0)}, \cdots, m_{l}^{(0)}, \cdots, m_{k}^{(0)}\right)
(m1(0),⋯,ml(0),⋯,mk(0))
(2)对样本进行麥类。对固定的类中心
m
(
t
)
=
(
m
1
(
t
)
,
⋯
,
m
l
(
t
)
,
⋯
,
m
k
(
t
)
)
,
m^{(t)}=\left(m_{1}^{(t)}, \cdots, m_{l}^{(t)}, \cdots, m_{k}^{(t)}\right),
m(t)=(m1(t),⋯,ml(t),⋯,mk(t)), 其中
m
l
(
t
)
m_{l}^{(t)}
ml(t) 为类
G
l
G_{l}
Gl 的中心,计算每个样本到类中心的距离,将每个样本指派到与其最近的 中心的类中,构成聚类结果
C
(
t
)
C^{(t)}
C(t)
(3)计算新的类中心。对聚类结果 C
(
t
)
,
^{(t)},
(t), 计算当前各个类中的样本的均值,作为新
的类中心
m
(
t
+
1
)
=
(
m
1
(
t
+
1
)
,
⋯
,
m
l
(
t
+
1
)
,
⋯
,
m
k
(
t
+
1
)
)
m^{(t+1)}=\left(m_{1}^{(t+1)}, \cdots, m_{l}^{(t+1)}, \cdots, m_{k}^{(t+1)}\right)
m(t+1)=(m1(t+1),⋯,ml(t+1),⋯,mk(t+1))
(4)如果迭代收琉或符合停止条件,输出
C
∗
=
C
(
t
)
C^{*}=C^{(t)}
C∗=C(t)。否则,
⇔
t
=
t
+
1
,
\Leftrightarrow t=t+1,
⇔t=t+1, 返回步 (2)
k 均值聚类算法的复杂度是 O ( m n k ) , O(m n k), O(mnk), 其中 m m m 是样本维数,n 是样本个数,k 是类别个数。
代码
# 定义聚类数的节点
class ClusterNode:
def __init__(self, vec, left=None, right=None, distance=-1, id=None, count=1):
"""
:param vec: 保存两个数据聚类后形成新的中心
:param left: 左节点
:param right: 右节点
:param distance: 两个节点的距离
:param id: 用来标记哪些节点是计算过的
:param count: 这个节点的叶子节点个数
"""
self.vec = vec
self.left = left
self.right = right
self.distance = distance
self.id = id
self.count = count
def euler_distance(point1: np.ndarray, point2: list) -> float:
"""
计算两点之间的欧拉距离,支持多维
"""
distance = 0.0
for a, b in zip(point1, point2):
distance += math.pow(a - b, 2)
return math.sqrt(distance)
# 层次聚类(聚合法)
class Hierarchical:
def __init__(self, k):
self.k = k
self.labels = None
def fit(self, x):
nodes = [ClusterNode(vec=v, id=i) for i, v in enumerate(x)]
distances = {}
point_num, feature_num = x.shape
self.labels = [-1] * point_num
currentclustid = -1
while(len(nodes)) > self.k:
min_dist = math.inf
nodes_len = len(nodes)
closest_part = None
for i in range(nodes_len - 1):
for j in range(i+1, nodes_len):
d_key = (nodes[i].id, nodes[j].id)
if d_key not in distances:
distances[d_key] = euler_distance(nodes[i].vec, nodes[j].vec)
d = distances[d_key]
if d < min_dist:
min_dist = d
closest_part = (i, j)
part1, part2 = closest_part
node1, node2 = nodes[part1], nodes[part2]
new_vec = [ (node1.vec[i] * node1.count + node2.vec[i] * node2.count ) / (node1.count + node2.count)
for i in range(feature_num)]
new_node = ClusterNode(vec=new_vec,
left=node1,
right=node2,
distance=min_dist,
id=currentclustid,
count=node1.count + node2.count)
currentclustid -= 1
del nodes[part2], nodes[part1]
nodes.append(new_node)
self.nodes = nodes
self.calc_label()
def calc_label(self):
"""
调取聚类的结果
"""
for i, node in enumerate(self.nodes):
# 将节点的所有叶子节点都分类
self.leaf_traversal(node, i)
def leaf_traversal(self, node: ClusterNode, label):
"""
递归遍历叶子节点
"""
if node.left == None and node.right == None:
self.labels[node.id] = label
if node.left:
self.leaf_traversal(node.left, label)
if node.right:
self.leaf_traversal(node.right, label)
# kmeans
class MyKmeans:
def __init__(self, k, n=20):
self.k = k
self.n = n
def fit(self, x, centers=None):
# 第一步,随机选择 K 个点, 或者指定
if centers is None:
idx = np.random.randint(low=0, high=len(x), size=self.k)
centers = x[idx]
#print(centers)
inters = 0
while inters < self.n:
#print(inters)
#print(centers)
points_set = {key: [] for key in range(self.k)}
# 第二步,遍历所有点 P,将 P 放入最近的聚类中心的集合中
for p in x:
nearest_index = np.argmin(np.sum((centers - p) ** 2, axis=1) ** 0.5)
points_set[nearest_index].append(p)
# 第三步,遍历每一个点集,计算新的聚类中心
for i_k in range(self.k):
centers[i_k] = sum(points_set[i_k])/len(points_set[i_k])
inters += 1
return points_set, centers