轉載地址:http://blog.csdn.net/watkinsong/article/details/38536463
1. 前言
PCA : principal component analysis ( 主成分分析)
最近發現我的一篇關於PCA算法總結以及個人理解的博客的訪問量比較高, 剛好目前又重新學習了一下PCA (主成分分析) 降維算法, 所以打算把目前掌握的做個全面的整理總結, 能夠對有需要的人有幫助。 自己再看自己寫的那個關於PCA的博客, 發現還是比較混亂的, 希望這里能過做好整理。 本文的所有總結參考了Andrew Ng的PCA教程, 有興趣的可以自己學習。
上一篇關於PCA 的博客: http://blog.csdn.net/watkinsong/article/details/8234766, 在這篇博客中,有關於我最初在讀研的時候關於PCA的認識, 但是不是很系統, 然后里面卻給出了很多我總結的網絡上的資料, 以及根據我個人使用的經驗總結的感悟, 所以還是收到了很多的好評, o(∩∩)o...哈哈, 謝謝各位的支持。
@copyright by watkins.song ^_^
2. PCA的應用范圍
PCA的應用范圍有:
1. 數據壓縮
1.1 數據壓縮或者數據降維首先能夠減少內存或者硬盤的使用, 如果內存不足或者計算的時候出現內存溢出等問題, 就需要使用PCA獲取低維度的樣本特征。
1.2 其次, 數據降維能夠加快機器學習的速度。
2. 數據可視化
在很多情況下, 可能我們需要查看樣本特征, 但是高維度的特征根本無法觀察, 這個時候我們可以將樣本的特征降維到2D或者3D, 也就是將樣本的特征維數降到2個特征或者3個特征, 這樣我們就可以采用可視化觀察數據。
3. PCA原理簡介
3.1 基礎入門
這里我只給出在需要使用PCA的時候需要了解的最基本的PCA的原理, 了解這些原理后對於正常的使用沒有問題, 如果想要深入了解PCA, 需要學習一些矩陣分析的知識, 更加詳細的PCA算法請見wikipedia。
首先, 我們定義樣本和特征, 假定有 m 個樣本, 每個樣本有 n 個特征, 可以如下表示:

由簡到難, 先看一下從2D 降維到1D的比較直觀的表示:

在上圖中, 假設只有兩個特征x1, x2, 然后需要降維到1D, 這個時候我們可以觀察途中X所表示的樣本點基本上分布在一條直線上, 那么就可以將所有的用(x1, x2)平面表示的坐標映射到圖像畫出的直線z上, 上圖中的黑色鉛筆線表示樣本點映射的過程。
映射到直線Z后, 如果只用直線Z表示樣本的空間分布, 就可以用1個坐標表示每個樣本了, 這樣就將2D的特征降維到1D的特征。 同樣的道理, 如果將3D的特征降維到2D, 就是將具有3D特征的樣本從一個三維空間中映射到二維空間。

在上圖中, 將所有的二維特征的樣本點映射到了一維直線上, 這樣, 從上圖中可以看出在映射的過程中存在映射誤差。
在上圖中, 用圓圈表示了樣本映射后的坐標位置。這些位置可以叫做近似位置, 以后還要用到這些位置計算映射誤差。
因為在降維映射的過程中, 存在映射誤差, 所有在對高維特征降維之前, 需要做特征歸一化(feature normalization), 這個歸一化操作包括: (1) feature scaling (讓所有的特征擁有相似的尺度, 要不然一個特征特別小, 一個特征特別大會影響降維的效果) (2) zero mean normalization (零均值歸一化)。
在上圖中, 也可以把降維的過程看作找到一個或者多個向量u1, u2, ...., un, 使得這些向量構成一個新的向量空間(需要學習矩陣分析哦), 然后把需要降維的樣本映射到這個新的樣本空間上。
對於2D -> 1D 的降維過程, 可以理解為找到一個向量u1, u1表示了一個方向, 然后將所有的樣本映射到這個方向上, 其實, 一個向量也可以表示一個樣本空間。
對於3D -> 2D 的降維過程, 可以理解為找到兩個向量u1, u2, (u1, u2) 這兩個向量定義了一個新的特征空間, 然后將原樣本空間的樣本映射到新的樣本空間。
對於n-D -> k-D 的降維過程, 可以理解為找到 k 個向量 u1, u2, ..., uk, 這k個向量定義了新的向量空間, 然后進行樣本映射。
3.2 Cost Function
既然樣本映射存在誤差, 就需要計算每次映射的誤差大小。 采用以下公式計算誤差大小:
X-approx表示的是樣本映射以后的新的坐標, 這個坐標如果位置如果用當前的樣本空間表示, 維度和 樣本X是一致的。
要特別注意, PCA降維和linear regression是不一樣的, 雖然看上去很一致, 但是linear regression的cost function的計算是樣本上線垂直的到擬合線的距離, 而PCA的cost function 是樣本點到擬合線的垂直距離。 差別如下圖所示:

3.3 PCA 計算過程
(A) Feature Normalization
function [X_norm, mu, sigma] = featureNormalize(X) %FEATURENORMALIZE Normalizes the features in X % FEATURENORMALIZE(X) returns a normalized version of X where % the mean value of each feature is 0 and the standard deviation % is 1. This is often a good preprocessing step to do when % working with learning algorithms. mu = mean(X); X_norm = bsxfun(@minus, X, mu); sigma = std(X_norm); X_norm = bsxfun(@rdivide, X_norm, sigma); end
(B) 計算降維矩陣
3.4 貢獻率 (降維的k的值的選擇)
在 http://blog.csdn.net/watkinsong/article/details/8234766 這篇文章中, 很多人問了關於貢獻率的問題, 這就是相當於選擇k的值的大小。 也就是選擇降維矩陣 U 中的特征向量的個數。
%% Initialization
clear ; close all; clc
fprintf('this code will load 12 images and do PCA for each face.\n');
fprintf('10 images are used to train PCA and the other 2 images are used to test PCA.\n');
m = 4000; % number of samples
trainset = zeros(m, 32 * 32); % image size is : 32 * 32
for i = 1 : m
img = imread(strcat('./img/', int2str(i), '.bmp'));
img = double(img);
trainset(i, :) = img(:);
end
%% before training PCA, do feature normalization
mu = mean(trainset);
trainset_norm = bsxfun(@minus, trainset, mu);
sigma = std(trainset_norm);
trainset_norm = bsxfun(@rdivide, trainset_norm, sigma);
%% we could save the mean face mu to take a look the mean face
imwrite(uint8(reshape(mu, 32, 32)), 'meanface.bmp');
fprintf('mean face saved. paused\n');
pause;
%% compute reduce matrix
X = trainset_norm; % just for convience
[m, n] = size(X);
U = zeros(n);
S = zeros(n);
Cov = 1 / m * X' * X;
[U, S, V] = svd(Cov);
fprintf('compute cov done.\n');
%% save eigen face
for i = 1:10
ef = U(:, i)';
img = ef;
minVal = min(img);
img = img - minVal;
max_val = max(abs(img));
img = img / max_val;
img = reshape(img, 32, 32);
imwrite(img, strcat('eigenface', int2str(i), '.bmp'));
end
fprintf('eigen face saved, paused.\n');
pause;
%% dimension reduction
k = 100; % reduce to 100 dimension
test = zeros(10, 32 * 32);
for i = 4001:4010
img = imread(strcat('./img/', int2str(i), '.bmp'));
img = double(img);
test(i - 4000, :) = img(:);
end
% test set need to do normalization
test = bsxfun(@minus, test, mu);
% reduction
Uk = U(:, 1:k);
Z = test * Uk;
fprintf('reduce done.\n');
%% reconstruction
%% for the test set images, we only minus the mean face,
% so in the reconstruct process, we need add the mean face back
Xp = Z * Uk';
% show reconstructed face
for i = 1:5
face = Xp(i, :) + mu;
face = reshape((face), 32, 32);
imwrite(uint8(face), strcat('./reconstruct/', int2str(4000 + i), '.bmp'));
end
%% for the train set reconstruction, we minus the mean face and divide by standard deviation during the train
% so in the reconstruction process, we need to multiby standard deviation first,
% and then add the mean face back
trainset_re = trainset_norm * Uk; % reduction
trainset_re = trainset_re * Uk'; % reconstruction
for i = 1:5
train = trainset_re(i, :);
train = train .* sigma;
train = train + mu;
train = reshape(train, 32, 32);
imwrite(uint8(train), strcat('./reconstruct/', int2str(i), 'train.bmp'));
end
fprintf('job done.\n');
