机器学习实战笔记4——主成分分析

Amber ·
更新时间:2024-09-21
· 810 次阅读

任务安排

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={xix_ixi​}是属于nnn维空间的,通过特征提取或者特征选择的方法,将原空间的维数降至kkk维,要求kkk远小于nnn,并满足:kkk维空间的特性能反映原空间数据的特征,这个过程称之为维数约简
      维数约简即通过某种数学变换,将原始高维属性空间转变为一个低维子空间,在这个子空间中样本密度大幅度提高,距离计算也变得容易起来
在这里插入图片描述
      由线性代数的知识我们知道,空间维度的改变依赖于变换矩阵,如XXX是一个nnn维列向量X=[1,2,...,n]TX=[1,2,...,n]^TX=[1,2,...,n]T,我们想要把它变成Y=[1,2,...,m]TY=[1,2,...,m]^TY=[1,2,...,m]T,即在XXX前面乘上一个m×nm×nm×n的变换矩阵AAA
      而主成分分析,就是降维里的一种重要方法。

      既然要对已有的特征值进行降维变换,那么首先,我们要先得到原样本集的特征值,回顾一下线性代数的知识。
      有一个nnn阶矩阵AAA,若存在数λλλ和非零nnn维列向量XXX,满足AX=λXAX=λXAX=λX,则称λ为A的一个特征值,X为A的对应于λ的一个特征向量

Ⅲ 核心思想

      主成分分析(Principal Component Analysis)的出发点是从一组特征(nnn维)中计算出一组按重要性从大到小排列的新特征(kkk维,k≤nk≤nk≤n,通常取远小于nnn),它们是原有特征的线性组合,并且相互之间不相关。(比如你和小伙伴的理科成绩非常接近,那么决定你们之间差距的主要科目(新特征值PC)就是文科类的了,只关注这几科,即降维了)

①主成分特点

      1. 源于质心的矢量
      2. 主成分①指向最大方差的方向
      3. 各后续主成分与前一主成分正交,且指向残差(剩余)子空间最大方差的方向

②举例(二维)

为了便于分析说明,我们举二维样本集的例子:
      如下图所示,红色的两向量表示“蓝色椭圆”的长轴短轴,很明显可以看出,假如我们把样本集的点投影到长轴上更能反映出样本集整体的分布,故在这个例子里我们把长轴记为主成分#1与长轴正交(互不相关)的短轴记为主成分#2,理想情况下,短轴的模(高维情况下称范数)为0,即仅通过长轴就可以完全分析出样本集的分布,这就实现了完美的降维,因而我们容易知道,长短轴的模(范数)相差越大,即降维的效果越好,所以我们的目标就是,找出尽量长的长轴(标号靠前的主成分)
在这里插入图片描述

③最大方差理论

      通常,我们认为信号具有较大的方差,噪声具有较小的方差,信噪比就是信号与噪声的功率之差(10lg(PsPn)10lg(\frac{P_s}{P_n})10lg(Pn​Ps​​)),越大越好。如下图所示,我们把紫色线上的数据认为是信号,而蓝色线上的数据认为是噪声,因此我们的目的就是最大化投影数据的方差(样本点在紫线上最分散)最小化数据点与投影之间的均方距离(蓝线和越小)
在这里插入图片描述

④目的

      PCA的目的就是“降噪”和“去冗余”。
      “降噪”即使保留下来的维度间的相关性尽可能小
      “去冗余”即使保留下来的维度含有的方差(能量)尽可能大

★Ⅳ 算法剖析

输入:样本集{xixixi}i=1n^n_{i=1}i=1n​,低维空间维数k(即所要保留的新特征值个数)
输出:投影矩阵W=[w1,w2,...,wk]W=[w_1,w_2,...,w_k]W=[w1​,w2​,...,wk​]
下面介绍两种PCA的实现方法:

①顺序排列

      1.对所有样本进行中心化(和期望作差)xi←xi−1n∑i=1nxix_i←x_i-\frac{1}{n}∑^n_{i=1}x_ixi​←xi​−n1​i=1∑n​xi​
      2.对中心化的数据{x1,x2,...,xnx_1,x_2,...,x_nx1​,x2​,...,xn​},计算主成分#1:(即目标函数)
w1=arg(max∣∣w1∣∣=11n∑i=1n(w1Txi)2)w_1=arg(\underset{||w_1||=1}{max}\frac{1}{n}∑^n_{i=1}(w^T_1x_i)^2)w1​=arg(∣∣w1​∣∣=1max​n1​i=1∑n​(w1T​xi​)2)
w1Txiw^T_1x_iw1T​xi​即内积运算(w1w_1w1​为单位向量),求的是xix_ixi​在w1w_1w1​上的投影,平方是为了省去求绝对值
利用拉格朗日乘数法求解最优λλλ,约束条件为||w||=1(即wTw=1w^Tw=1wTw=1)
L(w,λ)=1n(wTxi)2−λ(wTw−1)L(w,λ)=\frac{1}{n}(w^Tx_i)^2-λ(w^Tw-1)L(w,λ)=n1​(wTxi​)2−λ(wTw−1)
(矩阵求导)对www求导∂L∂w=(1n∑i=1nxixiT)w−λw\frac{\partial L}{\partial w}=(\frac{1}{n}∑^n_{i=1}x_ix_i^T)w-λw∂w∂L​=(n1​∑i=1n​xi​xiT​)w−λw
实际上,令X=[x1,x2,...,xn]X=[x_1,x_2,...,x_n]X=[x1​,x2​,...,xn​],则XXT=1n∑i=1nxixiTXX^T=\frac{1}{n}∑^n_{i=1}x_ix_i^TXXT=n1​∑i=1n​xi​xiT​
      3.最大化投影方差
wk=arg(max∣∣w1∣∣=11n∑i=1n[wkT(xi−∑j=1k−1wjwjTxi⏟xi′)]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​∣∣=1max​n1​i=1∑n​[wkT​(xi′​xi​−j=1∑k−1​wj​wjT​xi​​​)]2)
后面一串 xi−∑j=1k−1wjwjTxix_i-∑^{k-1}_{j=1}w_jw_j^Tx_ixi​−∑j=1k−1​wj​wjT​xi​ 可以简单点理解为,扣掉前面那个主成分的方向,在剩下的残差子空间里求新的主成分在这里插入图片描述

②协方差矩阵法

      1.对所有样本进行去中心化(和期望作差)xi←xi−1n∑i=1nxix_i←x_i-\frac{1}{n}∑^n_{i=1}x_ixi​←xi​−n1​i=1∑n​xi​
      2.计算样本的协方差矩阵CCC
C=(cij)n×n=[c11c12...c1nc21c22...c2n............cn1cn2...cnn]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​=⎣⎢⎢⎡​c11​c21​...cn1​​c12​c22​...cn2​​............​c1n​c2n​...cnn​​⎦⎥⎥⎤​
                         cij=Cov(Xi,Yj)c_{ij}=Cov(X_i,Y_j)cij​=Cov(Xi​,Yj​)     i,j=1,2,...,ni,j=1,2,...,ni,j=1,2,...,n
      (对角线元素为某一维度的方差)
      3.对协方差矩阵C做特征值分解(即求所有满足的特征值和特征向量)CW′=λW′CW'=λW'CW′=λW′(也可以用拉格朗日乘数法只求所需的最大的k个)
      4.取最大的k个特征值所对应的特征向量w1,w2,...,wkw_1,w_2,...,w_kw1​,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 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): 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()

效果图
在这里插入图片描述
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()

效果图
在这里插入图片描述


作者:绍少阿



机器学习实战 实战 学习 主成分分析 机器学习

需要 登录 后方可回复, 如果你还没有账号请 注册新账号