【机器学习】主成分分析(Principal Component Analysis,PCA)_吴恩达ML

2023-05-16

声明:本文基于在校课程及吴恩达ML教程,代码参考自多份博客(已在参考链接中表明),如需转载请标明出处。

源代码、实验数据、实验指导书: https://pan.baidu.com/s/1yTTI0_w2bZ7o8uuxravLyA 提取码: spbp

目录

    • 一、算法描述
    • 二、算法流程
      • I. 降维
      • II. 数据恢复
        • 压缩表示下的重构——数据恢复
    • 三、PCA 算法 python 实现
    • 四、吴恩达-机器学习 PCA 作业实践
      • assignment_1
      • assignment_2
    • 五、参考链接

一、算法描述

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. 降维

  1. 标准化。计算出所有特征的均值,然后令 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,(Xmean)/std

其中 mean 为所有样本数据的均值,std 为所有样本数据的标准差。

  1. 计算协方差矩阵(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=1mx(i)(x(i))T=m1XXT

x ( i ) x^{(i)} x(i) 代表第 i i i 个样本,是一个 n ∗ 1 n *1 n1 的向量, n n n 是特征维数, m m m 是样本个数。

  1. 计算协方差矩阵的特征向量(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 nn 维的主成分(Principal Component)集

  1. 降维。将数据从 n n n 维降至 k k k 维,只需要从 U U U 中选取前 k k k 个向量,获得一个 n ∗ k n*k nk 维度的矩阵。
    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 nk 维的前 k k k 个主成分
  • U r e d u c e T U_{reduce}^T UreduceT 是前 k k k 个主成分的转置( k ∗ n k*n kn 维), x ( i ) x^{(i)} x(i) n ∗ 1 n*1 n1 维的均值归一化后第 i i i 个样本数据,因此结果 z ( i ) z^{(i)} z(i) k ∗ 1 k*1 k1 维的投影向量
  • 整体使用矩阵计算即 m ∗ n m*n mn 维的 X X X 【矩阵乘】 n ∗ k n*k nk 维的 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 nk 维, z ( i ) z^{(i)} z(i) k ∗ 1 k*1 k1 维,可得 n ∗ 1 n*1 n1 维的 x a p p r o x ( i ) x^{(i)}_{approx} xapprox(i)
  • 整体使用矩阵计算, Z Z Z m ∗ k m*k mk 维, U r e d u c e T U_{reduce}^T UreduceT k ∗ n k*n kn 维,可得 m ∗ n m*n mn 维的 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) # numpy.std() 求标准差的时候默认是除以 n 的,即是有偏的,np.std无偏样本标准差方式为加入参数 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
        # 1. 均值、归一化
        normalize_x = self.normalize(X)
        # 2. 计算协方差矩阵
        cov_x = self.covariance_matrix(normalize_x)
        # 3. 计算协方差矩阵𝜮的特征向量, 使用奇异值分解(SVD分解)
        U, S, V = np.linalg.svd(cov_x)  # U: principle components (n, n)
        # 4. 将数据从𝑛维降至𝑘维,从𝑈中选取前𝑘个向量
        U_reduce = U[:, :keep_dims] # U_reduce.shape : (n, k)
        # 5. 将二维数据投影到主成分方向(二维数据降维到一维)得到降维的结果
        Z = normalize_x @ U_reduce # Z.shape : (m, k)
        return normalize_x, U_reduce, Z

    def recover(self, Z, U_reduce):
        """
        6. 数据恢复:将降维后一维数据再投影回二维空间。
            𝒙_𝒂𝒑𝒑𝒓𝒐𝒙^((𝒊) )=𝑼_𝒓𝒆𝒅𝒖𝒄𝒆 𝒛^((𝒊))
        """
        return Z @ U_reduce.T

四、吴恩达-机器学习 PCA 作业实践

  1. e x 7 d a t a 1. m a t ex7data1.mat ex7data1.mat 中的数据进行降维(原始数据是 2 2 2 维数据,降成 1 1 1 维)。
  2. 利用 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'] # X.shape : (50, 2)

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'] # X.shape : (5000, 1024)

if __name__ == '__main__':
    # 前100个人脸
    display_data(X, "Original faces")

    pca = PCA()
    X_norm, U_reduce, Z = pca.dimensional_reduction(X, 100)
    # 前100维主成分(转换成人脸形式)
    display_data(U_reduce.T, "Principle Components", 6, 6)

    X_approx = pca.recover(Z, U_reduce)
    # 100个人脸仅使用前100个主成分表示再恢复得到的人脸
    display_data(X_approx, "Recovered faces")

展示人脸数据的函数(displayData.py)

# displayData.py
import matplotlib.pyplot as plt
import numpy as np

# 函数说明:把输入的图像数据X进行重新排列,显示在一个面板figurePane中,
# 面板中有多个小imge用来显示每一行数据

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)

	# 设置图片的行数和列数
	# rows = 10 # np.floor(np.sqrt(m)).astype(int)
	# cols = 10 # np.ceil(m / rows).astype(int)
	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 = np.random.randint(0, m)
	current_image = 0
	for j in range(rows):
		for i in range(cols):
			if current_image >= m:
				break
			# [:,np.newaxis]可以让指定的那一列数据以列的形式返回和指定
			# 否则返回的是行的形式
			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 = np.random.randint(0, m)
			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 个主成分重构的人脸图像并排对比
    在这里插入图片描述

五、参考链接

  1. 吴恩达机器学习笔记-5
  2. 吴恩达机器学习作业Python实现(七):K-means和PCA主成分分析
  3. 机器学习 吴恩达 课后习题百度云资源 (Coursera 搬运)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【机器学习】主成分分析(Principal Component Analysis,PCA)_吴恩达ML 的相关文章

  • js 多级对象数组删除对象

    let firstIndex 61 null let secondIndex 61 null const findItemNested 61 arr itemId nestingKey 61 gt arr reduce a item myI
  • Aarch64安装Anaconda Pytorch Torchvision

    1 Anaconda wget https github com Archiconda build tools releases download 0 2 3 Archiconda3 0 2 3 Linux aarch64 sh sudo
  • 扩大VMWARE里面虚拟硬盘大小(*.vmdk)

    http blog csdn net bshawk archive 2008 01 28 2070587 aspx 最近编译2 6 22的内核时 xff0c 发现虚拟机器FC6硬盘空间不够了 xff0c 于是乎 xff0c 想扩展下硬盘的大
  • c#加载xml文件

    C 加载xml文件 XmlDocument xmlDoc 61 new XmlDocument xmlDoc Load Application StartupPath 43 34 34 43 34 xml xml 34 加载xml文件 Xm
  • zram

    wiki zram是Linux内核的一个模块 xff0c 之前被称为 compcache zram通过在RAM内的压缩块设备上分页 xff0c 直到必须使用硬盘上的交换空间 xff0c 以避免在磁盘上进行分页 xff0c 从而提高性能 由于
  • 英飞凌 AURIX 系列单片机的HSM详解(2)——与HSM相关的UCB和寄存器

    本系列的其它几篇文章 xff1a 英飞凌 AURIX 系列单片机的HSM详解 xff08 1 xff09 何为HSM 英飞凌 AURIX 系列单片机的HSM详解 xff08 2 xff09 与HSM相关的UCB和寄存器 英飞凌 AURIX
  • MySQL数据库知识点总结

    1 什么是 MySQL MySQL 是 种关系型数据库 xff0c 在 Java 企业级开发中 常常 xff0c 因为 MySQL 是开源免费的 xff0c 并 且 便扩展 阿 巴巴数据库系统也 量 到了 MySQL xff0c 因此它的稳
  • 论文笔记-Towards Scene Understanding-Unsupervised Monocular Depth Estimation

    论文信息 标题 xff1a Towards Scene Understanding Unsupervised Monocular Depth Estimation with Semantic aware Representation作者 x
  • 结合 Casbin 对 http 请求做 RBAC 鉴权以及添加请求路由参数支持

    目录 总结 背景 实操 安装 Casbin 创建一个 Casbin 模型 创建一个 Casbin 策略 加载 Casbin 模型和策略并创建一个路由 总结 在本文中 xff0c 我们将介绍如何结合 Casbin 对 HTTP 请求进行基于角
  • Git—— master|RELEASE1/1

    当提交代码时 xff0c 多人合作避免不了要冲突 公司就我一个前端 xff0c 所以我一般情况下几乎不习惯pull代码 记录一下今天的执行过程 1 在vscode工具中操作更新的代码 2 在Git Bash中push 代码 span cla
  • 【FPGA】Mint20.3系统安装VCS2018环境

    mint系统是目前新手入手linux系统最为容易的系统版本 xff0c 其界面与Windows系统高度重合 vcs是IC开发常用的系统仿真工具 xff0c 但vcs工具的安装是一个很头疼的事情 xff0c 本篇展现在mint20 3系统安装
  • kubernetes使用flannel网络插件服务状态显示CrashLoopBackOff

    使用Kubeadm安装K8s集群 xff0c 在安装flannel网络插件后 xff0c 发现pod kube flannel ds 一直是CrashLoopBackOff 报错内容如下 xff1a log is DEPRECATED an
  • 用Python写了个金融数据爬虫,半小时干了全组一周的工作量

    最近 xff0c 越来越多的研究员 基金经理甚至财务会计领域的朋友 xff0c 向小编咨询 xff1a 金融人需要学Python么 xff1f 事实上在2019年 xff0c 这已经不是一个问题了 Python已成为国内很多顶级投行 基金
  • SSIS_数据流转换(Union All&合并联接&合并)

    Union All xff1a 与sql语言 Union All 一样 xff0c 不用排序 xff0c 上下合并多个表 Union All转换替代合并转换 xff1a 输入输出无需排序 xff0c 合并超过两个表 合并联接 xff1a 有
  • LACP协议:链路聚合/华为交换机LACP

    链路聚合的3种模式 61 61 61 61 61 gt 手工聚合 静态聚合 动态聚合 手工聚合 xff1a 手工汇聚概述 xff1a 手工负载分担模式是一种最基本的链路聚合方式 xff0c Eth Trunk 接口的建立 xff0c 成员接
  • Pytorch中Tensor和numpy数组的互相转化

    Pytorch中Tensor和Numpy数组的相互转化分为两种 xff0c 第一种转化前后的对象共享相同的内存区域 xff08 即修改其中另外一个也会改变 xff09 xff1b 第二种是二者并不共享内存区域 共享内存区域的转化 这种涉及到
  • #51单片机# 用中断实现蜂鸣器

    蜂鸣器常作为提示音 xff0c 用于计算机 打印机 万用表等设备中 提示音一般很简单 xff0c 能响就行 某单片机的蜂鸣器原理图 xff1a 该单片机的CPU原理图 xff1a 下面这段程序用到了中断的算法 xff0c 实现了蜂鸣器在4k
  • VM跨主机通信ovs配置

    如果位于不同物理主机上的两个VM需要通信 xff0c 那么底层的虚拟交换机ovs需要配置tunnel端口 OVS中支持添加隧道 Tunnel 端口 xff0c 常见隧道技术有两种gre或vxlan 隧道技术是在现有的物理网络之上构建一层虚拟
  • 免受 DDoS 攻击的五种技术

    尽管 DDoS 攻击很可怕 xff0c 但好消息是它们很容易预防 本节将讨论保护您的业务免受 DDoS 攻击的五种技术 一 高质量的网络硬件 高质量的网络基础设施可以帮助您检测甚至阻止网站流量的恶意增加 网络硬件包括路由器 用于连接设备的电
  • Failed to connect to /XXXfor block, add to deadNodes and continue. java.net.NoRouteToHostException:

    15 10 09 00 18 18 INFO DFSClient Could not obtain BP 1056880277 192 168 1 101 1444127746416 blk 1073741825 1001 from any

随机推荐