brunch

You can make anything
by writing

C.S.Lewis

by 라인하트 Feb 11. 2021

머신러닝 옥타브 실습(7-4): PCA 주성분 분석

   온라인 강의 플랫폼 코세라의 창립자인 앤드류 응 (Andrew Ng) 교수는 인공지능 업계의 거장입니다. 그가 스탠퍼드 대학에서 머신 러닝 입문자에게 한 강의를 그대로 코세라 온라인 강의 (Coursera.org)에서 무료로 배울 수 있습니다. 이 강의는 머신러닝 입문자들의 필수코스입니다. 인공지능과 머신러닝을 혼자 공부하면서 자연스럽게 만나게 되는 강의입니다. 


Programming Exercise 7: 

K-means Clustering and Principal Component Analysis (K-평균 클러스터링과 주성분 분석)


2. Principal Component Analysis 

(주성분 분석)


   In this exercise, you will use principal component analysis (PCA) to perform dimensionality reduction. You will first experiment with an example 2D dataset to get intuition on how PCA works, and then use it on a bigger dataset of 5000 face image dataset.

   The provided script, ex7 pca.m, will help you step through the first half of the exercise.


   이번 실습은 주성분 분석(PCA, Principal Component Analysis)을 사용하여 차원 감소를 수행합니다. 먼저 2D 데이터 셋에서 PCA의 동작 방식을 이해합니다. 그리고, 5,000 개의 얼굴 이미지 데이터 셋에서 PCA를 수행합니다.

   ex7_pca.m 파일은 실습의 전반부를 진행하는 데 도움을 줄 것입니다. 


2.1 Example Dataset (예제 데이터 셋)


   To help you understand how PCA works, you will first start with a 2D dataset which has one direction of large variation and one of smaller variation. The script ex7 pca.m will plot the training data (Figure 4). In this part of the exercise, you will visualize what happens when you use PCA to reduce the data from 2D to 1D. In practice, you might want to reduce data from 256 to 50 dimensions, say; but using lower dimensional data in this example allows us to visualize the algorithms better.


   PCA의 작동 방식을 이해하기 위해 먼저 큰 변화량과 더 작은 변화량을 가진 2차원 데이터셋으로 시작합니다. ex7_pca.m 파일은 학습 데이터를 그림 4와 같이 도식화합니다. 실습에서 PCA 알고리즘으로 2차원 데이터를 1차원으로 축소하고 시각화합니다. 실제로 데이터를 256차원에서 50차원으로 축소합니다. 그러나 예제에서 더 낮은 차원의 데이터를 사용하면 알고리즘을 더 잘 시각화할 수 있습니다. 



< Part 1: 예제 데이터셋 로드 >


(1) 이미지 업로드


clear ;             % 옥타브 프로그램에 모든 변수를 제거

close all;         % 터미널 이외의 창을 닫음

clc                   % 터미널을 깨끗이 정리 


load ('ex7data1.mat');


>> load ('ex7data1.mat');

>> whos

Variables in the current scope:


   Attr Name        Size                     Bytes  Class

   ==== ====        ====                     =====  =====

        X                   50x2                        800  double


Total is 100 elements using 800 bytes



(2) 데이터 도식화


plot(X(:,1), X(:,2), 'x');  % X표로 데이터를 표시


plot(X(:,1), X(:,2), 'bo');   % 파란색 원으로 데이터를 표시



axis([0.5 6.5 2 8]);  % x축과 y축을 지정



axis squre;   % 데이터를 정사각 비율로 조정




2.2 Implementing PCA


   In this part of the exercise, you will implement PCA. PCA consists of two computational steps: First, you compute the covariance matrix of the data. Then, you use Octave/MATLAB’s SVD function to compute the eigenvec- tors U1, U2, . . . , Un. These will correspond to the principal components of variation in the data.

   Before using PCA, it is important to first normalize the data by subtract- ing the mean value of each feature from the dataset, and scaling each dimen- sion so that they are in the same range. In the provided script ex7 pca.m, this normalization has been performed for you using the featureNormalize function.

   After normalizing the data, you can run PCA to compute the principal components. You task is to complete the code in pca.m to compute the prin- cipal components of the dataset. First, you should compute the covariance matrix of the data, which is given by:


where X is the data matrix with examples in rows, and m is the number of examples. Note that Σ is a n × n matrix and not the summation operator.

   After computing the covariance matrix, you can run SVD on it to compute the principal components. In Octave/MATLAB, you can run SVD with the following command: [U, S, V] = svd(Sigma), where U will contain the principal components and S will contain a diagonal matrix.


  이번 실습에서 PCA를 구현합니다. PCA는 두 단계로 구성되어 있습니다. 첫 번째 단계는 공분산 행렬을 계산합니다. 그리고, 옥타브 프로그램의 svd() 함수를 사용하여 고유 행렬 U1, U2..., Un을 계산합니다. 이것들은 데이터 변화의 주성분입니다. 

   PCA를 사용하기 전에 먼저 데이터 셋에서 각 피처의 평균값을 빼고 각 차원이 동일한 범위에 있도록 스케일 하여 데이터를 정규화합니다. ex7_pca.m 파일은 정규화를 featureNomalize.m 파일에서 수행합니다. 

   데이터를 정규화하고 PCA를 실행하여 주성분을 계산합니다. 데이터 셋의 주성분을 계산하기 위해 pca.m 파일의 코드를 완성합니다. 데이터에 대한 공분산 행렬을 계산할 때 다음의 공식을 사용합니다.


   여기 X는 행에 있는 데이터 예제가 있는 데이터 행렬이고 m은 예제의 수입니다. 시그마 (Σ)는 합산 연산자가 아니라 n X n 행렬입니다. 

   공분산 행렬을 계산하고 svd() 함수를 실행하여 주성분을 계산합니다. 옥타브/매트랩 프로그램에서 다음 코드를 사용합니다.


     [U, S, V] = svd(Sigma);


   여기서 행렬 U는 주성분이고, S는 대각 행렬입니다. 


 

   Once you have completed pca.m, the ex7 pca.m script will run PCA on the example dataset and plot the corresponding principal components found.

(Figure 5). The script will also output the top principal component (eigen- vector) found, and you should expect to see an output of about [-0.707 -0.707]. (It is possible that Octave/MATLAB may instead output the neg- ative of this, since U1 and −U1 are equally valid choices for the first principal component.)

   You should now submit your solutions.


   pca.m 파일을 완료하고 ex7_pca.m 파일은 예제 데이터 셋에서 PCA를 실행하고 주성분을 그림 5와 같이 그립니다. ex7_pca.m 파일은 발견된 주성분(고유 벡터)을 출력하여 [ -0.707 -0.707의 출력을 볼 수 있다. (U1과 -U1이 첫 번째 주 성분에 대해 똑같이 유효한 선택이므로 옥타브 / 매트랩 프로그램은 이것의 음수를 출력할 수 있습니다. 

   이제 솔루션을 제출합니다. 


< Part 2: PCA >


(1) 피처 스케일링 및 정규화 


   데이터 행렬 X를 정규화하기 위해 featureNormalize.m 파일을 사용합니다. 파일을 호출할 때  데이터 행렬 X를 전달합니다. 


[X_norm, mu, sigma] = featureNormalize(X);


   featureNormalize.m 파일은 정규화된 데이터 행렬 X_norm, 평균 mu, 표준편차 sigma를 반환합니다.


(2) featureNormalize.m 파일 분석


function [X_norm, mu, sigma] = featureNormalize(X)

%FEATURENORMALIZE 데이터 행렬 X를 정규화  

%   FEATURENORMALIZE(X) 정규화된 데이터 행렬 X를 반환

%       각 피처의 평균은 0이고, 표준 편차는 1 임

%       이것은 학습 알고리즘을 실행할 때 좋은 전처리 단계 


mu = mean(X);              % 각 피처 별로 평균을 계산

X_norm = bsxfun(@minus, X, mu);      % 각 학습 예제를 


sigma = std(X_norm);

X_norm = bsxfun(@rdivide, X_norm, sigma);



% ============================================================


end


피처 스케일링을 위한 공식은 다음과 같습니다.

평균을 계산합니다. 데이터 행렬 X는 50 X 2차원 행렬입니다. 


>> X                    % 데이터 행렬 X 

X =

   3.3816   3.3891

   4.5279   5.8542

   2.6557   4.4120

   ...


>> mu = mean(X)       % 각 열 별로 평균을 계산

mu =

   3.9893   5.0028


>> X - mu                   % 데이터 행렬 X에 mu를 뺄셈

warning: operator -: automatic broadcasting operation applied

ans =

  -0.607703  -1.613693

   0.538610   0.851372

  -1.333583  -0.590811

...


   데이터 행렬 X는 50 X 2차원이고 mu는 1 X 2차원입니다. 차원이 맞지 않기 때문에 에러가 발생합니다. 에러를 무시하고 mu 1 X 2차원을 복사하여 50 X2 차원으로 만든 후에 뺄셈을 수행합니다. bsxfun() 함수는 연산을 위해 자동으로 배열을 확장하므로 에러가 발생하지 않습니다. 따라서, bsxfun() 함수를 사용하지 않아도 되고 사용해도 됩니다. 


>> bsxfun(@minus, X, mu)

ans =

  -0.607703  -1.613693

   0.538610   0.851372

  -1.333583  -0.590811

...


>> X_norm = bsxfun(@minus, X, mu); 

X_norm =

  -0.607703  -1.613693

   0.538610   0.851372

  -1.333583  -0.590811

...



 표준 편차를 계산합니다. 


>> X_norm

X_norm =

  -0.607703  -1.613693

   0.538610   0.851372

  -1.333583  -0.590811

...


>>  sigma = std(X_norm)

sigma =

   1.1730   1.0234


>> X_norm = bsxfun(@rdivide, X_norm, sigma)

X_norm =

  -0.518054  -1.576784

   0.459154   0.831899

  -1.136851  -0.577298

...


정리하면, 정규화된 데이터 행렬 X_norm은 다음과 같이 계산합니다.


X_norm = bsxfun(@minus, X, mu); 

sigma = std(X_norm);

X_norm = bsxfun(@rdivide, X_norm, sigma);


(3) PCA를 실행


 PCA를 실행하기 위해 pca.m 파일을 호출합니다. pca.m 파일을 호출할 때  정규화된 데이터 행렬 X_norm을 전달합니다. 


[U, S] = pca(X_norm);


   pca.m 파일은 고유 행렬 U와 대각 행렬 S를 반환합니다.


(4) pca.m 파일 분석




function [U, S] = pca(X)

%PCA  데이터셋 X에 대해 주성분 분석 PCA를 실행

%   [U, S, X] = pca(X) X에 대한 공분산 행렬의 공유 벡터를 계산 

%          고유 벡터 U와 대각 행렬 S를 반환

% 변수 선언 

[m, n] = size(X);

%

% 반환할 변수를 초기화 

U = zeros(n);           % 0으로 된 2 X 2 행렬로 초기화 

S = zeros(n);            % 0으로 된 2 X 2 행렬로 초기화

%

% ====================== YOUR CODE HERE ======================

% Instructions:  

%                첫 번째 단계 : 데이터 행렬 X에 대한 공분산 행렬 계산 

%                 두 번째 단계 : svd() 함수로 고유 벡터 U와 공분산 행렬의 고윳값 S 계산

%

% Note: 공분산 행렬을 계산할 때 총 학습 예제의 수로 나눌 것





 ============================================================

end   


(5) 공분산 행렬 계산하기


   공분산 행렬 Sigma를 계산하는 공식은 다음과 같습니다. 

   공식을 벡터화 구현으로 표현하면 다음과 같습니다.


   Sigma = 1/m * X'*X


   옥타브 프로그램에서 정규화된 데이터 행렬 X_norm에 대해 실행합니다.


>>  [m, n] = size(X);

>> Sigma = 1/m * X'*X     % 데이터 행렬 X에 대한 공분산 행렬 

Sigma =

   17.263   20.823

   20.823   26.054


>> Sigma = 1/m * X_norm'*X_norm   % 정규화된 데이터 행렬 X에 대한 공분산 행렬

Signam =

   0.98000   0.72082

   0.72082   0.98000


정리하면, 공분산 행렬 Sigma는 다음과 같이 계산합니다.


[m, n] = size(X);

Sigma = 1/m * X_norm'*X_norm;


(6) 주성분이자 고유 벡터 U와 대각 행렬 S를 계산


   PCA 알고리즘을 수행하는 코드는 다음과 같습니다.


[U, S, V] = svd(Sigma);


>> [U, S, V] = svd(Sigma)

U =

  -0.70711  -0.70711

  -0.70711   0.70711


S =

Diagonal Matrix

   1.70082         0

         0   0.25918


V =

  -0.70711  -0.70711

  -0.70711   0.70711


(7) 정답


function [U, S] = pca(X)

%PCA  데이터셋 X에 대해 주성분 분석 PCA를 실행

%   [U, S, X] = pca(X) X에 대한 공분산 행렬의 공유 벡터를 계산 

%          고유 벡터 U와 대각 행렬 S를 반환

% 변수 선언 

[m, n] = size(X);

%

% 반환할 변수를 초기화 

U = zeros(n);           % 0으로 된 2 X 2 행렬로 초기화 

S = zeros(n);            % 0으로 된 2 X 2 행렬로 초기화

%

% ====================== YOUR CODE HERE ======================

% Instructions:  

%                첫 번째 단계 : 데이터 행렬 X에 대한 공분산 행렬 계산 

%                 두 번째 단계 : svd() 함수로 고유 벡터 U와 공분산 행렬의 고윳값 S 계산

%

% Note: 공분산 행렬을 계산할 때 총 학습 예제의 수로 나눌 것


Sigma = 1/m * X'*X;

[U, S, V] = svd(Sigma);


 ============================================================

end   


(8)  데이터의 중앙에 주성분인 고유 벡터 U 그리기


  PCA 알고리즘을 적용하기 위해 다음의 순서로 진행하였습니다.


1) 데이터 행렬 X를 정규화하여 X__norm을 생성

2) 정규화된 데이터 행렬 X_norm에 대한 공분산 행렬 Sigma를 생성

3) Sigma 행렬을 특이값 분해하기 위해 svd(Sigma)를 적용

4) 주성분인 고유 벡터 U와 대각 행렬 S를 반환


 여기서 공분산 행렬 Sigma를 특이값 분해를 하였을 때 반환된 3 값은 다음과 같습니다. 


>> [U, S, V] = svd(Sigma)

U =

  -0.70711  -0.70711

  -0.70711   0.70711


S =

Diagonal Matrix

   1.70082         0

         0   0.25918


V =

  -0.70711  -0.70711

  -0.70711   0.70711


   각 피처의 평균 mu는 다음과 같습니다.


>> mu

mu =

   3.9893   5.0028



   데이터셋의 최대 변화량의 방향을 보여주기 위한 직선을 그립니다. 지난 실습에서 직선을 그리기 위한 drawLine.m 파일을 작성했습니다. drawLine.m 파일은 두 개의 점 p1과 p2가 주어졌을 때 직선으로 두 점을 연결합니다.  이 파일의 핵심 코드는 다음과 같습니다.


plot([p1(1) p2(1)], [p1(2) p2(2)]);


   여기서, p1의 x축의 값 p1(1)과 p2의 x축의 값 p2(1)을 놓고, y축의 값 p1(2)과 p2(2)로 직선을 그립니다. 


  그래프는 수평축은 x1이고, 수직축은 x2입니다. 첫 번째 점 p1은 x1의 평균과 x2의 평균값으로 mu = [3.9893   5.0028]입니다. 두 번째 점 p2는 대각 행렬 S의 (1,1) 번째 성분을 주성분 행렬 U의 첫 번째 열에 값을 곱하고 1.5배 한 값을 곱한 것입니다.  


drawLine(mu, mu + 1.5 * S(1,1) * U(:,1)', '-k', 'LineWidth', 2);


   평균점을 기준으로 데이터가 퍼진 방향을 나타냅니다. 



  평균점을 기준으로 직교하여 데이터가 퍼진 방향을 나타냅니다. 


drawLine(mu, mu + 1.5 * S(2,2) * U(:,2)', '-k', 'LineWidth', 2);



두 개의 선을 같이 표시합니다. 


figure; hold on;

drawLine(mu, mu + 1.5 * S(1,1) * U(:,1)', '-k', 'LineWidth', 2);

drawLine(mu, mu + 1.5 * S(2,2) * U(:,2)', '-k', 'LineWidth', 2);

hold off;




(8) 결과 확인


기존의 데이터와 함께 코드를 정리합니다.


clear; close all; clc;


load ('ex7data1.mat');

plot(X(:, 1), X(:, 2), 'bo');

axis([0.5 6.5 2 8]); axis square;


[X_norm, mu, sigma] = featureNormalize(X);

[U, S] = pca(X_norm);


hold on;

drawLine(mu, mu + 1.5 * S(1,1) * U(:,1)', '-k', 'LineWidth', 2);

drawLine(mu, mu + 1.5 * S(2,2) * U(:,2)', '-k', 'LineWidth', 2);

hold off;






2.3 Dimensionality Reduction with PCA (차원 축소)


   After computing the principal components, you can use them to reduce the feature dimension of your dataset by projecting each example onto a lower dimensional space, x^(i) → z^(i) (e.g., projecting the data from 2D to 1D). In this part of the exercise, you will use the eigenvectors returned by PCA and project the example dataset into a 1-dimensional space.

   In practice, if you were using a learning algorithm such as linear regression or perhaps neural networks, you could now use the projected data instead of the original data. By using the projected data, you can train your model faster as there are less dimensions in the input.


   주성분을 계산한 후에 각 학습 예제를 더 낮은 차원의 공간 x^(i) → z^(i)로 투영하여 데이터 셋의 피처 차원을 축소합니다. 예를 들어, 2차원 데이터를 1차원 데이터에 투영합니다. 실습에서 PCA 알고리즘이 반환한 고유 벡터를 사용하여 데이터 셋을 1차원 공간에 투영합니다.

   시제로 선형 회귀 또는 신경망과 같은 학습 알고리즘을 사용할 때 원래 데이터 대신 투영된 데이터를 사용합니다. 투영한 데이터를 사용하면 입력의 차원이 적기 때문에 모델을 더 빠르게 훈련할 수 있습니다. 



2.3.1 Projecting the data onto the principal components

            (주 성분에 데이터 투영하기)

            (주 성분에 데이터 투영하기)


   You should now complete the code in projectData.m. Specifically, you are given a dataset X, the principal components U, and the desired number of dimensions to reduce to K. You should project each example in X onto the top K components in U. Note that the top K components in U are given by the first K columns of U, that is U reduce = U(:, 1:K).

   Once you have completed the code in projectData.m, ex7 pca.m will project the first example onto the first dimension and you should see a value of about 1.481 (or possibly -1.481, if you got −U1 instead of U1).

   You should now submit your solutions.


   이제 projectData.m 파일의 코드를 완성합니다. projectData.m 파일에 데이터 셋 X, 주성분 U 및 축소할 차원의 수 k를 제공합니다.  데이터 셋 X의 각 예제를 주성분 U의 상위 k개의 성분에 투영합니다. U의 상위 k개 성분을 제공합니다. U의 처음 k열을 선택하는 코드는 다음과 같습니다.


 Ureduce = U(:,1:k);


   projectData.m 코드를 완료하고 ex7_pca.m 이 첫 번째 예제를 첫 번째 차원에 투영하고 약 1.481 또는 -1.481의 값을 확인합니다.

   이제 솔루션을 제출합니다. 



< Part 3: 차원 축소 (상)>


(1) 정규화된 데이터 행렬 X_norm을 그리기


   데이터 행렬 X를 그린 것처럼 수평축에 피처 x1을 나열하고 수직축에 x2를 나열합니다.


plot(X_norm(:, 1), X_norm(:, 2), 'bo');

axis([-4 3 -4 3]); axis square

 



(2)  주 성분 벡터에 데이터 투영하기


  1차원 주성분 벡터 U에 데이터를 투영하기 위해 projectData.m 파일을 호출합니다. projectData.m 파일에 정규화된 데이터 행렬 X_norm, 주성분 고유 벡터 U, 축소할 차원의 크기 K를 제공합니다. 


K = 1;

Z = projectData(X_norm, U, K);


  projectData.m 파일은 계산 후에 주성분 벡터에 투영된 데이터 행렬 Z를 반환합니다. 



(3) projectData.m 파일 분석


function Z = projectData(X, U, K)

%PROJECTDATA k 고유 벡터에 데이터를 투영  

%   Z = projectData(X, U, K) computes the projection of 

%         정규화된 데이터 행렬 X

%             주성분 고유 벡터 U

%             축소할 차원의 수 K 

%             투영된 데이터 행렬 Z를 반환

%

% 반환할 투영된 데이터 행렬 Z를 초기화 

Z = zeros(size(X, 1), K);


% ====================== YOUR CODE HERE ======================

% Instructions: 주성분 U에 K 고유 벡터에 데이터를 투영

%              예를 들면, i 번째 학습 예제 X(i,:)를 k 번째 고유 벡터에 투영 코드 F

%                    x = X(i, :)';

%                    projection_k = x' * U(:, k);

%




% =============================================================

end


(4) 주성분 U에 데이터를 투영하기


   이미 PCA 분석을 설명할 때 이 부분을 설명했습니다. 주성분 U에서 K 차원까지의 열만 가져와 Ureduce 행렬을 생성합니다. 그리고, 정규화된 데이터와 내적을 계산


   Ureduce = U (:, 1:K);         % u^(1)에서 u^(k)까지의 열을 가져와 Ureduce 행렬 생성

   Z = Ureduce' * X               % z 방향으로 투영한 x^(i)의 값을 구함


>> Ureduce = U(:,1:K)

Ureduce =

  -0.70711

  -0.70711


>>   Z = Ureduce' * X

error: operator *: nonconformant arguments (op1 is 1x2, op2 is 50x2)


   Ureduce는 2X1 행렬이므로 전치하여 1X2 행렬로 만듭니다, X가 데이터 셋의 학습 예제를 하나씩 계산할 때는 Ureduce' * X가 연산이 가능합니다. 하지만, 50 X 2차원의 행렬 X를 벡터화 구현하기 위해 위치를 바꿉니다. 


Ureduce = U (:, 1:K);  

Z = X * Ureduce


>> Ureduce = U(:,1:K)

Ureduce =

  -0.70711

  -0.70711


>> Z = X * Ureduce

Z =

  -4.7876

  -7.3412

  -4.9976

...


   여기서 두 개의 코드를 하나로 합칠 수도 있습니다. 


Z = X * U(:, 1:K);


   코드의 줄을 줄이는 것이 멋진 코드이지만, 배운 대로 식을 이해하기 위해 두 줄을 선택합니다.



(5) 정답


function Z = projectData(X, U, K)

%PROJECTDATA k 고유 벡터에 데이터를 투영  

%   Z = projectData(X, U, K) computes the projection of 

%         정규화된 데이터 행렬 X

%             주성분 고유 벡터 U

%             축소할 차원의 수 K 

%             투영된 데이터 행렬 Z를 반환

%

% 반환할 투영된 데이터 행렬 Z를 초기화 

Z = zeros(size(X, 1), K);


% ====================== YOUR CODE HERE ======================

% Instructions: 주성분 U에 K 고유 벡터에 데이터를 투영

%              예를 들면, i 번째 학습 예제 X(i,:)를 k 번째 고유 벡터에 투영 코드 F

%                    x = X(i, :)';

%                    projection_k = x' * U(:, k);

%


Ureduce = U (:, 1:K);  

Z = X * Ureduce;


% =============================================================

end



(6) 결과 확인


plot(X_norm(:, 1), X_norm(:, 2), 'bo');

axis([-4 3 -4 3]); axis square;


K = 1;

Z = projectData(X_norm, U, K);






2.3.2 Reconstructing an approximation of the data

         (데이터의 근사치로 재구성)


   After projecting the data onto the lower dimensional space, you can ap- proximately recover the data by projecting them back onto the original high dimensional space. Your task is to complete recoverData.m to project each example in Z back onto the original space and return the recovered approxi- mation in X rec.

   Once you have completed the code in recoverData.m, ex7 pca.m will recover an approximation of the first example and you should see a value of about [-1.047 -1.047].

   You should now submit your solutions.


   데이터를 저차원 간에 투영한 후 고차원 공간으로 복원하면 원래 데이터의 근사깂을 얻을 수 있습니다. recoverData.m 파일을 완료하면 투영된 데이터 Z의 각 예제를 원래 공간으로 다시 복원한 근사값 X_rec로 반환합니다. 

   recoverData.m 파일의 코드를 완성하면 ex7_pca.m 파일은 첫 번째 예제의 근사치를 [-1.047, -1.047] 값을 반환합니다.

   모두 마치면 제출합니다. 



< Part 3: 차원 축소 (중)>


(1)  주 성분 벡터에 데이터 투영하기


  투영된 데이터 Z에서 원래 데이터의 근사값을 복원하기 위해 recoverData.m 파일을 호출합니다. recoverData.m 파일에 정규화된 데이터 행렬 Z, 주성분 고유 벡터 U, 축소된 차원의 크기 K를 제공합니다. 


X_rec = recoverData(Z, U, K);


   recoverData.m 파일은 원래 데이터의 근사값 행렬 X_rec를 반환합니다.  



(2) recoverData.m 파일 분석 


function X_rec = recoverData(Z, U, K)

%RECOVERDATA  투영된 데이터에서 원래 데이터의 근사값을 복원

%   X_rec = RECOVERDATA(Z, U, K) r

%      정규화된 데이터 행렬 Z, 주성분 고유 벡터 U, 축소된 차원의 크기 K 

%      원래 데이터의 근사값 행렬 X_rec를 반환 

%


% 반환할 데이터를 초기화 

X_rec = zeros(size(Z, 1), size(U, 1));


% ====================== YOUR CODE HERE ======================

% Instructions: 투영된 데이터에서 고유 벡터 U를 사용하여 원래 데이터 공간으로 복원

%

%               i번째 데이터 Z(i,:)를 j 차원의 원래 데이터 값의 근사값으로 복원할 때

%                    v = Z(i, :)';

%                    recovered_j = v' * U(j, 1:K)';

%

%               Notice : that U(j, 1:K)는 행 벡터 

%               





% =============================================================


end


(3) 근사값으로 복원하기


   투영된 데이터 Z에서 근사치 X_rec를 복원하는 공식은 다음과 같습니다.

이 공식을 옥타브 프로그램으로 그대로 옮깁니다.


Ureduce = U(:, 1:K);

X_rec = Z*Ureduce


>> U

U =

  -0.70711  -0.70711

  -0.70711   0.70711


>> Ureduce

Ureduce =

  -0.70711

  -0.70711


>> Z 

Z =

   1.4812739

  -0.9129123

   1.2120866

...


>> X_rec = Z*Ureduce

error: operator *: nonconformant arguments (op1 is 50x1, op2 is 2x1)


  투영된 행렬 Z는 50 X 1차원 행렬이고, Ureduce는  2 X1 차원 행렬입니다. 두 식을 계산하기 위해 Ureduce를 전치하여 1X2 행렬로 바꿉니다. 


X_rec = Z*Ureduce'


>> X_rec = Z*Ureduce'             % X_rec는 50 X 2 행렬

X_rec =

  -1.0474188  -1.0474188

   0.6455265   0.6455265

  -0.8570746  -0.8570746

...


   첫 번째 예제의 값은 [-1.047 -1.047]로 복원되었습니다.


정리하면,  코드는 다음과 같습니다.


Ureduce = U(:, 1:K);

X_rec = Z*Ureduce'


물론, 두 줄 코드를 한 줄로 만들 수 있지만, 배운대로  두 줄로 작성합니다.


X_rec = Z*U(:,1:K)'



(4) 정답


function X_rec = recoverData(Z, U, K)

%RECOVERDATA  투영된 데이터에서 원래 데이터의 근사값을 복원

%   X_rec = RECOVERDATA(Z, U, K) r

%      정규화된 데이터 행렬 Z, 주성분 고유 벡터 U, 축소된 차원의 크기 K 

%      원래 데이터의 근사값 행렬 X_rec를 반환 

%


% 반환할 데이터를 초기화 

X_rec = zeros(size(Z, 1), size(U, 1));


% ====================== YOUR CODE HERE ======================

% Instructions: 투영된 데이터에서 고유 벡터 U를 사용하여 원래 데이터 공간으로 복원

%

%               i번째 데이터 Z(i,:)를 j 차원의 원래 데이터 값의 근사값으로 복원할 때

%                    v = Z(i, :)';

%                    recovered_j = v' * U(j, 1:K)';

%

%               Notice : that U(j, 1:K)는 행 벡터 

%               


Ureduce = U(:, 1:K);

X_rec = Z*Ureduce';



% =============================================================


end

 


(5) 결과 확인


X_rec  = recoverData(Z, U, K);





2.3.3 Visualizing the projections




   After completing both projectData and recoverData, ex7 pca.m will now perform both the projection and approximate reconstruction to show how the projection affects the data. In Figure 6, the original data points are indicated with the blue circles, while the projected data points are indicated with the red circles. The projection effectively only retains the information in the direction given by U1.


   projectData.m와 recoverData.m 파일의 코드를 모두 작성을 한 후 ex7.m 파일은 투영한 데이터 셋과 재구성된 근사값을 그림 6과 같이 도식화합니다. 그림 6에서 원래 데이터 포인트는 파란색 원으로 표시하고, 투영된 데이터는 빨간색 원으로 표시합니다. 투영은 U1이 제공하는 방향으로만 정보를 효과적으로 유지합니다.



< Part 3: 차원 축소 (하)>


(1)  정규화된 데이터 행렬 X를 그리기


clear ; close all; clc

load ('ex7data1.mat');


[X_norm, mu, sigma] = featureNormalize(X);

[U, S] = pca(X_norm);


plot(X_norm(:, 1), X_norm(:, 2), 'bo');

axis([-4 3 -4 3]); axis square



(2) 투영된 데이터를 원래 데이터의 근사치로 복원하여 그리기


K = 1;

Z = projectData(X_norm, U, K);

X_rec  = recoverData(Z, U, K);


plot(X_rec(:, 1), X_rec(:, 2), 'ro');hold on;

axis([-4 3 -4 3]); axis square;



(3) 원래 데이터와 복원 데이터 사이에 선 그리기



for i = 1:size(X_norm, 1)

    drawLine(X_norm(i,:), X_rec(i,:), '--k', 'LineWidth', 1);

end




(4) 모든 그래프를 조합하기


close all;

plot(X_norm(:, 1), X_norm(:, 2), 'bo');

axis([-4 3 -4 3]); axis square


hold on;

plot(X_rec(:, 1), X_rec(:, 2), 'ro');hold on;


for i = 1:size(X_norm, 1)

    drawLine(X_norm(i,:), X_rec(i,:), '--k', 'LineWidth', 1);

end

hold off;



매거진의 이전글 머신러닝 옥타브 실습(7-3): K-평균으로 이미지압축
브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari