python pca/svd原理及应用

news2025/1/23 9:18:21

PCA的定义

  • 主成分分析,即Principal Component Analysis(PCA),是多元统计中的重要内容,也广泛应用于机器学习和其它领域。它的主要作用是对高维数据进行降维。PCA把原先的n个特征用数目更少的k个特征取代,新特征是旧特征的线性组合,这些线性组合最大化样本方差,尽量使新的k个特征互不相关。

PCA的实现步骤

  1. 计算样本每个特征的平均值;

  1. 每个样本数据减去该特征的平均值;

  1. 对样本组成的矩阵求协方差矩阵;

  1. 对协方差矩阵做分解得到特征值和特征向量,并将特征值和特征向量重新按照降序排列;

  1. 对特征值求取累计贡献率;

  1. 通过累计贡献率选取适合的特征向量子集合;

  1. 对原始数据进行转换


注意:假设有m个样本,每个样本有n个特征,即组成m行n列的矩阵A,如果是图像的话,由于图像是二维向量,所以先要将图像转换为一个行向量。求均值是对A矩阵的每一列求均值,此处协方差矩阵应该是A.T * A而不是A*A.T,最后得到的协方差矩阵的形状应为n*n。

协方差矩阵分解

  1. 原始算法(硬算,特征数很大时计算量非常大)

  1. numpy的svd算法来分解(使用svd分解出来的右奇异矩阵和直接求出来的特征向量矩阵是一个意思,但是svd并不是通过协方差矩阵来计算的,而是通过某种强大的算法近似求解)

  1. scikit-learn实现的PCA

PCA实现

mat = [[-1,-1,0,2,1],[2,0,0,-1,-1],[2,0,1,1,0]]
mat = np.array(mat)
#原始算法
def origin_algorithm_pca(mat, 2):
    #对列求均值
    mean = np.mean(mat, 0)
    #去中心化
    A = mat - mean
    #求方差矩阵
    cov = np.dot(A.T, A)/2
    #求解协方差矩阵的特征值和特征向量
    s, vector = np.linalg.eig(cov)
    #对特征进行压缩
    compression = np.dot(A, vector[:2,:].T)
    return compression

def numpy_svd(mat, 2):
    #对列求均值
    mean = np.mean(mat, 0)
    #去中心化
    A = mat - mean
    #
    u,s,VT = np.linalg.svd(A)
    #压缩
    compression = np.dot(A, VT[:2,:])
    return compression

PCA实现人脸识别

  1. 将每张图像拉直为一维行向量

  1. 将所有样本存储为矩阵形式,矩阵的每一列表示图像的一个特征也是一个像素

  1. 按列求取均值,并用原始矩阵减去均值

  1. 利用A.T * A得到协方差矩阵(这一步代码中直接利用svd方法得到U,S,VT)

  1. 将原始矩阵乘以VT得到压缩后的矩阵,将VT存储起来用于测试测试样本

  1. train_A*VT和test_A*VT,将test_A*VT中的每个样本与train_A*VT计算平方差,并按行求和后排序,得到距离最小的对应的train_A的label,就是预测结果

  1. 根据预测结果和真实标签计算准确率

# coding:utf-8
import os
from numpy import *
import numpy as np
import cv2
import matplotlib.pyplot as plt
from pylab import mpl

mpl.rcParams['font.sans-serif'] = ['SimHei']


# 图片矢量化
def img2vector(image):
    img = cv2.imread(image, 0)  # 读取图片
    rows, cols = img.shape  #获取图片的像素
    imgVector = np.zeros((1, rows * cols))
    imgVector = np.reshape(img, (1, rows * cols))#使用imgVector变量作为一个向量存储图片矢量化信息,初始值均设置为0
    return imgVector


orlpath = "./ORL"


# 读入人脸库,每个人随机选择k张作为训练集,其余构成测试集
def load_orl(k):#参数K代表选择K张图片作为训练图片使用
    '''
    对训练数据集进行数组初始化,用0填充,每张图片尺寸都定为112*92,
    现在共有40个人,每个人都选择k张,则整个训练集大小为40*k,112*92
    '''
    train_face = np.zeros((40 * k, 112 * 92))
    train_label = np.zeros(40 * k)  # [0,0,.....0](共40*k个0)
    test_face = np.zeros((40 * (10 - k), 112 * 92))
    test_label = np.zeros(40 * (10 - k))
    # sample=random.sample(range(10),k)#每个人都有的10张照片中,随机选取k张作为训练样本(10个里面随机选取K个成为一个列表)
    sample = random.permutation(10) + 1  # 随机排序1-10 (0-9)+1
    for i in range(40):  # 共有40个人
        people_num = i + 1
        for j in range(10):  # 每个人都有10张照片
            image = orlpath + '/s' + str(people_num) + '/' + str(sample[j]) + '.jpg'
            # 读取图片并进行矢量化
            img = img2vector(image)
            if j < k:
                # 构成训练集
                train_face[i * k + j, :] = img
                train_label[i * k + j] = people_num
            else:
                # 构成测试集
                test_face[i * (10 - k) + (j - k), :] = img
                test_label[i * (10 - k) + (j - k)] = people_num

    return train_face, train_label, test_face, test_label


# 定义PCA算法
def PCA(data, r):#降低到r维
    data = np.float32(np.mat(data))
    rows, cols = np.shape(data)
    # print(rows, cols)
    data_mean = np.mean(data, 0)  # 对列求平均值
    A = data - np.tile(data_mean, (rows, 1))  # 将所有样例减去对应均值得到A
    u, s, VT = np.linalg.svd(A) #利用svd求解右奇异向量即需要将原始数组映射的向量空间矩阵
    V_r = VT[:, 0:r]  # 按列取前r个特征向量
    #将原始数据乘上新的空间向量得到降维后的矩阵
    final_data = A * V_r
    return final_data, data_mean, V_r

def face_recongize():
    for r in range(10, 81, 10):  # 最多降到40维,即选取前40个主成分(因为当k=1时,只有40维)
        print("当降维到%d时" % (r))
        x_value = []
        y_value = []
        train_face, train_label, test_face, test_label = load_orl(7)  # 得到数据集

        # 利用PCA算法进行训练
        data_train_new, data_mean, V_r = PCA(train_face, r)
        # print(data_train_new.shape)
        num_train = data_train_new.shape[0]  # 训练脸总数
        num_test = test_face.shape[0]  # 测试脸总数
        temp_face = test_face - np.tile(data_mean, (num_test, 1))
        data_test_new = temp_face * V_r  # 得到测试脸在特征向量下的数据
        data_test_new = np.array(data_test_new)  # mat change to array
        # print(data_test_new.shape)
        data_train_new = np.array(data_train_new)

        # 测试准确度
        true_num = 0
        for i in range(num_test):
            testFace = data_test_new[i, :]
            # print(testFace.shape)
            diffMat = data_train_new - np.tile(testFace, (num_train, 1))  # 训练数据与测试脸之间距离
            print(diffMat.shape)
            sqDiffMat = diffMat ** 2
            sqDistances = sqDiffMat.sum(axis=1)  # 按行求和
            sortedDistIndicies = sqDistances.argsort()  # 对向量从小到大排序,使用的是索引值,得到一个向量
            indexMin = sortedDistIndicies[0]  # 距离最近的索引
            if train_label[indexMin] == test_label[i]:
                true_num += 1
            else:
                pass

            accuracy = float(true_num) / num_test
            x_value.append(7)
            y_value.append(round(accuracy, 2))

        print('当每个人选择%d张照片进行训练时,The classify accuracy is: %.2f%%' % (7, accuracy * 100))

if __name__ == '__main__':
    face_recongize()

PCA的优缺点

  1. 优点

  • 仅仅需要以方差衡量信息量,不受数据集以外的因素影响。

  • 各主成分之间正交,可消除原始数据成分间的相互影响的因素

  • 计算方法简单,主要运算是特征值分解,易于实现。

  1. 缺点

  • 主成分各个特征维度的含义具有一定的模糊性,不如原始样本特征的解释性强。

  • 方差小的非主成分也可能含有对样本差异的重要信息,因降维丢弃可能对后续数据处理有影响。

SVD原理

任意形状的矩阵A经过svd分解会得到UΣVT(V的转置)三个矩阵,其中U是一个M×M的方阵,被称为左奇异向量,方阵里面的向量是正交的;Σ是一个M×N的对角矩阵,除了对角线的元素其他都是0,对角线上的值称为奇异值;VT(V的转置)是一个N×N的矩阵,被称为右奇异向量,方阵里面的向量也都是正交的。

可以计算ΣΣ前x个奇异值的平方和占所有奇异值的平方和的比例,如果大于90%,我们就选这x个奇异值重构矩阵(剩余的数据代表的可能是噪声,无用数据)。

那么重构的A'为:

SVD的应用

  • svd实现图像压缩

import scipy.misc
from scipy.linalg import svd
import matplotlib.pyplot as plt
import numpy as np
import numpy
img = scipy.misc.face()[:,:,0]
img = np.array(img)
U,s,Vh=svd(img)
#将特征压缩到十维,并还原图像
A = numpy.dot(U[:,0:10],numpy.dot(numpy.diag(s[0:10]),Vh[0:10,:]))
plt.subplot(111,aspect='equal')
plt.title(":10")
plt.imshow(A)
plt.imsave('a10.png', A)
  • svd实现信号去噪

import matplotlib.pylab as plt
import numpy as np
import numpy
from scipy.linalg import svd
x = np.linspace(-np.pi, np.pi, 400)
mu, sigma = 0, 0.05
ss = np.random.normal(mu, sigma, 400)
a = (np.sin(x) + ss).reshape(20, 20)

U,s,Vh = svd(a)
print s
A = numpy.dot(U[:,0:2],numpy.dot(numpy.diag(s[0:2]),Vh[0:2,:]))
aa = A.reshape((400,))

plt.subplot(221,aspect='equal')
plt.plot(x, np.sin(x))
plt.title("sin")

plt.subplot(222,aspect='equal')
plt.plot(x, np.sin(x) + ss)
plt.title("sin with noise")

plt.subplot(223,aspect='equal')
plt.title("sin remove noise x = 2")
plt.plot(x, aa)

A = numpy.dot(U[:,0:1],numpy.dot(numpy.diag(s[0:1]),Vh[0:1,:]))
aa = A.reshape((400,))
plt.subplot(224,aspect='equal')
plt.title("sin remove noise x = 1")
plt.plot(x, aa)

plt.show()

第一副图是纯sin波形,第2副图是加了噪声的波形,第三副选择2个奇异值重构A结果很接近标准sin波形实现了去噪,第四副图是选了1个奇异值重构A的结果。

参考文献

http://liao.cpython.org/scipy06.html

https://www.cnblogs.com/jclian91/p/8024101.html

https://blog.csdn.net/m0_50572604/article/details/121018988

https://www.cnblogs.com/pinard/p/6239403.html

https://www.cnblogs.com/pinard/p/6251584.html

https://github.com/Gaoshiguo/PCA-Principal-Components-Analysis

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/397117.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Elasticsearch使用——高级篇

1.数据聚合**聚合&#xff08;aggregations&#xff09;**可以让我们极其方便的实现对数据的统计、分析、运算。例如&#xff1a;什么品牌的手机最受欢迎&#xff1f;这些手机的平均价格、最高价格、最低价格&#xff1f;这些手机每月的销售情况如何&#xff1f;实现这些统计功…

【ns-3】添加nr(5G-LENA)模块

文章目录前言1. 下载5G-LENA源代码2. 配置并重新构建ns-3项目参考文献前言 本篇以ns-3.37为例介绍如何在ns-3中添加nr&#xff08;5G-LENA&#xff09;模块 [1]。5G-LENA是一个由Mobile Networks group CTTC&#xff08;Centre Tecnolgic de Telecomunicacions de Catalunya&a…

微信小程序开发学习笔记1——安心食疗

2.1小程序代码结构 目录结构 1.小程序的目录 pages:小程序的页面 页面路径 一个小程序页面由四个文件组成&#xff0c;分别是&#xff1a; xxx.js xxx.wxml xxx.json xxx.wxss 注意&#xff1a;为了方便开发者减少配置项&#xff0c;描述页面的四个文件必须具有相同的路径与文…

MySQL(二)视图、锁、存储过程、触发器、锁以及常用工具

MySQL进阶视图检查选项视图的更新存储过程存储过程基本语法变量系统变量用户自定义变量局部变量if判断参数casewhile循环repeat循环loop循环cursor游标handler条件处理程序存储函数触发器锁全局锁表级锁表锁元数据锁意向锁行级锁行锁间隙锁&临键锁InnoDB引擎逻辑存储结构事…

使用Arduino开发ESP32:开发环境搭建

开发环境搭建 使用Arduino开发ESP32开发环境搭建方式和用Arduino开发ESP8266相似&#xff1a;https://blog.csdn.net/Naisu_kun/article/details/80186950#t0 下载安装Arduino IDE&#xff1a; https://www.arduino.cc/en/Main/Software Arduino IDE中添加ESP32开发板数据&a…

第二道pwn题:shellcode

题目来自视频&#xff1a;链接&#xff1a;https://pan.baidu.com/s/17vX9dbfHkXBw71mcEXBgNQ?pwd6666 提取码&#xff1a;6666查看文件类型和保护&#xff0c;虽然现在的我还没有明白太多的保护。64位&#xff0c;放到ida里边rbp:保存的是栈中当前执行函数的基本地址。当前执…

xCAT安装指南

一、简介 xCAT使您能够轻松管理任何类型的技术计算工作负载的大量服务器。xCAT以卓越的扩展、各种支持的硬件和操作系统、虚拟化平台和完整的“day0”设置功能而闻名。 二、安装指南 免责声明 这些说明仅为指南&#xff0c;具体细节可能因操作系统版本而略有不同。有关最新推…

TCP与UDP

概述 传输层时向上层的应用层提供通讯服务的&#xff0c;是属于面向通信部份的最高层&#xff0c;同时也是用户功能的最底层 传输层有两个很重要的特点&#xff1a;复用、分用 复用&#xff1a;应用层所有的应用进程都可以通过运输层再传到网络层 分用&#xff1a;运输层从网…

【Unity】多分辨率适配

笔者按&#xff1a;使用Unity版本为2021.3LTS&#xff0c;与其他版本或有异同。请仅做参考 一、前言。 本文是笔者在学习使用Unity引擎的过程中&#xff0c;产学研的一个笔记。由笔者根据官方文档Unity User Manual 2021.3 (LTS)/Create user interfaces (UI)/Unity UI/UI 操作…

mingw编译opencv

我这里是msys2 这个是msys2的教程 https://blog.csdn.net/qq_39942341/article/details/105931335?ops_request_misc%257B%2522request%255Fid%2522%253A%2522167821146216800197067008%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&requ…

【LeetCode】剑指 Offer 24. 反转链表 p142 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/fan-zhuan-lian-biao-lcof/submissions/ 1. 题目介绍&#xff08;24. 反转链表&#xff09; 定义一个函数&#xff0c;输入一个链表的头节点&#xff0c;反转该链表并输出反转后链表的头节点。 【测试用例】&#xff1a; 示…

C++右值引用/移动语义

在此之前&#xff0c;我们所用的引用&#xff0c;其实都是左值引用。 int a 10; int& ra a; 下面我们来重新认识一下引用&#xff1a; 而何为左值&#xff1f;左值引用其实是什么&#xff1f;请往下看~ 左值是一个表示数据的表达式(如变量名或解引用的指针)&#xff…

77. writerows写入多行

文章目录1. 目标任务2. 准备工作3. writerow单行写入4. writerows多行写入5. a以追加的模式写入值6. 总结1. 目标任务 新建【各班级成绩】文件夹&#xff1b; 在该文件夹下新建一个【1班成绩单.csv】文件&#xff1b; 在该文件中写入下面的内容&#xff1a; 成绩 姓名 刘一…

CentOS 8搭建EMQX集群

概览 EMQX (opens new window)是一款大规模可弹性伸缩的云原生分布式物联网 MQTT (opens new window)消息服务器。 EMQ X 设计目标是实现高可靠&#xff0c;并支持承载海量物联网终端的MQTT连接&#xff0c;支持在海量物联网设备间低延时消息路由: 1. 稳定承载大规模的 MQTT 客…

Allegro如何添加菜单栏操作指导

Allegro如何添加菜单栏操作指导 用Allegro设计PCB的时候,将常用的命令放在菜单栏的话可以方便使用,省去设计时间,菜单如下图 Allegro支持自由添加或者删除菜单,具体操作如下 点击View点击Customize Toolbar

【使用vue init和vue create的区别以及搭建vue项目的教程】

vue init 是vue-cli2.x的初始化方式&#xff0c;可以使用github上面的一些模板来初始化项目 webpack是官方推荐的标准模板名 使用方式&#xff1a;vue init webpack 项目名称 例如使用github上面electron-vue的模板使用方式&#xff1a;vue init electron-vue 项目名称教程目…

Java的数据库编程:JDBC

Content &#x1f389;1什么是API &#x1f389;2.什么是JDBC &#x1f389;3.数据库驱动包的安装 &#x1f389;4.数据库安装包在idea的使用 &#x1f389;5.JDBC的增删改查的简单实现 今天为大家带来JAVA的数据库编程,也就是用Java实现数据库 数据库的最基本的操作就是…

分布式锁简介

Redis因为单进程、性能高常被用于分布式锁&#xff1b;锁在程序中作用是同步工具&#xff0c;保证共享资源在同一时刻只能被一个线程访问。 Java中经常用的锁synchronized、Lock&#xff0c;但是Java的锁智能保证单机的时候有效&#xff0c;分布式集群环境就无能为力了&#xf…

软件设计师错题集

软件设计师错题集一、计算机组成与体系结构1.1 浮点数1.2 Flynn分类法1.3 指令流水线1.4 层次化存储体系1.4.1 程序的局限性1.5 Cache1.6 输入输出技术1.7 总线系统1.8 CRC循环冗余校验码二、数据结构与算法基础2.1 队列与栈2.2 树与二叉树的特殊性2.3 最优二叉树&#xff08;哈…

VisualSP Enterprise - February crack

VisualSP Enterprise - February crack VisualSP(可视化支持平台)提供了一个上下文中完全可定制的培训平台&#xff0c;它可以作为企业web应用程序的覆盖层提供。无论员工正在使用什么应用程序&#xff0c;他们都能够快速访问页面培训和指导&#xff0c;说明如何最有效地使用该…