热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

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

北京|高性能计算之GPUCUDA课程11月24-26日3天密集学习快速带你晋级阅读全文刘凯欣,中国矿业大学在校学生,曾参加过ThoughtWorks举

北京 | 高性能计算之GPU CUDA课程11月24-26日3天密集学习 快速带你晋级阅读全文>


刘凯欣,中国矿业大学在校学生,曾参加过ThoughtWorks举办的结对编程活动。


今天看了用主成分分析简化数据,就顺便用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] &#61;&#61; 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维的一维数组&#xff0c;变成我们想看的图片就需要把它reshape成28x28的二维数组&#xff0c;然后再用Image里的方法&#xff0c;把它拼成一张2x5的大图。


由于tensorflow中MNIST都是灰度图&#xff08;L&#xff09;&#xff0c;所以shape是&#xff08;55000&#xff0c;784&#xff09;&#xff0c;每张图的dtype是float32&#xff0c;如果是彩色图&#xff08;RGB&#xff09;&#xff0c;shape可能是&#xff08;55000&#xff0c;784&#xff0c;3&#xff09;&#xff0c;图的dtype是uint8&#xff0c;从array转到Image需要用下面的方法&#xff1a;


def array_to_img(array):    array&#61;array*255    new_img&#61;Image.fromarray(array.astype(np.uint8))    return new_img


拼图


def comb_imgs(origin_imgs, col, row, each_width, each_height, new_type):    new_img &#61; Image.new(new_type, (col* each_width, row* each_height))    for i in range(len(origin_imgs)):        each_img &#61; array_to_img(np.array(origin_imgs[i]).reshape(each_width, each_width))        # 第二个参数为每次粘贴起始点的横纵坐标。在本例中&#xff0c;分别为&#xff08;0&#xff0c;0&#xff09;&#xff08;28&#xff0c;0&#xff09;&#xff08;28*2&#xff0c;0&#xff09;依次类推&#xff0c;第二行是&#xff08;0&#xff0c;28&#xff09;&#xff08;28&#xff0c;28&#xff09;&#xff0c;&#xff08;28*2&#xff0c;28&#xff09;类推        new_img.paste(each_img, ((i % col) * each_width, (i / col) * each_width))    returnnew_img


效果图


ten_origin_7_imgs&#61;comb_imgs(origin_7_imgs, 10, 10, 28, 28, &#39;L&#39;) ten_origin_7_imgs.show()



数字7原图


实现主成分分析算法&#xff08;详细代码解析在文章后面的原理部分&#xff09;


def pca(data_mat, top_n_feat&#61;99999999):  
"""    
主成分分析&#xff1a;    
输入&#xff1a;矩阵data_mat &#xff0c;其中该矩阵中存储训练数据&#xff0c;每一行为一条训练数据         保留前n个特征top_n_feat&#xff0c;默认全保留  
返回&#xff1a;降维后的数据集和原始数据被重构后的矩阵&#xff08;即降维后反变换回矩阵&#xff09;  

"""    
# 获取数据条数和每条的维数  
num_data,dim &#61; data_mat.shape  
print(num_data)  # 100  
print(dim)   # 784  
# 数据中心化&#xff0c;即指变量减去它的均值  
mean_vals &#61; data_mat.mean(axis&#61;0)  #shape:(784,)  
mean_removed &#61; data_mat - mean_vals # shape:(100, 784)  
# 计算协方差矩阵&#xff08;Find covariance matrix&#xff09;  
cov_mat &#61; np.cov(mean_removed, rowvar&#61;0) # shape&#xff1a;(784, 784)  
# 计算特征值(Find eigenvalues and eigenvectors)  
eig_vals, eig_vects &#61; linalg.eig(mat(cov_mat)) # 计算特征值和特征向量&#xff0c;shape分别为&#xff08;784&#xff0c;&#xff09;和(784, 784)  
eig_val_index &#61; argsort(eig_vals)  # 对特征值进行从小到大排序&#xff0c;argsort返回的是索引&#xff0c;即下标 eig_val_index &#61; eig_val_index[:-(top_n_feat &#43; 1) : -1] # 最大的前top_n_feat个特征的索引  
# 取前top_n_feat个特征后重构的特征向量矩阵reorganize eig vects,  
# shape为(784, top_n_feat)&#xff0c;top_n_feat最大为特征总数  
reg_eig_vects &#61; eig_vects[:, eig_val_index]  
# 将数据转到新空间  
low_d_data_mat &#61; mean_removed * reg_eig_vects # shape: (100, top_n_feat), top_n_feat最大为特征总数  
recon_mat &#61; (low_d_data_mat * reg_eig_vects.T) &#43; mean_vals # 根据前几个特征向量重构回去的矩阵&#xff0c;shape:(100, 784)

 return low_d_data_mat, recon_mat


调用PCA进行降维


low_d_feat_for_7_imgs, recon_mat_for_7_imgs &#61; 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 &#61; comb_imgs(recon_mat_for_7_imgs, 10, 10, 28, 28, &#39;L&#39;) low_d_img.show()



数字7降维后的图


主成分分析效果是什么



降维前后对比图


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


主成分分析的原理是什么


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


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


统计学中的几个概念


平均值


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


标准差


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


方差


标准差的平方。


方差


协方差


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



协方差


从公式可以看出协方差的一些性质&#xff1a;
1、cov(X, X) &#61; var(X)
2、cov(X,Y) &#61; cov(Y, X)


协方差矩阵


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



协方差矩阵


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



三维协方差矩阵


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


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


结合代码分析原理


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


 # 数据中心化&#xff0c;即指变量减去它的均值  mean_vals &#61; data_mat.mean(axis&#61;0)  #shape:(784,)  mean_removed &#61; data_mat - mean_vals # shape:(100, 784)  # 计算协方差矩阵&#xff08;Find covariance matrix&#xff09;  cov_mat &#61; np.cov(mean_removed, rowvar&#61;0)


协方差矩阵需要计算平均值&#xff0c;上面强调了计算的是不同维度的协方差&#xff0c;数据每行是一个样本&#xff0c;每列是一个维度&#xff0c;因此计算的是列的平均值&#xff0c;即axis&#61;0&#xff0c;因此shape为&#xff08;784&#xff0c;&#xff09;。使用np的cov函数计算协方差矩阵&#xff0c;api入下&#xff1a;


numpy.cov(m, y&#61;None, rowvar&#61;True, bias&#61;False, ddof&#61;None, fweights&#61;None, aweights&#61;None)[source]


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


** eig_vals, eig_vects &#61; linalg.eig(mat(cov_mat)) # 计算特征值和特征向量


  • mat(cov_mat)&#xff1a;将输入转成矩阵。和matrix&#xff0c;asmatrix不同&#xff0c;如果输入已经是举着嗯或者ndarray&#xff0c;它不会制作副本。相当于matrix(data, copy&#61;False)
    详细API请点这里&#xff08;https://docs.scipy.org/doc/numpy/reference/generated/numpy.mat.html&#xff09;

  • linalg.eig(a)&#xff1a;计算特征值和特征向量
    详细API请点这里&#xff08;https://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.eig.html&#xff09;


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


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


numpy.argsort(a, axis&#61;-1, kind&#61;&#39;quicksort&#39;, order&#61;None)
详细API请点这里&#xff08;https://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html&#xff09;


eig_val_index &#61; eig_val_index[:-(top_n_feat &#43; 1) : -1] # 最大的前top_n_feat个特征的索引 reg_eig_vects &#61; eig_vects[:, eig_val_index]


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


[:, eig_val_index]代表第一维不变&#xff0c;第二维要eig_val_index个&#xff0c;所以它的shape是&#xff08;784&#xff0c;top_n_feat&#xff09;


# 将数据转到新空间  low_d_data_mat &#61; mean_removed * reg_eig_vects # shape: (100, top_n_feat), top_n_feat最大为特征总数  recon_mat &#61; (low_d_data_mat * reg_eig_vects.T) &#43; mean_vals # 根据前几个特征向量重构回去的矩阵&#xff0c;shape:(100, 784)


一个shape是&#xff08;100&#xff0c;784&#xff09;的矩阵&#xff0c;乘以一个shape是&#xff08;784&#xff0c;top_n_feat&#xff09;的矩阵&#xff0c;最后得到降维的矩阵&#xff08;100&#xff0c; top_n_feat&#xff09;

recon_mat再将矩阵变回&#xff08;100&#xff0c;784&#xff09;&#xff0c;得到降维后再重构的矩阵。


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


优点&#xff1a;降低数据的复杂性&#xff0c;识别最重要的特征


缺点&#xff1a;不一定需要&#xff0c;且可能损失有用信息


适用数据类型&#xff1a;数值型数据


原文链接&#xff1a;http://www.jianshu.com/p/b9f2c92dfeaa

查阅更为简洁方便的分类文章以及最新的课程、产品信息&#xff0c;请移步至全新呈现的“LeadAI学院官网”&#xff1a;

www.leadai.org


请关注人工智能LeadAI公众号&#xff0c;查看更多专业文章


大家都在看

LSTM模型在问答系统中的应用

基于TensorFlow的神经网络解决用户流失概览问题

最全常见算法工程师面试题目整理&#xff08;一&#xff09;

最全常见算法工程师面试题目整理&#xff08;二&#xff09;

TensorFlow从1到2 | 第三章 深度学习革命的开端&#xff1a;卷积神经网络

装饰器 | Python高级编程

今天不如来复习下Python基础


点击“阅读原文”直接打开【北京站 | GPU CUDA 进阶课程】报名链接




推荐阅读
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 浅析python实现布隆过滤器及Redis中的缓存穿透原理_python
    本文带你了解了位图的实现,布隆过滤器的原理及Python中的使用,以及布隆过滤器如何应对Redis中的缓存穿透,相信你对布隆过滤 ... [详细]
  • Python函数的高级用法[python基础]
    Python的函数也是一种值:所有函数都是function对象,这意味着可以把函数本身赋值给变量,就像把整数、浮点数、列表、元组赋值给变量一样;同样可以使用函数作为函数的形参,也可 ... [详细]
  • 如何在 Python 列表中添加元素 [Python 基础]
    本文介绍了 Python 中常用的三种方法来向列表中添加元素:`append()`、`extend()` 和 `insert()`。这些方法分别适用于不同的场景,帮助开发者灵活地管理列表数据。 ... [详细]
  • 本文介绍了如何在Python中使用插值方法将不同分辨率的数据统一到相同的分辨率。 ... [详细]
  • 机器学习算法:SVM(支持向量机)
    SVM算法(SupportVectorMachine,支持向量机)的核心思想有2点:1、如果数据线性可分,那么基于最大间隔的方式来确定超平面,以确保全局最优, ... [详细]
  • 本文节选自《NLTK基础教程——用NLTK和Python库构建机器学习应用》一书的第1章第1.2节,作者Nitin Hardeniya。本文将带领读者快速了解Python的基础知识,为后续的机器学习应用打下坚实的基础。 ... [详细]
  • 本文介绍如何使用OpenCV和线性支持向量机(SVM)模型来开发一个简单的人脸识别系统,特别关注在只有一个用户数据集时的处理方法。 ... [详细]
  • 本文探讨了 TypeScript 中泛型的重要性和应用场景,通过多个实例详细解析了泛型如何提升代码的复用性和类型安全性。 ... [详细]
  • 使用Tkinter构建51Ape无损音乐爬虫UI
    本文介绍了如何使用Python的内置模块Tkinter来构建一个简单的用户界面,用于爬取51Ape网站上的无损音乐百度云链接。虽然Tkinter入门相对简单,但在实际开发过程中由于文档不足可能会带来一些不便。 ... [详细]
  • 本文介绍了如何使用Python爬取妙笔阁小说网仙侠系列中所有小说的信息,并将其保存为TXT和CSV格式。主要内容包括如何构造请求头以避免被网站封禁,以及如何利用XPath解析HTML并提取所需信息。 ... [详细]
  • Cookie学习小结
    Cookie学习小结 ... [详细]
  • 本文详细介绍了如何在PHP中记录和管理行为日志,包括ThinkPHP框架中的日志记录方法、日志的用途、实现原理以及相关配置。 ... [详细]
  • 本题主要考察二维数组的遍历和重塑。通过将二维数组降为一维,再根据新的行数和列数重新构建矩阵。 ... [详细]
  • 探讨Redis的最佳应用场景
    本文将深入探讨Redis在不同场景下的最佳应用,包括其优势和适用范围。 ... [详细]
author-avatar
手机用户2602884633
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有