机器学习——特征工程之K均值降维
前言
1、先直观解释什么是平面(线性子空间)和流形(非线性子空间):
答:如果线性子空间是一张平展的纸,那么非线性流形的一个简单例子就是卷起来的纸,可以把流形看作一个可以以多种方式伸展和卷动的曲面,平面(线性子空间)可以推广为流形(非线性子空间)。
2、为什么能够使用降维手段实现降维?(后面有图)
答:即使一个大的流形看上去非常复杂,但它的每个数据点的邻近区域通常可以非常好地近似为一块平面。换句话说,可以通过多个小平面使用局部结构组成全局结构。
3、为什么聚类算法可以实现降维?
答:彼此相近(可以用一种特定的度量方式(比如欧式距离)来定义“近”的概念)的点属于同一个簇。给定一个聚类,数据点可以用它的簇成员向量来表示。如果簇的数量小于初始的特征数量,那么相对于初始表示,这种新表示就具有更少的维度,初始数据就被压缩进一个更低维度的空间。
一、K-均值聚类(K-means)
K-means属于无监督学习方法,不需要标签,仅基于数据本身的结构推测出簇标签。
1、算法推导
为了说明算法实现过程,先解释算法的伪代码,再手推一个实例,最后用代码实现举例。
K-means好像成篇的数学推导,这个算法简单来说就是基于距离度量,把每个样本点聚类到与它距离最近的类中。
E
=
∑
i
=
1
k
∑
x
∈
C
i
∥
x
−
μ
i
∥
2
2
(1)
E=\sum_{i=1}^{k}\sum_{x\in C_{i}}\left\|x-\mu_{i}\right\|_{2}^{2}\tag{1}
E=i=1∑kx∈Ci∑∥x−μi∥22(1)
解释下上面的平方误差公式:
假
定
样
本
集
D
=
{
x
1
,
x
2
,
.
.
.
,
x
m
}
,
“
希
望
”
使
用
K
−
m
e
a
n
s
算
法
聚
类
出
K
个
簇
(
类
)
,
分
别
为
C
=
{
C
1
,
C
2
,
.
.
,
C
K
}
,
(
1
)
式
中
的
μ
是
这
K
个
簇
的
均
值
向
量
μ
i
=
1
∣
C
i
∣
∑
x
∈
C
i
x
,
聚
类
算
法
希
望
E
越
小
越
好
。
假定样本集D=\{x_{1},x_{2},...,x_{m}\},“希望”使用K-means算法聚类出K个簇(类),分别为C=\{C_{1},C_{2},..,C_{K}\},(1)式中的\mu是这K个簇的均值向量\mu_{i}=\frac{1}{|C_{i}|}\sum_{x\in C_{i}}x,聚类算法希望E越小越好。
假定样本集D={x1,x2,...,xm},“希望”使用K−means算法聚类出K个簇(类),分别为C={C1,C2,..,CK},(1)式中的μ是这K个簇的均值向量μi=∣Ci∣1∑x∈Cix,聚类算法希望E越小越好。
那么怎样划分每一个样本?
答:这块使用欧氏距离。
假
设
当
前
已
有
K
个
簇
,
每
个
簇
的
均
值
向
量
为
{
μ
1
,
μ
2
,
.
.
.
,
μ
k
}
,
使
用
欧
氏
距
离
计
算
当
前
样
本
x
j
与
每
一
个
簇
的
μ
i
的
距
离
d
j
i
=
∥
x
j
−
μ
i
∥
2
,
找
到
最
小
距
离
对
应
的
簇
μ
i
,
便
将
该
样
本
点
划
入
到
簇
μ
i
中
,
然
后
重
新
计
算
μ
i
的
均
值
向
量
,
这
样
不
断
对
每
个
样
本
点
进
行
计
算
,
知
道
所
有
样
本
点
都
划
分
完
毕
,
算
法
终
止
。
假设当前已有K个簇,每个簇的均值向量为\{\mu_{1},\mu_{2},...,\mu_{k}\},使用欧氏距离计算当前样本x_{j}与每一个簇的\mu_{i}的距离d_{ji}=\left\| x_{j}-\mu_{i}\right\|_{2},找到最小距离对应的簇\mu_{i},便将该样本点划入到簇\mu_{i}中,然后重新计算\mu_{i}的均值向量,这样不断对每个样本点进行计算,知道所有样本点都划分完毕,算法终止。
假设当前已有K个簇,每个簇的均值向量为{μ1,μ2,...,μk},使用欧氏距离计算当前样本xj与每一个簇的μi的距离dji=∥xj−μi∥2,找到最小距离对应的簇μi,便将该样本点划入到簇μi中,然后重新计算μi的均值向量,这样不断对每个样本点进行计算,知道所有样本点都划分完毕,算法终止。
基本过程上面已经有说,伪代码直接截图了:
2、举例
用西瓜书上的例子吧
下面是原数据集
该数据集一共有30个样本,将其分别编号为
{
x
1
,
x
2
,
x
3
,
.
.
.
,
x
30
}
\{x_{1},x_{2},x_{3},...,x_{30}\}
{x1,x2,x3,...,x30},每个样本有两个属性。
1、算法初始化:
取聚类簇个数K = 3,随机选取三个样本(
x
6
,
x
12
,
x
27
x_{6},x_{12},x_{27}
x6,x12,x27)作为初始均值向量
μ
\mu
μ,即:
μ
1
=
(
0.403
;
0.237
)
,
μ
2
=
(
0.343
;
0.099
)
,
μ
3
=
(
0.532
;
0.472
)
\mu_{1}=(0.403;0.237),\mu_{2}=(0.343;0.099),\mu_{3}=(0.532;0.472)
μ1=(0.403;0.237),μ2=(0.343;0.099),μ3=(0.532;0.472)
此时对应的三个簇为:
C
1
=
{
x
6
}
,
C
2
=
{
x
12
}
,
C
3
=
{
x
27
}
C_{1}=\{x_{6}\},C_{2}=\{x_{12}\},C_{3}=\{x_{27}\}
C1={x6},C2={x12},C3={x27}
2、循环遍历:
分别取数据集中剩下的样本,假设此时取样本
x
1
=
(
0.697
;
0.460
)
x_{1}=(0.697;0.460)
x1=(0.697;0.460),使用欧式距离公式分别计算它与当前均值向量
μ
1
,
μ
2
,
μ
3
\mu_{1},\mu_{2},\mu_{3}
μ1,μ2,μ3的距离,如下:
d
11
=
∥
x
1
−
μ
1
∥
2
=
(
0.697
−
0.403
)
2
+
(
0.460
−
0.237
)
2
=
0.369
d_{11}=\left\|x_{1}-\mu_{1}\right\|_{2} = \sqrt{(0.697-0.403)^{2}+(0.460-0.237)^{2}}=0.369
d11=∥x1−μ1∥2=(0.697−0.403)2+(0.460−0.237)2=0.369
d
12
=
∥
x
1
−
μ
2
∥
2
=
(
0.697
−
0.343
)
2
+
(
0.460
−
0.099
)
2
=
0.506
d_{12}=\left\|x_{1}-\mu_{2}\right\|_{2} = \sqrt{(0.697-0.343)^{2}+(0.460-0.099)^{2}}=0.506
d12=∥x1−μ2∥2=(0.697−0.343)2+(0.460−0.099)2=0.506
d
13
=
∥
x
1
−
μ
3
∥
2
=
(
0.697
−
0.532
)
2
+
(
0.460
−
0.472
)
2
=
0.166
d_{13}=\left\|x_{1}-\mu_{3}\right\|_{2} = \sqrt{(0.697-0.532)^{2}+(0.460-0.472)^{2}}=0.166
d13=∥x1−μ3∥2=(0.697−0.532)2+(0.460−0.472)2=0.166
可以看出
d
13
<
d
11
<
d
12
d_{13}<d_{11}<d_{12}
d13<d11<d12,说明当前样本
x
1
x_{1}
x1与以
μ
3
\mu_{3}
μ3为均值向量的簇距离最近,那么就把
x
1
x_{1}
x1归入到簇
C
3
C_{3}
C3中,此时的三个簇为:
C
1
=
{
x
6
}
C_{1}=\{x_{6}\}
C1={x6}
C
2
=
{
x
12
}
C_{2}=\{x_{12}\}
C2={x12}
C
3
=
{
x
1
,
x
27
}
C_{3}=\{x_{1},x_{27}\}
C3={x1,x27}
每计算完一个样本,一定要更新对应簇的均值向量,那些没有改变的簇的均值向量不改变,直接参加下一个样本的计算,即:
μ
1
=
(
0.403
;
0.237
)
(
没
变
)
,
μ
2
=
(
0.343
;
0.099
)
(
没
变
)
\mu_{1}=(0.403;0.237)(没变),\mu_{2}=(0.343;0.099)(没变)
μ1=(0.403;0.237)(没变),μ2=(0.343;0.099)(没变),但是因簇
C
3
C_{3}
C3加入了新样本点,所以要更新
μ
3
\mu_{3}
μ3:
μ
3
=
1
n
∑
i
=
1
n
C
3
=
1
2
[
x
1
+
x
27
]
=
1
2
[
(
0.697
;
0.460
)
+
(
0.532
;
0.472
)
]
=
(
0.6145
;
0.466
)
\mu_{3} = \frac{1}{n}\sum_{i=1}^{n}C_{3}=\frac{1}{2}[x_{1}+x_{27}]=\frac{1}{2}[(0.697;0.460)+(0.532;0.472)]=(0.6145;0.466)
μ3=n1i=1∑nC3=21[x1+x27]=21[(0.697;0.460)+(0.532;0.472)]=(0.6145;0.466)
就这样不断计算每个样本点,直到全部样本被划分完毕。
3、返回结果
按照上面的循环,最后可得下面的三个簇:
C
1
=
{
x
5
,
x
6
,
x
7
,
x
8
,
x
9
,
x
10
,
x
13
,
x
14
,
x
15
,
x
17
,
x
18
,
x
19
,
x
20
,
x
23
}
C_{1} =\{x_{5},x_{6},x_{7},x_{8},x_{9},x_{10},x_{13},x_{14},x_{15},x_{17},x_{18},x_{19},x_{20},x_{23}\}
C1={x5,x6,x7,x8,x9,x10,x13,x14,x15,x17,x18,x19,x20,x23}
C
2
=
{
x
11
,
x
12
,
x
16
}
C_{2}=\{x_{11},x_{12},x_{16}\}
C2={x11,x12,x16}
C
3
=
{
x
1
,
x
2
,
x
2
,
x
4
,
x
21
,
x
22
,
x
24
,
x
25
,
x
26
,
x
27
,
x
28
,
x
29
,
x
30
}
C_{3} =\{x_{1},x_{2},x_{2},x_{4},x_{21},x_{22},x_{24},x_{25},x_{26},x_{27},x_{28},x_{29},x_{30}\}
C3={x1,x2,x2,x4,x21,x22,x24,x25,x26,x27,x28,x29,x30}
计算最后的均值向量:
μ
1
‘
=
(
0.473
;
0.214
)
\mu_{1}^{`}=(0.473;0.214)
μ1‘=(0.473;0.214)
μ 2 ‘ = ( 0.394 ; 0.066 ) \mu_{2}^{`}=(0.394;0.066) μ2‘=(0.394;0.066)
μ 1 ‘ = ( 0.623 ; 0.388 ) \mu_{1}^{`}=(0.623;0.388) μ1‘=(0.623;0.388)
二、降维
上面介绍完K-means算法的原理,下面将其应用到降维任务中。
为了理解前言中的问题二,现举个例子:
代码:
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
from sklearn import manifold, datasets
# 生成带噪声的瑞士卷数据集
X, color = datasets.samples_generator.make_swiss_roll(n_samples=1500)
# 使用100个k-均值簇对数据进行近似
clusters_swiss_roll = KMeans(n_clusters=100, random_state=1).fit_predict(X)
# 使用k-均值簇ID作为颜色来绘制数据集
fig2 = plt.figure()
ax = fig2.add_subplot(111, projection='3d')
ax.scatter(X[:, 0], X[:, 1], X[:, 2], c=clusters_swiss_roll, cmap='Spectral')
plt.show()
运行图:
如果把每个聚类簇的均值向量作为新的数据集,那么就可以实现降维的目的。
代码实现:
def K_means(X,k,rand_seed):
m = X.shape[0]#样本个数
n = X.shape[1]#属性个数
#初始化均值向量
np.random.seed(rand_seed)
rand_index = np.random.choice(m,k,replace=False)###先从所有样本中随机选择出K个样本作为均值向量(先随机取k个索引)
u = X[rand_index,:]
# 初始化簇
C = []
for sample in u:
C.append(sample)
X = np.delete(X,rand_index,axis = 0)#去除掉选中作为初始均值向量的样本
#遍历除随机选到的样本以外的所有样本
for i,x in enumerate(X):
dist = np.sqrt(np.sum(np.square(x - u),axis = 1))#计算距离
dist_order = np.argsort(dist)[0]#取最小距离的索引
C[dist_order] = np.row_stack([C[dist_order],x])#将样本添加到距离最近的簇中
u[dist_order] = np.mean(u[dist_order])#更新均值向量
return C,u
修改随机种子,每次得到的聚类结果都不同:
随机种子等于1:
随机种子等于2:
随机种子等于3:
这就表明了K-means算法的缺点:受初值和离群点的影响,每次结果不稳定。所以才有了K-means++、ISODATA、Bi-kmeasn、mini batch kmeans等。