Matlab Pca

Posted by kifish on December 1, 2017

参考:http://blog.csdn.net/jiandanjinxin/article/details/50598155

下面这个比较乱:http://blog.csdn.net/watkinsong/article/details/8234766

http://blog.csdn.net/lijihw_1022/article/details/46622667 这个链接求写协方差矩阵是X’X/(n-1).似乎两种做法:/n或者/n-1都有看到过,可能类似总体std和样本std的关系吧.我觉得应该使用/(n-1)

https://www.cnblogs.com/sweetyu/p/5085798.html

http://blog.jobbole.com/86905/ 散点图比较

http://blog.sina.com.cn/s/blog_61b8694b0101jg4f.html 测试数据

MATLAB直接用样本实现主成分分析用有多种方式,但是mathwork公司推荐(1)式,因为princomp在使用时调用的是pca,两者的计算结果一样,而且pca多一项explain,更强大。 [coeff,score,latent,tsquared,explained]= pca(X) (1) [COEFF,SCORE,latent,tsquare] = princomp(X) (2)

[coef,score,latent,t2] = princomp(x);(个人观点):

princomp/pca 会自动对数据进行减去均值的归一化.

x:为要输入的n维原始数据。带入这个matlab自带函数,将会生成新的n维加工后的数据(即score)。此数据与之前的n维原始数据一一对应。

score:生成的n维加工后的数据存在score里。它是对原始数据进行的分析,进而在新的坐标系下获得的数据。他将这n维数据按贡献率由大到小排列。(即在改变坐标系的情况下,又对n维数据排序)

latent:(协方差特征值而已,大小对应了方差,也就是所贡献的信息量大小)是一维列向量,每一个数据是对应score里相应维的贡献率,因为数据有n维所以列向量有n个数据。由大到小排列(因为score也是按贡献率由大到小排列)。

coef:是系数矩阵。通过cofe可以知道x是怎样转换成score的。

则模型为从原始数据出发: score= bsxfun(@minus,x,mean(x,1)) * coef; (作用:可以把测试数据通过此方法转变为新的坐标系) 逆变换: x= bsxfun(@plus,score*inv(coef),mean(x,1))

score实际上就是原始数据经过pca变换后(降维)的数据,可以直接拿来用. 实际上pca是可逆的,也就是说只要记录了coef(如果初始做归一化了还需要mean),即可以逆变换. 这个逆变换之后的数据,相当于对于原始数据做了滤波.

matlab里面的pca默认会做减去均值的预处理,我动手实现了pca,可以选择不做减去均值的预处理。

变量名命名有点混乱。有空再改吧。

main.m

 %input
rawdata = transpose(input);
mean_data = mean(rawdata);
th = 95;%%这里th可以改
flag= 0;
%%flag=1,代表预处理减去mean
%flag=0 则不减去mean
FiltedData = PCA_Filter_Noise(rawdata,th,flag);
if flag==1
    FiltedData = ones(size(FiltedData,1),1)*mean_data+FiltedData;
end
FiltedData = FiltedData';

PCA_Filter_Noise.m

%% 尝试用PCA去除发射电流噪声
% PCA 原始数据建立
% RawData:m*n维,样本数m,样本维度为n
%   行向量为一个样本包含的各分量,1*n
%   列向量为样本中某个变量的多次观测值
function [ FiltedData] = PCA_Filter_Noise(RawData,th,flag)
     [TransData,Principal_Componentvec,mean] = PCA_Reduce_Dimension(RawData,th,flag);
     ReconstructedData = TransData*Principal_Componentvec';
     FiltedData = ReconstructedData;          
end

PCA_Reduce_Dimension.m

% PCA  降低原始数据的维度 原始数据建立
% Normalized_Data:m*n维,样本数m,样本维度为n
%   行向量为一个样本包含的各分量,1*n,各分量的量刚应该一致
%   列向量为样本中某个变量的多次观测值

function [ TransData,Principal_Componentvec,mean] = PCA_Reduce_Dimension(data,threshold,flag)
    if (0<=threshold)&&(threshold<=100)
        threshold = threshold/100;
    else
        error('阈值输入错误!');
    end
    if flag ==1
        [EigenVector,Score,EigenValue,Tsquared,RatioOfEigenValue,mean] = pca(data);
        sum_RatioOfEigenValue = cumsum(RatioOfEigenValue./100);
    else
        [ EigenVector,Score,EigenValue,sum_RatioOfEigenValue,mean ] = pca2(data);
    end
    id_EigenValue = find(sum_RatioOfEigenValue >= threshold);

    NumComponents = id_EigenValue(1);%从最大的特征值开始选取,id_EigenValue(1)是所需选取的最后一个特征值的编号
    Principal_EigenValue = EigenValue(1:NumComponents);
    Principal_Componentvec = EigenVector(:,1:NumComponents);% 列向量为特征向量
%     % 输出所有特征值和特征向量
%     fprintf('特征值: %f \n')
%     disp(EigenValue);
%     fprintf('各特征值的贡献率: %f \n')
%     disp(RatioOfEigenValue);
%     fprintf('特征向量: %f \n')
%     disp(EigenVector);
%     % 输出满足条件的主分量和对应的特征值和特征向量
%     fprintf('方差累计贡献率: %f \n');
%     disp(sum_RatioOfEigenValue);
%     fprintf('方差累计贡献率大于 %f的特征值为: %f \n');
%     disp(threshold);disp(Principal_EigenValue);
%      fprintf('方差累计贡献率大于 %f的特征向量为: %f \n');
%      disp(threshold);disp(Principal_Componentvec);

    %RestructedData = Normalized_Data*Principal_Component;只有这里的
    %Normalized_Data做了减去均值的归一化(应该做),上下两行的结果才一致
    TransData = Score(:,1:NumComponents);
end

pca2.m

function [ eigVect,Score,lambda,sum_ratio,meanValue ] = pca2(data)
%
meanValue = mean(data);
%方法1 C = cov(data)
%方法2
%normData = data- repmat(meanValue,[size(data,1),1]);    %
%中心化样本矩阵,测试如果不做中心化,有什么影响,那么score肯定和做了中心化求出score有不同
%实际上pca默认做了中心化
normData = data;
CovMat = (normData'*normData)/(size(normData,1)-1);
[eigVect,eigVal] = eig(CovMat);%求取特征值和特征向量
lambda = eigVal(eigVal~=0);
[lambda,idx] = sort(lambda,'descend');
eigVect = eigVect(:,idx);
sum_lambda = sum(lambda);
lambda_ratio = lambda/sum_lambda;
sum_ratio = cumsum(lambda_ratio);
Score = normData *eigVect;
end

test.m

testdata = [7 26 6 60;
1 29 15 52;
11 56 8 20;
11 31 8 47;
7 52 6 33;
11 55 9 22;
3 71 17 6;
1 31 22 44;
2 54 18 22;
21 47 4 26;
1 40 23 34;
11 66 9 12;
10 68 8 12];
[EigenVector,score,latent,tsquare] = pca(testdata ); %调用pca分析函数
[ eigVect,Score,lambda,sum_ratio,meanValue ] = pca2(testdata);