python主成分分析法降维_主成分分析降维(MNIST数据集)

今天看了用主成分分析简化数据,就顺便用MNIST数据集做了下实验,想直观地看一下效果,并通过完成这个小demo深入理解下原理。

我发现“是什么、能做什么、怎么用、效果是什么、原理是什么、优缺点是什么”这样的思路能让我更好地接受一个新知识,之所以把原理放在效果后面,是因为我比较喜欢先看看它的作用,可视化意义之后能提起我对一个知识的兴趣,加深对它意义的理解,后面看数学原理会容易,所以整篇文章就以这样的思路组织整理。

主成分分析是什么

主成分分析(Principal Component Analysis,PCA),一种降维方法,在PCA中,数据从原来的坐标系转换到了新的坐标系,新坐标系由数据本身决定,在新坐标系中,第一个坐标轴选择的是原始数据中方差最大的方向,第二个坐标轴选择的是和第一个坐标轴正交且具有最大方差的方向。该过程一直重复,重复次数为原始数据中特征的数目。我们会发现,大部分方差都包含在最前面的几个新坐标轴中。因此,我们可以忽略余下的坐标轴,即对数据进行了降维处理。

初看这段话感觉是抽象的。方差大意味着什么?方差是衡量源数据和期望值相差的度量值,方差越大,数据差别越大。选择方差最大的方向,就是选择数据差别最大的方向。重复特征数目次,就是说找第一个特征(第一维)方差最大的方向(即覆盖数据点最多的一条直线),做第一个轴,正交且最大方差方向做第二个轴,在此基础上再看第二个特征(第二维),找方差最大方向做第一个轴,正交且最大方差方向做第二个轴,依次类推。这样执行后会发现前几个坐标轴已经差不多囊括所有大差异了,剩下的就不要了,所以实现了降维。

上面从理论上讲了主成分分析和它是如何一步一步实现降维的,有一个感性认识。

主成分分析能做什么

降维,在多个指标中只取重要的几个指标,能使复杂问题简单化,就像说话说重点一样。

主成分分析怎么用

要做的事就是使用tensorflow里的MNIST数据集,取前100张图片中所有的手写数字7图片,对他们进行主成分分析,输出经过降维反变换回去的图片,对比差异,看看降维后的效果。

引入MNIST数据集、numpy和PIL的Image

import tensorflow.examples.tutorials.mnist.input_data as input_data

import numpy as np

from PIL import Image

获得MNIST数据集的所有图片和标签

mnist = input_data.read_data_sets("MNIST_data/", one_hot=False)

imgs = mnist.train.images

labels = mnist.train.labels

这里可以看看imgs和labels的type和shape,对于一个python初学者来说总是想搞清楚各个变量的类型和长相。

print(type(imgs)) #

print(type(labels)) #

print(imgs.shape) # (55000, 784)

print(labels.shape) # (55000,)

取前1000张图片里的100个数字7

origin_7_imgs = []

for i in range(1000):

if labels[i] == 7 and len(origin_7_imgs) < 100:

origin_7_imgs.append(imgs[i])

看看shape

print(np.array(origin_7_imgs).shape) # (100, 784)

把10张图片排成2x5的表格

由于一张图片是一个784维的一维数组,变成我们想看的图片就需要把它reshape成28x28的二维数组,然后再用Image里的方法,把它拼成一张2x5的大图。

由于tensorflow中MNIST都是灰度图(L),所以shape是(55000,784),每张图的dtype是float32,如果是彩色图(RGB),shape可能是(55000,784,3),图的dtype是uint8,从array转到Image需要用下面的方法:

def array_to_img(array):

array=array*255

new_img=Image.fromarray(array.astype(np.uint8))

return new_img

拼图

def comb_imgs(origin_imgs, col, row, each_width, each_height, new_type):

new_img = Image.new(new_type, (col* each_width, row* each_height))

for i in range(len(origin_imgs)):

each_img = array_to_img(np.array(origin_imgs[i]).reshape(each_width, each_width))

# 第二个参数为每次粘贴起始点的横纵坐标。在本例中,分别为(0,0)(28,0)(28*2,0)依次类推,第二行是(0,28)(28,28),(28*2,28)类推

new_img.paste(each_img, ((i % col) * each_width, (i / col) * each_width))

return new_img

```

- 效果图

```Python

ten_origin_7_imgs=comb_imgs(origin_7_imgs, 10, 10, 28, 28, 'L')

ten_origin_7_imgs.show()

数字7原图

实现主成分分析算法(详细代码解析在文章后面的原理部分)

def pca(data_mat, top_n_feat=99999999):

"""

主成分分析:

输入:矩阵data_mat ,其中该矩阵中存储训练数据,每一行为一条训练数据

保留前n个特征top_n_feat,默认全保留

返回:降维后的数据集和原始数据被重构后的矩阵(即降维后反变换回矩阵)

"""

# 获取数据条数和每条的维数

num_data,dim = data_mat.shape

print(num_data) # 100

print(dim) # 784

# 数据中心化,即指变量减去它的均值

mean_vals = data_mat.mean(axis=0) #shape:(784,)

mean_removed = data_mat - mean_vals # shape:(100, 784)

# 计算协方差矩阵(Find covariance matrix)

cov_mat = np.cov(mean_removed, rowvar=0) # shape:(784, 784)

# 计算特征值(Find eigenvalues and eigenvectors)

eig_vals, eig_vects = linalg.eig(mat(cov_mat)) # 计算特征值和特征向量,shape分别为(784,)和(784, 784)

eig_val_index = argsort(eig_vals) # 对特征值进行从小到大排序,argsort返回的是索引,即下标

eig_val_index = eig_val_index[:-(top_n_feat + 1) : -1] # 最大的前top_n_feat个特征的索引

# 取前top_n_feat个特征后重构的特征向量矩阵reorganize eig vects,

# shape为(784, top_n_feat),top_n_feat最大为特征总数

reg_eig_vects = eig_vects[:, eig_val_index]

# 将数据转到新空间

low_d_data_mat = mean_removed * reg_eig_vects # shape: (100, top_n_feat), top_n_feat最大为特征总数

recon_mat = (low_d_data_mat * reg_eig_vects.T) + mean_vals # 根据前几个特征向量重构回去的矩阵,shape:(100, 784)

return low_d_data_mat, recon_mat

调用PCA进行降维

low_d_feat_for_7_imgs, recon_mat_for_7_imgs = pca(np.array(origin_7_imgs), 1) # 只取最重要的1个特征

print(low_d_feat_for_7_imgs.shape) # (100, 1)

print(recon_mat_for_7_imgs.shape) # (100, 784)

看降维后只用1个特征向量重构的效果图

low_d_img = comb_imgs(recon_mat_for_7_imgs, 10, 10, 28, 28, 'L')

low_d_img.show()

数字7降维后的图

主成分分析效果是什么

降维前后对比图

不难发现降维后数字7长得规则多了,或许降维后再用tensorflow入门教程的softmax进行分类accuracy会更高。

主成分析的原理是什么

前面转坐标轴从理论上考虑,这里主要从数学的角度考虑。

第一个主成分是数据差异最大(方差最大)的方向,第二个主成分是数据差异次大且与第一个主成分正交的方向。通过数据集的协方差矩阵及其特征值分析,就能求得这些主成分的值。

统计学中的几个概念

平均值

这个最为熟悉最不容易忘记,描述样本集合的中间点。

标准差

描述样本集合中各个点到平均值的距离。

方差

标准差的平方。

方差

协方差

方差是用来描述一维数据的,协方差用来描述二维数据,用来描述两个随机变量之间的关系,如果是正值,则说明两变量正相关,负值,说明负相关,0,说明不相关,即相互独立。

协方差

从公式可以看出协方差的一些性质:

1、cov(X, X) = var(X)

2、cov(X,Y) = cov(Y, X)

协方差矩阵

协方差可以描述二维数据,但是对于多维数据来说,我们只能两个点两个点地计算多次协方差,一个n维数据,我们需要计算C(n, 2)=A(n,2)/2=n!/((n-2)!*2)个协方差,自然就需要用矩阵来组织这些数据。所以协方差矩阵的定义为

协方差矩阵

比如数据集有三个维度,X,Y,Z,则协方差矩阵为

三维协方差矩阵

可见,矩阵的对角线为方差,由于cov(X,Y) = cov(Y, X),所以是一个对称矩阵。

注意,协方差矩阵计算的是不同维度之间的协方差,不是不同样本之间的协方差。

结合代码分析原理

目的就是找出差异最大的方向,也就是影响最大的几个特征,数学上通过协方差矩阵来找差异最大的特征,排序,最后找到降维后的特征矩阵。

# 数据中心化,即指变量减去它的均值

mean_vals = data_mat.mean(axis=0) #shape:(784,)

mean_removed = data_mat - mean_vals # shape:(100, 784)

# 计算协方差矩阵(Find covariance matrix)

cov_mat = np.cov(mean_removed, rowvar=0)

协方差矩阵需要计算平均值,上面强调了计算的是不同维度的协方差,数据每行是一个样本,每列是一个维度,因此计算的是列的平均值,即axis=0,因此shape为(784,)。使用np的cov函数计算协方差矩阵,api入下:

numpy.cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None, aweights=None)[source]

详细的API请点这里

**rowvar代表是否转置。在API里,默认rowvar是True,也就是行是variable,列是observation,我们这里列是observation,行是variable。**

eig_vals, eig_vects = linalg.eig(mat(cov_mat)) # 计算特征值和特征向量

mat(cov_mat):将输入转成矩阵。和matrix,asmatrix不同,如果输入已经是举着嗯或者ndarray,它不会制作副本。相当于matrix(data, copy=False)

详细API请点这里

linalg.eig(a):计算特征值和特征向量

详细API请点这里

矩阵乘法对应了一个变换,在这个变换的过程中,原向量主要发生旋转、伸缩的变化。如果矩阵对某一个向量或某些向量只发生伸缩变换,不对这些向量产生旋转的效果,那么这些向量就称为这个矩阵的特征向量,伸缩的比例就是特征值。

eig_val_index = argsort(eig_vals) # 对特征值进行从小到大排序,argsort返回的是索引,即下标

numpy.argsort(a, axis=-1, kind='quicksort', order=None)

详细API请点这里

eig_val_index = eig_val_index[:-(top_n_feat + 1) : -1] # 最大的前top_n_feat个特征的索引

reg_eig_vects = eig_vects[:, eig_val_index]

这里有一个语法问题,[::]代表切片,[开始:结束:步长],负号代表从后往前每隔步长个取一次,比如有一个array[1, 2, 3, 4, 5],取[:-4:-2],0是第一个,-1是最后一个(在这里是5的下标),从最后一个往前数,一直数到-4(在这里是2的下标),每两个取1个数,最后得到的array是[5, 3]。

[:, eig_val_index]代表第一维不变,第二维要eig_val_index个,所以它的shape是(784,top_n_feat)

# 将数据转到新空间

low_d_data_mat = mean_removed * reg_eig_vects # shape: (100, top_n_feat), top_n_feat最大为特征总数

recon_mat = (low_d_data_mat * reg_eig_vects.T) + mean_vals # 根据前几个特征向量重构回去的矩阵,shape:(100, 784)

一个shape是(100,784)的矩阵,乘以一个shape是(784,top_n_feat)的矩阵,最后得到降维的矩阵(100, top_n_feat)

recon_mat再将矩阵变回(100,784),得到降维后再重构的矩阵。

主成分分析的优缺点是什么

优点:降低数据的复杂性,识别最重要的特征

缺点:不一定需要,且可能损失有用信息

适用数据类型:数值型数据

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

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

相关文章

ARIMA加法季节模型

目录 ARIMA加法季节模型 ARIMA加法季节模型函数 例题 ARIMA加法季节模型 季节效应和其它效应之间是加法关系 通过简单的趋势差分、季节差分之后转化为平稳&#xff0c;模型结构通常如下 ARIMA加法季节模型函数 例题 部分数据&#xff1a; timexJan-93977.5Feb-93892.5Mar…

Java在远程方法调用中运用反射机制

我们将介绍反射机制在网络编程中的应用&#xff0c;实现如何在客户端通过远程方法调用服务器端的方法。 假定在服务器端有一个 HelloService 接口&#xff0c;该接口具有 getTime() 和 echo() 方法&#xff0c;具体代码如下&#xff1a; import java.util.Date;public interf…

安捷伦频谱仪的使用方法图解_频谱仪的简单操作使用方法lbrack;1rsqb;

R3131A频谱仪简单操作使用方法一&#xff0e;R3131A频谱仪简介。R3131A频谱仪是日本ADVANTEST公司的产品&#xff0c;用于测量高频信号&#xff0c;可测量的频率范围为9K—3GHz。对于GSM手机的维修&#xff0c;通过频谱仪可测量射频电路中的以下电路信号, (维修人员可以通过对所…

多元时间序列分析 —— 因果检验

目录 因果检验 因果关系的识别 例 Granger 因果关系定义 两变量之间的4种因果关系 Granger因果检验 1.假设条件 2.检验统计量 例 进行Granger因果检验应该注意的问题 因果检验 因果关系的识别 对于多元时间序列而言&#xff0c;如果能找到对响应变量有显.著影响的输…

华为仿苹果字体_华为mate40系列再次霸榜DXO,网友:无敌是多么寂寞

阅读本文前&#xff0c;请您先点击上面的蓝色字体&#xff0c;再点击“关注”&#xff0c;这样您就可以免费收到最新内容了。每天都有分享&#xff0c;完全是免费订阅&#xff0c;请放心关注。声明&#xff1a;本文转载自网络&#xff0c;如有侵权&#xff0c;请在后台留言联系…

Java常见异常处理

异常&#xff08;exception&#xff09;是在运行程序时产生的一种异常情况&#xff0c;已经成为了衡量一门语言是否成熟的标准之一。 异常简介 Java 中的异常又称为例外&#xff0c;是一个在程序执行期间发生的事件&#xff0c;它中断正在执行程序的正常指令流。为了能够及时…

干预分析 + 伪回归

目录 干预分析 干预分析的定义 干预分析的产生背景 干预分析的实质 干预分析步骤 步骤一 步骤二 步骤三 步骤四 步骤五 步骤六 干预机制的选择 伪回归 定义 伪回归随机模拟试验 伪回归产生原因 干预分析 干预分析的定义 时间序列常常受到某些外部事件的影响…

R如何安装MSBVAR包!!!请看这里!!

目录 1.MSBVAR介绍 2.为何R上安装失败 3.解决方案 1.MSBVAR介绍 MSBVAR: 估计贝叶斯向量自回归模型和贝叶斯结构向量自回归模型&#xff0c;也可以用于时间序列的因果检验。 2.为何R上安装失败 MSBVAR现在不属于R中的库&#xff0c;属于第三方安装库&#xff0c;并且它在…

easy excel根据行列excel_Excel函数如何根据地级市匹配所在省份计算快递费用

前些日子一个学员问的关于excel计算快递费的问题&#xff0c;office小超老师觉得很有代表性。在这里和大家分享一下具体处理快递费的处理流程。在她的这个案例中&#xff0c;订单信息地区仅为各个地级市&#xff0c;现在的问题就是要根据不同的地级市和各个地区不同的快递费用&…

Java中Error和Exception的异同

Error&#xff08;错误&#xff09;和 Exception&#xff08;异常&#xff09;都是 java.lang.Throwable 类的子类&#xff0c;在 Java 代码中只有继承了 Throwable 类的实例才能被 throw 或者 catch。 Exception 和 Error 体现了 Java 平台设计者对不同异常情况的分类&#x…

智能计算之遗传算法(GA)介绍

目录 1. 简介 2. GA思想来源及建立过程 3. 研究发展 4. GA的基本结构 5. GA的实现流程 (1) 染色体编​辑 (2) 群体的初始化 (3) 适应值评价 (4) 选择算子(父体选择) (5) 交配算子(杂交算子) (6) 变异算子 (7) 算法流程 6. 实例举例 7. 遗传算法的改进 (1) 算子的…

sublimetext3插件安装_sublime text 3 交互python

爱折腾的我最近在用sublime text 3 写python&#xff0c;但是原生态的编译模式不支持交互。在网上找了许多资料&#xff0c;想要可以交互运行python&#xff0c;大都需要sublimeREPL这个插件&#xff0c;我不想用这个插件。在多次摸索过后找到了如下解决方案&#xff0c;在此记…

如何用手机打开dcm格式图片_压缩图片用这个神奇吧(电脑版)

一码不扫&#xff0c;可以扫天下&#xff1f;Light Image Resizer是将数码照片和图像存在电脑中&#xff0c;并希望重新调整图片大小&#xff0c;压缩&#xff0c;转换&#xff0c;创建备份&#xff0c;导入或组织图片的人们设计的完美工具。Light Image Resizer 专业的图像缩放…

智能计算之神经网络(BP)介绍

目录 1. 神经网络流行原因 2. 人工神经网络定义 3. 人工神经网络的学习能力 4. 人工神经网络的基本原理 5. 神经网络的研究进展 6. 神经网络的典型结构 6.1 单层感知器网络 6.2 前馈型网络 6.3 前馈内层互联网络 6.4 反馈型网络 6.5 全互联网络 7. 神经网络的学习算…

python系统关键字_Python基础教程 - global关键字及全局变量的用法

Python中global关键字主要作用是声明变量的作用域。 在C语言中&#xff0c;由于变量一定是先声明&#xff0c;后使用&#xff0c;所以我们可以清楚的知道&#xff0c;现在使用的变量是全局还是局部&#xff0c;比如&#xff1a; int a 5; void test(void) { a 1; // 没有先声…

如何查看keepalived版本号_Keepalived介绍 , 配置说明 , 及实际应用

1. Keepalived介绍Keepalived是一个基于VRRP协议来实现的服务高可用方案&#xff0c;可以利用其来避免IP单点故障&#xff0c;类似的工具还有heartbeat、corosync、pacemaker。但是它一般不会单独出现&#xff0c;而是与其它负载均衡技术(如lvs、haproxy、nginx)一起工作来达到…

智能计算之神经网络(Hopfield网络-DHNN,CHNN )介绍

目录 1. 神经网络受欢迎的原因 2. 人工神经网络定义 3. 人工神经网络的学习能力 4. 人工神经网络的基本原理 5. 神经网络的研究进展 6. 神经网络的典型结构 6.1 单层感知器网络 6.2 前馈型网络 6.3 前馈内层互联网络 6.4 反馈型网络 6.5 全互联网络 7. 神经网络的学…

用python画渐变的圆_使用numpy绘制圆形渐变

由于对称性&#xff0c;实际上只需要计算图像256*256的四分之一&#xff0c;即64*64&#xff0c;然后将其逐块旋转90度&#xff0c;然后将它们组合起来。这样&#xff0c;总时间是计算256256像素的1/4倍。在 以下是示例。在import numpy as np import matplotlib.pyplot as plt…

发那科程序全部输出_如何拷贝FANUC系统全部程序

在SETTING画面复I/O通道一项中设定I/O4(或者制20#参数改为4)&#xff0c;将存储卡(插在机床的面板上的PCMCIA接口里。选择编辑模式&#xff0c;程序钥匙锁打开&#xff0c;全部程序预览页面(列表)&#xff0c;点击(操作)&#xff0c;点击右扩展键&#xff0c;点击(F输出)&#…

计算平均成绩

根据用户输入的总人数和总成绩计算平均成绩。要求程序能够处理总人数或者总成绩不是数字时的情况。 使用多重 catch 语句时&#xff0c;Java 虚拟机会把实际拋出的异常对象依次和各个 catch 代码块中声明的异常类型匹配&#xff0c;如果异常对象为某个异常类型或者其子类的实例…