轉載地址: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');