声明:本文基于在校课程及吴恩达ML教程,代码参考自多份博客(已在参考链接中表明),如需转载请标明出处。
源代码、实验数据、实验指导书: https://pan.baidu.com/s/1yTTI0_w2bZ7o8uuxravLyA 提取码: spbp
目录
- 一、算法描述
- 二、算法流程
-
- 三、PCA 算法 python 实现
- 四、吴恩达-机器学习 PCA 作业实践
-
- 五、参考链接
一、算法描述
PCA 是最常见的降维算法。
比如说,现在想把
2
2
2 维 降到
1
1
1 维。PCA 的做法是找到一个方向向量(Vector direction),当把所有的数据都投射到该向量上时,投射均方误差能尽可能地小。方向向量是一个经过原点的向量,而投射误差是从特征向量向该方向向量作垂线的长度。
现在将问题一般化,即将 n 维数据降至 k 维,对于 PCA 来说就是找到高维向量
U
=
(
u
1
,
u
2
,
.
.
.
,
u
k
)
U = (u^1, u^2, ... , u^k)
U=(u1,u2,...,uk) 使得总的投射误差最小。
二、算法流程
I. 降维
- 标准化。计算出所有特征的均值,然后令
x
j
=
x
j
−
μ
j
x_j = x_j - \mu_j
xj=xj−μj。如果特征是在不同的数量级上,还需要将其除以标准差,
x
j
∗
=
(
x
j
−
μ
j
)
/
σ
j
x_j^* = (x_j - μ_j ) / σ_j
xj∗=(xj−μj)/σj。
z-score 标准化(zero-mean normalization),也叫标准差标准化。这种方法给予原始数据的均值(mean)和标准差(standard deviation)进行数据的标准化。经过处理的数据符合标准正态分布,即均值为
0
0
0,标准差为
1
1
1。注意,一般来说 z-score 不是归一化,而是标准化,归一化只是标准化的一种。from 数据标准化/归一化normalization
f
o
r
e
a
c
h
c
o
l
u
m
n
,
(
X
−
m
e
a
n
)
/
s
t
d
for \ each \ column, (X - mean) / std
for each column,(X−mean)/std
其中 mean 为所有样本数据的均值,std 为所有样本数据的标准差。
- 计算协方差矩阵(covariance matrix)
c
o
v
_
m
a
t
=
1
m
∑
i
=
1
m
x
(
i
)
(
x
(
i
)
)
T
=
1
m
X
X
T
cov\_mat = \frac{1}{m}\sum_{i=1}^{m}x^{(i)}(x^{(i)})^T = \frac{1}{m}XX^T
cov_mat=m1i=1∑mx(i)(x(i))T=m1XXT
x
(
i
)
x^{(i)}
x(i) 代表第
i
i
i 个样本,是一个
n
∗
1
n *1
n∗1 的向量,
n
n
n 是特征维数,
m
m
m 是样本个数。
- 计算协方差矩阵的特征向量(eigenvectors)。使用奇异值分解(singular value decomposition,SVD)来求解协方差矩阵的特征向量。
c
o
v
_
m
a
t
=
U
S
V
T
U
=
[
u
1
,
u
2
,
.
.
.
,
u
n
]
cov\_mat = USV^T \\ U = [u_1, u_2, ... , u_n]
cov_mat=USVTU=[u1,u2,...,un]
U
U
U 是
n
∗
n
n*n
n∗n 维的主成分(Principal Component)集
- 降维。将数据从
n
n
n 维降至
k
k
k 维,只需要从
U
U
U 中选取前
k
k
k 个向量,获得一个
n
∗
k
n*k
n∗k 维度的矩阵。
U
r
e
d
u
c
e
=
[
u
1
,
u
2
,
.
.
.
,
u
k
]
U_{reduce} = [u_1, u_2, ... , u_k]
Ureduce=[u1,u2,...,uk]
然后通过如下计算即可获得要求的新特征向量
Z
Z
Z。
z
(
i
)
=
U
r
e
d
u
c
e
T
x
(
i
)
Z
=
X
U
r
e
d
u
c
e
z^{(i)} = U_{reduce}^Tx^{(i)} \\ Z = XU_{reduce}
z(i)=UreduceTx(i)Z=XUreduce
-
U
r
e
d
u
c
e
U_{reduce}
Ureduce 是
n
∗
k
n*k
n∗k 维的前
k
k
k 个主成分
-
U
r
e
d
u
c
e
T
U_{reduce}^T
UreduceT 是前
k
k
k 个主成分的转置(
k
∗
n
k*n
k∗n 维),
x
(
i
)
x^{(i)}
x(i) 是
n
∗
1
n*1
n∗1 维的均值归一化后第
i
i
i 个样本数据,因此结果
z
(
i
)
z^{(i)}
z(i) 为
k
∗
1
k*1
k∗1 维的投影向量
- 整体使用矩阵计算即
m
∗
n
m*n
m∗n 维的
X
X
X 【矩阵乘】
n
∗
k
n*k
n∗k 维的
U
r
e
d
u
c
e
U_{reduce}
Ureduce 即可。
Z
=
X
U
r
e
d
u
c
e
Z = XU_{reduce}
Z=XUreduce
II. 数据恢复
若想使用压缩后的数据近似的获得原有的特征,可以使用如下公式:
因为:
z
(
i
)
=
U
r
e
d
u
c
e
T
x
(
i
)
z^{(i)} = U_{reduce}^Tx^{(i)}
z(i)=UreduceTx(i)
所以相反的方程:
x
a
p
p
r
o
x
(
i
)
=
U
r
e
d
u
c
e
z
(
i
)
x
a
p
p
r
o
x
(
i
)
≈
x
(
i
)
X
a
p
p
r
o
x
=
Z
U
r
e
d
u
c
e
T
x^{(i)}_{approx} = U_{reduce}z^{(i)} \\ x^{(i)}_{approx} \approx x^{(i)} \\ X_{approx} = Z U_{reduce}^T
xapprox(i)=Ureducez(i)xapprox(i)≈x(i)Xapprox=ZUreduceT
-
U
r
e
d
u
c
e
U_{reduce}
Ureduce
n
∗
k
n*k
n∗k 维,
z
(
i
)
z^{(i)}
z(i) 为
k
∗
1
k*1
k∗1 维,可得
n
∗
1
n*1
n∗1 维的
x
a
p
p
r
o
x
(
i
)
x^{(i)}_{approx}
xapprox(i)
- 整体使用矩阵计算,
Z
Z
Z 是
m
∗
k
m*k
m∗k 维,
U
r
e
d
u
c
e
T
U_{reduce}^T
UreduceT 是
k
∗
n
k*n
k∗n 维,可得
m
∗
n
m*n
m∗n 维的
X
a
p
p
r
o
x
X_{approx}
Xapprox
压缩表示下的重构——数据恢复
x
a
p
p
r
o
x
(
i
)
=
U
r
e
d
u
c
e
z
(
i
)
x
a
p
p
r
o
x
(
i
)
≈
x
(
i
)
x^{(i)}_{approx} = U_{reduce}z^{(i)} \\ x^{(i)}_{approx} \approx x^{(i)}
xapprox(i)=Ureducez(i)xapprox(i)≈x(i)
如图所知,这是一个漂亮的重构,它们与原始数据相当相似。上图直观的展现了从低维表示
Z
Z
Z 回到未压缩的表示。
三、PCA 算法 python 实现
import numpy as np
class PCA():
def normalize(self, X):
"""
1. 均值归一化
1. 计算出每一维特征的均值𝜇_𝑗 ,令 𝑥_𝑗=𝑥_𝑗−𝜇_𝑗。
2. 如果特征是在不同的数量级上,还需要将其除以标准差 。
for each column, (X - mean) / std
"""
means = X.mean(axis=0)
stds = X.std(axis=0, ddof=1)
X_norm = (X - means) / stds
return X_norm
def covariance_matrix(self, X_norm):
"""
2. 计算协方差矩阵(covariance matrix)𝛴
∑=1/𝑚 ∑1_(𝑖=1)^m▒〖(𝑥^((𝑖)) ) (𝑥^((𝑖)) )^𝑇 〗= 1/𝑚 𝑋𝑋^𝑇
∑ = 1/𝑚〖𝑋^𝑇 𝑋〗
"""
m = X_norm.shape[0]
return (X_norm.T @ X_norm) / m
def dimensional_reduction(self, X, keep_dims=None):
if not keep_dims:
keep_dims = X.shape[1] - 1
normalize_x = self.normalize(X)
cov_x = self.covariance_matrix(normalize_x)
U, S, V = np.linalg.svd(cov_x)
U_reduce = U[:, :keep_dims]
Z = normalize_x @ U_reduce
return normalize_x, U_reduce, Z
def recover(self, Z, U_reduce):
"""
6. 数据恢复:将降维后一维数据再投影回二维空间。
𝒙_𝒂𝒑𝒑𝒓𝒐𝒙^((𝒊) )=𝑼_𝒓𝒆𝒅𝒖𝒄𝒆 𝒛^((𝒊))
"""
return Z @ U_reduce.T
四、吴恩达-机器学习 PCA 作业实践
- 对
e
x
7
d
a
t
a
1.
m
a
t
ex7data1.mat
ex7data1.mat 中的数据进行降维(原始数据是
2
2
2 维数据,降成
1
1
1 维)。
- 利用 PCA 对人脸进行降维。人脸数据集
e
x
7
f
a
c
e
s
.
m
a
t
ex7faces.mat
ex7faces.mat 原始的人脸大小
32
×
32
=
1024
32×32=1024
32×32=1024 维,一行数据是一个人脸,将数据
r
e
s
h
a
p
e
reshape
reshape 成
32
×
32
32×32
32×32,就可以显示人脸图像。利用 PCA 算法将
1024
1024
1024 维的人脸降维到
100
100
100 维。
assignment_1
import scipy.io as scio
import numpy as np
import matplotlib.pyplot as plt
from PCA import PCA
data = scio.loadmat('ex7data1.mat')
X = data['X']
if __name__ == '__main__':
plt.figure(0, (7, 7))
plt.title("raw data")
plt.xlim(xmin=0, xmax=7)
plt.ylim(ymin=2, ymax=8)
plt.scatter(X[:, 0], X[:, 1], c='', marker='o', facecolors='none', edgecolors='b')
pca = PCA()
X_norm, U_reduce, Z = pca.dimensional_reduction(X)
print("U_reduce : ", U_reduce)
print("Z[0] : ", Z[0])
X_approx = pca.recover(Z, U_reduce)
print("X_approx[0] : ", X_approx[0])
plt.figure(1, (7, 7))
plt.scatter(X_norm[:, 0], X_norm[:, 1], c='', marker='o', facecolors='none', edgecolors='b')
plt.scatter(X_approx[:, 0], X_approx[:, 1], c='', marker='o', facecolors='none', edgecolors='r')
for i in range(X.shape[0]):
x = [X_norm[i, 0], X_approx[i, 0]]
y = [X_norm[i, 1], X_approx[i, 1]]
plt.plot(x, y, '--k', linewidth=1)
plt.title("PCA dimensional reduction and recover")
plt.xlim(xmin=-4, xmax=3)
plt.ylim(ymin=-4, ymax=3)
plt.show()
- ex7data1.mat原始数据图
计算出的第一主成分:U_reduce : [[-0.70710678] [-0.70710678]]
第一个样本的投影值:Z[0] : [1.48127391]
第一个样本投影回二维数据空间位置:X_approx[0] : [-1.04741883 -1.04741883]
- 在二维空间里面画出原始样本点(均值归一化后的)和数据恢复后的样本点。用蓝色代表原始点,红色代表回复后的数据点,图如下:
assignment_2
import scipy.io as scio
import numpy as np
import matplotlib.pyplot as plt
from PCA import PCA
from displayData import display_data
data = scio.loadmat('ex7faces.mat')
X = data['X']
if __name__ == '__main__':
display_data(X, "Original faces")
pca = PCA()
X_norm, U_reduce, Z = pca.dimensional_reduction(X, 100)
display_data(U_reduce.T, "Principle Components", 6, 6)
X_approx = pca.recover(Z, U_reduce)
display_data(X_approx, "Recovered faces")
展示人脸数据的函数(displayData.py)
import matplotlib.pyplot as plt
import numpy as np
def display_data(x, title = "show top 100", rows = 10, cols = 10):
(m,n) = x.shape
width = np.round(np.sqrt(n)).astype(int)
height = (n / width).astype(int)
print("width : ", width, " height : ", height)
print("rows : ", rows, " cols : ", cols)
pad = 1
display_array = -np.ones((pad + rows*(height+pad),
pad + cols*(width + pad)))
print(display_array.shape)
current_image = 0
for j in range(rows):
for i in range(cols):
if current_image >= m:
break
max_val = np.max(np.abs(x[current_image,:]))
display_array[pad + j*(height + pad) + np.arange(height),
pad + i*(width + pad) + np.arange(width)[:,np.newaxis]] = \
x[current_image,:].reshape((height,width)) / max_val
current_image += 1
if current_image >= m :
break
plt.figure(figsize=(8, 8))
plt.imshow(display_array,cmap = 'gray',extent =[-1,1,-1,1])
plt.axis('off')
plt.title(title, fontsize=20)
plt.show()
- 人脸数据集 ex7faces.mat 中前
100
100
100 张人脸图
- 使用 PCA 降维,将降维得到的
100
100
100 个主成分转换成人脸形式——Eigenfaces(特征脸/本征脸)
- 使用前
100
100
100 个主成分表示再恢复得到的人脸图
- 原始人脸图像与使用前
100
100
100 个主成分重构的人脸图像并排对比
五、参考链接
- 吴恩达机器学习笔记-5
- 吴恩达机器学习作业Python实现(七):K-means和PCA主成分分析
- 机器学习 吴恩达 课后习题百度云资源 (Coursera 搬运)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)