任务安排
1、机器学习导论 8、核方法
2、KNN及其实现 9、稀疏表示
3、K-means聚类 10、高斯混合模型
4、主成分分析 11、嵌入学习
5、线性判别分析 12、强化学习
6、贝叶斯方法 13、PageRank
7、逻辑回归 14、深度学习
主成分分析(PCA)
Ⅰ 算法背景:维数灾难
维数灾难最早是由理查德·贝尔曼(Richard E. Bellman)在考虑优化问题时提出来的 ,它用来描述当(数学)空间维度增加时,分析和组织高维空间(通常有成百上千维)中的数据,因体积指数增加而遇到各种问题场景。
维数灾难这个概念具有的共同特点是:当维度增加时,空间的体积增加得很快,使得可用的数据变得稀疏。
生活中多维数据比较的例子很多,比如人的三围及身高体重、游戏角色的六维属性等等。我们拿大家最熟悉的成绩来说,小学时,我们可能只有语数英三科(三维),想要和小伙伴比较成绩,关键看到底是哪一个科目(某一特征值)具体影响了我们之间的差距,因为科目不多,还比较容易,但到了中学,我们可能要学八科、九科、十科…,身边小伙伴也变多了,想要比较起来就没有之前那么容易了,而当分析某一数学问题时,可能有成百上千维的数据,样本个数也不在少数,那么总体分析就显得举步维艰。因此,我们就想让数据变得简单一些,就有了维数约简思想。
Ⅱ 维数约简
维数约简又称降维,是机器学习的一种必要手段。若数据
X
=
X=
X={
x
i
x_i
xi} 是属于
n
n
n 维空间的,通过特征提取或者特征选择的方法,将原空间的维数降至
k
k
k 维,要求
k
k
k 远小于
n
n
n,并满足:
k
k
k 维空间的特性能反映原空间数据的特征,这个过程称之为维数约简
维数约简即通过某种数学变换,将原始高维属性空间转变为一个低维子空间,在这个子空间中样本密度大幅度提高,距离计算也变得容易起来
由线性代数的知识我们知道,空间维度的改变依赖于变换矩阵,如
X
X
X 是一个
n
n
n 维列向量
X
=
[
1
,
2
,
.
.
.
,
n
]
T
X=[1,2,...,n]^T
X=[1,2,...,n]T,我们想要把它变成
Y
=
[
1
,
2
,
.
.
.
,
m
]
T
Y=[1,2,...,m]^T
Y=[1,2,...,m]T,即在
X
X
X 前面乘上一个
m
×
n
m×n
m×n 的变换矩阵
A
A
A
而主成分分析,就是降维里的一种重要方法。
既然要对已有的特征值进行降维变换,那么首先,我们要先得到原样本集的特征值,回顾一下线性代数的知识。
有一个
n
n
n 阶矩阵
A
A
A,若存在数
λ
λ
λ 和非零
n
n
n 维列向量
X
X
X,满足
A
X
=
λ
X
AX=λX
AX=λX,则称
λ
λ
λ 为
A
A
A 的一个特征值,
X
X
X 为
A
A
A 的对应于
λ
λ
λ 的一个特征向量
Ⅲ 核心思想
主成分分析(Principal Component Analysis) 的出发点是从一组特征 ( n n n 维)中计算出一组按重要性从大到小排列的新特征( k k k 维, k ≤ n k≤n k≤n,通常取远小于 n n n),它们是原有特征的线性组合,并且相互之间不相关。(比如你和小伙伴的理科成绩非常接近,那么决定你们之间差距的主要科目 (新特征值PC) 就是文科类的了,只关注这几科,即降维了)
①主成分特点
1. 源于质心的矢量
2. 主成分 ① 指向最大方差的方向
3. 各后续主成分与前一主成分正交,且指向残差(剩余)子空间最大方差的方向
②举例(二维)
为了便于分析说明,我们举二维样本集的例子:
如下图所示,红色的两向量表示“蓝色椭圆”的长轴短轴,很明显可以看出,假如我们把样本集的点投影到长轴上,更能反映出样本集整体的分布,故在这个例子里我们把长轴记为主成分#1,与长轴正交(互不相关)的短轴记为主成分#2,理想情况下,短轴的模(高维情况下称范数)为 0,即仅通过长轴就可以完全分析出样本集的分布,这就实现了完美的降维,因而我们容易知道,长短轴的模(范数)相差越大,即降维的效果越好,所以我们的目标就是,找出尽量长的长轴(标号靠前的主成分)
③最大方差理论
通常,我们认为信号具有较大的方差,噪声具有较小的方差,信噪比就是信号与噪声的功率之差(
10
l
g
(
P
s
P
n
)
10lg(\frac{P_s}{P_n})
10lg(PnPs)),越大越好。如下图所示,我们把紫色线上的数据认为是信号,而蓝色线上的数据认为是噪声,因此我们的目的就是最大化投影数据的方差(样本点在紫线上最分散),最小化数据点与投影之间的均方距离(蓝线和越小)
④目的
PCA 的目的就是“降噪”和“去冗余”。
“降噪”即使保留下来的维度间的相关性尽可能小
“去冗余”即使保留下来的维度含有的方差(能量)尽可能大
★Ⅳ 算法剖析
输入:样本集 {
x
i
xi
xi}
i
=
1
n
^n_{i=1}
i=1n,低维空间维数
k
k
k(即所要保留的新特征值个数)
输出:投影矩阵
W
=
[
w
1
,
w
2
,
.
.
.
,
w
k
]
W=[w_1,w_2,...,w_k]
W=[w1,w2,...,wk]
下面介绍两种 PCA 的实现方法:
①顺序排列
1.对所有样本进行中心化(和期望作差)
x
i
←
x
i
−
1
n
∑
i
=
1
n
x
i
x_i←x_i-\frac{1}{n}∑^n_{i=1}x_i
xi←xi−n1i=1∑nxi
2.对中心化的数据 {
x
1
,
x
2
,
.
.
.
,
x
n
x_1,x_2,...,x_n
x1,x2,...,xn},计算主成分#1:(即目标函数)
w
1
=
arg
m
a
x
∣
∣
w
1
∣
∣
=
1
1
n
∑
i
=
1
n
(
w
1
T
x
i
)
2
w_1=\arg \underset{||w_1||=1}{max}\frac{1}{n}∑^n_{i=1}(w^T_1x_i)^2
w1=arg∣∣w1∣∣=1maxn1i=1∑n(w1Txi)2
w
1
T
x
i
w^T_1x_i
w1Txi 即内积运算(
w
1
w_1
w1 为单位向量),求的是
x
i
x_i
xi 在
w
1
w_1
w1 上的投影,平方是为了省去求绝对值
利用拉格朗日乘数法求解最优
λ
λ
λ,约束条件为
∣
∣
w
∣
∣
=
1
||w||=1
∣∣w∣∣=1(即
w
T
w
=
1
w^Tw=1
wTw=1)
L
(
w
,
λ
)
=
1
n
(
w
T
x
i
)
2
−
λ
(
w
T
w
−
1
)
L(w,λ)=\frac{1}{n}(w^Tx_i)^2-λ(w^Tw-1)
L(w,λ)=n1(wTxi)2−λ(wTw−1)
(矩阵求导)对
w
w
w求导
∂
L
∂
w
=
(
1
n
∑
i
=
1
n
x
i
x
i
T
)
w
−
λ
w
\frac{\partial L}{\partial w}=(\frac{1}{n}∑^n_{i=1}x_ix_i^T)w-λw
∂w∂L=(n1i=1∑nxixiT)w−λw
实际上,令
X
=
[
x
1
,
x
2
,
.
.
.
,
x
n
]
X=[x_1,x_2,...,x_n]
X=[x1,x2,...,xn],则
X
X
T
=
1
n
∑
i
=
1
n
x
i
x
i
T
XX^T=\frac{1}{n}∑^n_{i=1}x_ix_i^T
XXT=n1∑i=1nxixiT
3.最大化投影方差
w
k
=
arg
m
a
x
∣
∣
w
1
∣
∣
=
1
1
n
∑
i
=
1
n
[
w
k
T
(
x
i
−
∑
j
=
1
k
−
1
w
j
w
j
T
x
i
⏟
x
i
′
)
]
2
w_k=\arg \underset{||w_1||=1}{max}\frac{1}{n}∑^n_{i=1}[w^T_k(\underbrace{x_i-∑^{k-1}_{j=1}w_jw_j^Tx_i}_{\text{$x_i'$}})]^2
wk=arg∣∣w1∣∣=1maxn1i=1∑n[wkT(xi′
xi−j=1∑k−1wjwjTxi)]2
后面一串
x
i
−
∑
j
=
1
k
−
1
w
j
w
j
T
x
i
x_i-∑^{k-1}_{j=1}w_jw_j^Tx_i
xi−∑j=1k−1wjwjTxi 可以简单点理解为,扣掉前面那个主成分的方向,在剩下的残差子空间里求新的主成分
②协方差矩阵法
1.对所有样本进行去中心化(和期望作差)
x
i
←
x
i
−
1
n
∑
i
=
1
n
x
i
x_i←x_i-\frac{1}{n}∑^n_{i=1}x_i
xi←xi−n1i=1∑nxi
2.计算样本的协方差矩阵
C
C
C
C
=
(
c
i
j
)
n
×
n
=
[
c
11
c
12
.
.
.
c
1
n
c
21
c
22
.
.
.
c
2
n
.
.
.
.
.
.
.
.
.
.
.
.
c
n
1
c
n
2
.
.
.
c
n
n
]
C=(c_{ij})_{n×n}=\left[ \begin{matrix} c_{11} & c_{12} & ... & c_{1n}\\ c_{21} & c_{22} & ... & c_{2n} \\ ... & ... & ... & ... \\ c_{n1} & c_{n2} & ... & c_{nn} \end{matrix} \right]
C=(cij)n×n=⎣⎢⎢⎡c11c21...cn1c12c22...cn2............c1nc2n...cnn⎦⎥⎥⎤
c
i
j
=
C
o
v
(
X
i
,
Y
j
)
c_{ij}=Cov(X_i,Y_j)
cij=Cov(Xi,Yj)
i
,
j
=
1
,
2
,
.
.
.
,
n
i,j=1,2,...,n
i,j=1,2,...,n
(对角线元素为某一维度的方差)
3.对协方差矩阵C做特征值分解(即求所有满足的特征值和特征向量)
C
W
′
=
λ
W
′
CW'=λW'
CW′=λW′(也可以用拉格朗日乘数法只求所需的最大的
k
k
k 个)
4.取最大的
k
k
k 个特征值所对应的特征向量
w
1
,
w
2
,
.
.
.
,
w
k
w_1,w_2,...,w_k
w1,w2,...,wk
比较详细的 PCA 数学推导过程 主成分分析(PCA)原理详解
——————————这节课的理论理解是真的费劲啊!————————
今日任务
1.给定的图像数据集,可视化并输出聚类性能(上节课还想偷懒,没想到该来的这么快就来了)
2.给定的图像数据集,计算相应的特征脸(Eigenfaces)
注:不是每一组 20 张算一个特征脸,是 200 张取前十个特征脸(这特征脸有点恐怖,不是说好提取完是张伟吗)
3.给定图像数据集,探讨 PCA 降维后特征个数与聚类性能的关系
任务解决
1、今天要用到 python 的库 cv2(版本更新被合并到 opencv_python 里了),提前装一下
pip install opencv_python -i https://pypi.tuna.tsinghua.edu.cn/simple
import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.cluster import KMeans
from PIL import Image
from ML_clustering_performance import clusteringMetrics
path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180
IMAGE_COLUMN = 20 # 列
IMAGE_ROW = 10 # 行
to_image = Image.new('RGB', (IMAGE_COLUMN * w, IMAGE_ROW * h))
def createDatabase(path):
# 查看路径下所有文件
TrainFiles = os.listdir(path) # 遍历每个子文件夹
# 计算有几个文件(图片命名都是以 序号.jpg方式)
Train_Number = len(TrainFiles) # 子文件夹个数
train = []
y_sample = []
# 把所有图片转为1维并存入T中
for k in range(0, Train_Number):
Trainneed = os.listdir(path + '/' + TrainFiles[k]) # 遍历每个子文件夹里的每张图片
Trainneednumber = len(Trainneed) # 每个子文件里的图片个数
for i in range(0, Trainneednumber):
img = Image.open(path + '/' + TrainFiles[k] + '/' + Trainneed[i])
to_image.paste(img, (i * w, k * h)) # 把读出来的图贴到figure上
image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32) # 数据类型转换
image = cv.cvtColor(image, cv.COLOR_RGB2GRAY) # RGB变成灰度图
train.append(image)
y_sample.append(k)
train = np.array(train)
y_sample = np.array(y_sample)
return train, y_sample
# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
# print(X.shape)
X_ = X.reshape(X.shape[0], h*w)
kms = KMeans(n_clusters=10)
y_sample = kms.fit_predict(X_, y)
print(clusteringMetrics(y, y_sample))
plt.imshow(to_image)
plt.show()
( ↓ ↓ ↓别人家的代码系列)
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import matplotlib.image as imgplt
import os
import pandas as pd
from ML_clustering_performance import clusteringMetrics
name = []
target = []
def getimage():
# 获取文件并构成向量
# 预测值为1维,把一张图片的三维(RGB)压成1维,那么n张图片就是二维
global total_photo
file = os.listdir('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images') # 遍历face_images里每个子文件夹
i = 0
for subfile in file:
photo = os.listdir('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images\\' + subfile) # 遍历每个子文件夹里的照片
for name in photo:
photo_name.append('C:\\Users\\1233\\Desktop\\Machine Learning\\face_images\\' + subfile+'\\'+name)
target.append(i)
i += 1
print(photo_name)
for path in photo_name:
photo = imgplt.imread(path)
# photo = cv.imread(path)
photo = photo.reshape(1, -1)
photo = pd.DataFrame(photo)
total_photo = total_photo.append(photo, ignore_index=True)
total_photo = total_photo.values
def kmeans():
clf = KMeans(n_clusters=10)
clf.fit(total_photo)
y_predict = clf.predict(total_photo)
centers = clf.cluster_centers_
result = centers[y_predict]
result = result.astype("int64")
result = result.reshape(200, 200, 180, 3) # 图像的矩阵大小为200,180,3
return result, y_predict
def draw():
fig, ax = plt.subplots(nrows=10, ncols=20, sharex=True, sharey=True, figsize=[15, 8], dpi=80)
plt.subplots_adjust(wspace=0, hspace=0)
count = 0
for i in range(10):
for j in range(20):
ax[i, j].imshow(result[count])
count += 1
plt.show()
def score():
print(clusteringMetrics(target, y_predict))
total_photo = pd.DataFrame()
getimage()
result, y_predict = kmeans()
draw()
score()
效果图(就这,也跑了十几秒T∩T)
2、直接放代码吧,PCA 理论分析比较难,但用起来挺简单的,学着别人的例子用改改参数就行了(Python 真香)
参考了 Scikit-learn实例之Pca+Svm人脸识别(AT&T数据集)
import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.decomposition import PCA
path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180
def createDatabase(path):
TrainFiles = os.listdir(path)
Train_Number = len(TrainFiles)
train = []
y_sample = []
for k in range(0, Train_Number):
Trainneed = os.listdir(path + '/' + TrainFiles[k])
Trainneednumber = len(Trainneed)
for i in range(0, Trainneednumber):
image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32)
image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
train.append(image)
y_sample.append(k)
train = np.array(train)
y_sample = np.array(y_sample)
return train, y_sample
# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
X_ = X.reshape(X.shape[0], h*w)
# 从200张图里挑出特征值前10的特征脸
n_components = 10
pca = PCA(n_components).fit(X_) # svd_solver='randomized', whiten=True
eigenfaces = pca.components_.reshape((n_components, h, w))
# 将输入数据投影到特征面正交基上
X_train_pca = pca.transform(X_)
def plot_gallery(images, titles, h, w, n_row=1, n_col=10):
"""Helper function to plot a gallery of portraits"""
plt.figure(figsize=(1.8 * n_col, 2 * n_row))
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35) # 图片位置布局
for i in range(10):
plt.subplot(n_row, n_col, i + 1)
plt.imshow(images[i].reshape((h, w)))
# plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles[i], size=12)
# 把坐标去了
plt.xticks(())
plt.yticks(())
eigenface_titles = ["eigenface %d" % (i+1) for i in range(eigenfaces.shape[0])]
plot_gallery(eigenfaces, eigenface_titles, h, w)
plt.show()
效果图
不需要用到 opencv,直接用 matplotlib 的相关函数求特征脸
from sklearn.decomposition import PCA
import matplotlib.pyplot as plt
import matplotlib.image as imgplt
import os
import pandas as pd
path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
n_row, n_col = 1, 10
n_components = n_row * n_col
image_shape = (200, 540)
photo_name = []
target = []
total_photo = pd.DataFrame()
def getinfo(path):
# 获取文件并构成向量
# 预测值为1维,把一张图片的三维压成1维,那么n张图片就是二维
global total_photo
file = os.listdir(path)
# 遍历每个图片
for subfile in file:
photo = os.listdir(path + subfile)
for name in photo:
photo = imgplt.imread(path + subfile + '/' + name)
photo = photo.reshape(1, -1)
photo = pd.DataFrame(photo)
total_photo = total_photo.append(photo, ignore_index=True)
total_photo = total_photo.values
getinfo(path)
faces = total_photo
def plot_gallery(images, title, n_col=n_col, n_row=n_row):
plt.figure(figsize=(1.8 * n_col, 2 * n_row))
plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35)
plt.suptitle(title, size=16)
for i, comp in enumerate(images):
plt.subplot(n_row, n_col, i + 1)
# vmax = max(comp.max(), -comp.min())
plt.imshow(comp.reshape(image_shape)) # cmap=plt.cm.gray interpolation='nearest', vmin=-vmax, vmax=vmax
plt.xticks(())
plt.yticks(())
estimators = [("", PCA(n_components=10, whiten=True))]
for name, estimator in estimators:
# print("Extracting the top %d %s..." % (n_components, name))
# print(faces.shape)
estimator.fit(faces)
components_ = estimator.components_
plot_gallery(components_[:n_components], name)
plt.show()
效果图(跑出来效果差一点,应该是有地方修改的,改半天没搞定,先放着了)
3、循环聚类下画个图就OK了
import matplotlib.pyplot as plt
import os
import cv2 as cv
import numpy as np
from sklearn.cluster import KMeans
from sklearn.decomposition import PCA
from PIL import Image
from ML_clustering_performance import clusteringMetrics
path = 'C:/Users/1233/Desktop/Machine Learning/face_images/'
h, w = 200, 180
IMAGE_COLUMN = 20
IMAGE_ROW = 10
def createDatabase(path):
TrainFiles = os.listdir(path)
Train_Number = len(TrainFiles)
train = []
y_sample = []
for k in range(0, Train_Number):
Trainneed = os.listdir(path + '/' + TrainFiles[k])
Trainneednumber = len(Trainneed)
for i in range(0, Trainneednumber):
img = Image.open(path + '/' + TrainFiles[k] + '/' + Trainneed[i])
image = cv.imread(path + '/' + TrainFiles[k] + '/' + Trainneed[i]).astype(np.float32)
image = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
train.append(image)
y_sample.append(k)
train = np.array(train)
y_sample = np.array(y_sample)
return train, y_sample
# n_samples, h, w = 200, 200, 180
X, y = createDatabase(path)
X_ = X.reshape(X.shape[0], h*w)
n_components = 10
ACCS = []
NMIS = []
ARIS = []
for i in range(1, 9):
n_components = i
pca = PCA(n_components=n_components).fit(X_) # svd_solver='randomized', whiten=True
eigenfaces = pca.components_.reshape((n_components, h, w))
# 将输入数据投影到特征面正交基上
X_train_pca = pca.transform(X_)
# 聚类
kms = KMeans(n_clusters=10)
y_sample = kms.fit_predict(X_train_pca, y)
ACC, NMI, ARI = clusteringMetrics(y, y_sample)
ACCS.append(ACC)
NMIS.append(NMI)
ARIS.append(ARI)
fig, ax = plt.subplots()
bar_width = 0.35
opacity = 0.4 # 不透明度
index = np.arange(8)
# error_config = {'ecolor': '0.3'}
rects1 = ax.bar(index, ACCS, bar_width, alpha=opacity, color='r', label='ACC') # error_kw=error_config
rects2 = ax.bar(index + bar_width, NMIS, bar_width, alpha=opacity, color='g', label='NMI')
rects3 = ax.bar(index + 2*bar_width, ARIS, bar_width, alpha=opacity, color='b', label='ARI')
ax.set_xticks(index + bar_width / 2)
ax.set_xticklabels(('1', '2', '3', '4', '5', '6', '7', '8'))
ax.legend()
plt.show()
效果图