matlab程序通过PCA降维实现手写数字识别

手写数字特征测试数据集-Matlab文档类资源-CSDN下载

 手写数字识别的训练数据集-Matlab文档类资源-CSDN下载

  使用PCA的方式对手写数字的特征数据进行降维,一方面减小了识别过程所需要的计算量,另一方面也可以进行去噪,我作为信号处理的初学者,觉得这种方式也是信号图像处理方面很重要的一环,下面附上我的实现过程和代码。

实现PCA的过程主要有以下几个环节,可以借鉴下面这篇文章:

机器学习实战之PCA - 卑微的蜗牛 - 博客园 (cnblogs.com)

我在写作的过程中也借鉴了上面的思路,在学习PCA之前一定要对算法的数学过程进行推导,这里我简单讲一下自己的思路。

1.数据中心化

这一步相当于让数据在坐标轴上向着中心点平移,这样就可以对数据进行简单的预处理,方便后续步骤的进行,如果不做也是可以的

2.求协方差矩阵

为啥要这么做呢?这个可以通过一维数据的方差来理解,整个降维的过程就相当于是将一个二维数据向一维数据上进行投影,在投影的时候就有X,Y轴两种选择,到底投到那个轴效果更好呢,就是看那个轴的数据损失少,这里我的理解就是看投影到那个轴数据更加分散,就是数据的方差要大,产生的重合更少。所以求协方差矩阵就是为了利用协方差矩阵的特性,确定原来的高维数据要投影到那个低维空间去。

3.选取N个最大特征值的特征向量作为新的空间向量将原来的数据投影到这个N维空间去。

这样的话就实现了对数据的降维操作,然后就得到了PCA降维之后特征数据。为啥要去最大值呢?大概率就是为了让数据不会有太大的损失。就投影到这个方向上它的数据损失最小 。

function  [eigvalInd,sampling,lowDtrain]=PCA(N,train)
%input:将数据降到N维空间中,train是输入的需要进行处理的数据
%output:eigvalInd:选出的N个最大的特征值对应的特征向量
%sampling:每一组特征数据对应的手写数字
%lowDtrain:降维之后的特征数据
%该函数实现PCA降维过程
[m,p]=size(train);
F=train(:,2:p);
sampling=train(:,1);
[n,p]=size(F);%样本数n,特征数据维度p
%数据标准化或归零化,中心化
meanvals=mean(F,1);
meanremoved=F-meanvals;%每一列的特征值减去该列的特征均值,不需要考虑维度

%利用索引由小到大对特征值排序
covmat=cov(meanremoved);%求协方差矩阵

[eigvects_1,diag_eigvals]=eig(covmat);%求协方差矩阵的特征值和特征向量
[d,ind]=sort(diag(diag_eigvals));%对特征值按照由小到大的顺序排序,返回其索引ind
eigvals=diag_eigvals(ind,ind);%特征值按照由小到大的顺序排列后的对角矩阵
eigvects=eigvects_1(:,ind);%特征值对应的特征列向量排序
%判断特征向量是否归一化
% a=eigvects(1:end,1);
% S=0;
% for i=1:256
%     S=a(i,:)^2+S;
% end
%选取最大的N个特征值
eigvalInd=eigvects(:,p-N+1:p);%N个最大的特征值对应的特征列向量
% 将中心化的特征数据向选出的N个特征向量空间投影,实现数据的降维
lowDtrain=meanremoved*eigvalInd;%降维之后的特征矩阵"样本数*N个新的降维特征"
end

下面是主函数实现测试的部分

clc
clear all
% load test.mat;
load('train.mat');
N=10;
[spevect,data_train,lowDtrain]=PCA(N,train);%调用函数对训练数据进行PCA降维处理
%使用test数据集测试
%% 测试数据处理
load test.mat
[n,p]=size(test);
F=test(:,2:p);
sampling=test(:,1);%将测试数据中的值取出来方便后面进行效果比对
meanvals=mean(F,1);
meanremoved=F-meanvals;
lowDtest=meanremoved*spevect;%降维之后的测试集特征数据
%% 计算数据之间的欧氏距离对数字进行识别
k=0;m=0;
for i=1:size(test,1)
    for j=1:size(train,1)
        k=k+1;
    dist(k)=dist_E(lowDtest(i,:),lowDtrain(j,:));
    end
    [M,I]=min(dist);%调用函数计算disk数组的最小值,返回最小值和索引
    m=m+1;
    num(m,1)=train(I,1);
    k=0;
end
%% 计算识别结果的误差
A=num-sampling;
error=sum(A(:)==0)/size(A,1);%通过计算可以发现识别的精度维89.89%,下面思考如何进一步改善这种测量的误差。

最后还有在主函数中调用的一个计算欧氏距离的函数。文中使用的数据集放在文章开头,水平不高,有问题的话希望大家指正!

function dist=dist_E(x,y)
dist=[x;y];
dist=pdist(dist);%计算各行向量之间的欧氏距离
end

你可能感兴趣的:(matlab,机器学习)