건프의 소소한 개발이야기

[ML - Matlab/Octave] Linear Regression with Multiple Variables 본문

개발 이야기/Machine Learning 이야기

[ML - Matlab/Octave] Linear Regression with Multiple Variables

건강한프로그래머 2016. 4. 23. 00:14

안녕하세요, 건프입니다.


앞에서는 수많은 학습데이터들을 이용해서 패턴을 분석하는 예측함수를 구하고,

그 예측함수를 이용해서, 현실값과 가장 차이가 적게나는 계수값(세타값들)을 구해서

다음 들어올 데이터를 이용해 현실값과 가장 근접한 예측값을 뽑아내는 것을 했습니다.

(사실 이것이 Data Based Machine Learning 기법의 전부인 듯한..)


다만 한가지 맹점은, 그 학습하는 데이터의 특징(Feature)가 단 하나여야 했다는 것이죠.

데이터의 특징이 하나라는 의미는 다음과 같아요.

ex> 집값을 결정하는 요인(feature)는  '집의 크기' 뿐이다.

이럴 때, 집의 크기는 요인(feature)이고, 값 결정의 요인이 단 하나이므로 생각보다 간단하게 구해낼 수 있습니다.


하지만 이세상의 대부분의 경우는 하나의 요소로 결정되지 않겠죠.

우리는 Multiple Variables 상황에 대비해야 합니다.

오늘은 이것이 주제입니다.


예를 하나 들겠습니다.

집의 요소를 결정하는 요소가 집의 크기 뿐만 아니라, 방의 개수도 함께라고 할께요. 

1. 이를 위해서 미리 정의되어 있는 텍스트 파일을 메모리로 로드합니다.


1번째 열은 집의 크기,    => x1

2번째 열은 방의 갯수,     =>x2

3번째 열이 집의 가격(결과값) 입니다.     =>y


2. 데이터를 성격에 맞게 분리합니다.


마찬가지 원리로 y도 분리해주시면 됩니다.


근데 여기서 한가지 의문점이 생겨야 합니다. 다뤄야 할 feature가 다양해지고 많아졌을때, 원초적인 feature 간 크기간 차이가 너무 심하다는 것입니다. 집의 크기와 방의 갯수를 숫자 그대로 다루기에는 너무 불공평 하다는 의미이죠.

따라서 우리는 여기서

3. 정규화(Normalization) 을 시도합니다. 방법은 다음과 같아요.


mean 함수로 평균을 구하고,

std함수로 표준편차를 구할 수 있습니다.

size함수는 해당 매트릭스가 ? by ? 매트릭스 인지를 리턴하죠. 이를 이용해서 조사해야할 데이터의 갯수를 구할 수 있습니다.

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

% You need to set these values correctly

X_norm = X;

mu = zeros(1, size(X, 2));

sigma = zeros(1, size(X, 2));


% Instructions: First, for each feature dimension, compute the mean

%               of the feature and subtract it from the dataset,

%               storing the mean value in mu. Next, compute the 

%               standard deviation of each feature and divide

%               each feature by it's standard deviation, storing

%               the standard deviation in sigma. 

%

%               Note that X is a matrix where each column is a 

%               feature and each row is an example. You need 

%               to perform the normalization separately for 

%               each feature. 

     

mu = mean(X);

sigma = std(X);

num = size(X,1);


X_norm = (X - repmat(mu, num, 1)) ./ repmat(sigma, num, 1);


end

위는 들어온 데이터를 각각 정규화해서 리턴해줍니다.

우리가 집중할 필요가 있는 것은 위 함수안에 있는 주황색 글씨입니다.

repmat 함수는 첫번째 인자로 들어온 매트릭스를, 두번째 인자만큼 row 방향, 세번째 인자만큼 column 방향으로 반복해서 늘리는 함수입니다.


이렇게 하는 이유는 X 의 경우 47*2 매트릭스인데 mu 자체는 1*2 형태이기 때문에 (-)연산을 진행하기 위해서는 repmat을 이용해서 그 크기를 맞춰줄 필요가 있습니다. (사실 별 특별한 함수는 아니에요! 생긴게 이상해서 그렇지..)




4. Input Data(X)를 정규화 했다면, 이제 Gradient Descent 기법으로 접근해서, 최적의 계수값(세타)구할 차례입니다.

이는 Single Variable 과 논리가 같습니다.

우선

X = [ones(size(X), 1), X_norm];

으로 X 데이터의 맨앞 column을 1로 모두 깔아줍니다. 그리고

function [theta, J_history] = gradientDescentMulti(X, y, theta, alpha, num_iters)

%   GRADIENTDESCENTMULTI Performs gradient descent to learn theta

%   theta = GRADIENTDESCENTMULTI(x, y, theta, alpha, num_iters) updates theta by

%   taking num_iters gradient steps with learning rate alpha


% Initialize some useful values

m = length(y); % number of training examples

J_history = zeros(num_iters, 1);


for iter = 1:num_iters

     h = X*theta;

     theta = theta - (alpha/m) * (transpose(X) * (h-y));

    

    % Save the cost J in every iteration    

    J_history(iter) = computeCostMulti(X, y, theta);


end


end

이렇게 GradientDescent함수를 구성해주면 됩니다.

computeCostMulti함수는 사실상 computeCost 함수(single var 일때 정의하여 사용했던 함수입니다.) 와 동일하므로 생략합니다.


5. 그럼 cost함수의 변화를 표로 확인해볼까요

% Plot the convergence graph

figure;

plot(1:numel(J_history), J_history, '-b', 'LineWidth', 2);

xlabel('Number of iterations');

ylabel('Cost J');







6. 이렇게 구해낸 세타를 이용해서 예상값을 만들어냅시다



여기서 질문!

세타값을 저렇게 얻었고, 집의 크기는 1650, 방의 갯수는 3인 데이터가 들어온다면, 가격을 어떻게 예상하면 될까요??

.

.

.

.

.

.

.

.

.

.

.

.

저는 처음에 

price = 0;

predict = [1, 1650, 3];

price = predict * theta;


했다가 틀리고,

정규화를 이용하지 않았음을 깨닫고


predict = [1650, 3]

predict_norm = [1, featureNormalize(predict)];

price = predict_norm * theta;


라고 자신있게 했다가 또 엉망인 값을 만들었습니다 ㅋㅋㅋ

혹시 여러분들은 정확한 답이 무엇인지 맞추셨는지요.

정답은 다음과 같아요.

price = 0; % You should change this

predict = [1650, 3];

predict_norm = [1, (predict - mu)./sigma];

price = predict_norm* theta;


featureNormalize() 를 다시 부르는건 이미 위에서 만들어놓은 mu 와 sigma 데이터를 의미없이 만들기 때문에 불필요했습니다.

이미 구한 mu 와 sigma를 이용해서 정규화를 시도하면 되는 것이었답니다!



저도 차근차근 ML의 기본 구조에 익숙해지는 기분입니다.

여러분들에게 저의 삽질이 작은 도움이라도 되었으면 정말 행복할 것 같습니다.

Happy Coding :)

고맙습니다.

Comments