coursera에서 진행하는 logistic regression을 구현해 보도록 하겠습니다.


logistic regression은 classification의 알고리즘이며 또한 supervisor learning입니다.

즉, 주어진 데이터를 여러형태로 분류하기 위해 사용합니다.

이전에 배운 linear regression 사용하지 못하고 새로운 접근법을 이용하여 알고리즘을 적용해야 합니다.


이번에 참고할 데이터 셋은 아래와 같이 3개로 구분되어 있습니다.

각각 x좌표, y좌표, 결과 라고 가정 할 수 있습니다.


파일이름 : ex2data1.txt


34.62365962451697,78.0246928153624,0

30.28671076822607,43.89499752400101,0

35.84740876993872,72.90219802708364,0

60.18259938620976,86.30855209546826,1

79.0327360507101,75.3443764369103,1

45.08327747668339,56.3163717815305,0

61.10666453684766,96.51142588489624,1

....



이 데이터의 1번째, 2번째를 data x로

3번째를 data y로 나눠 보겠습니다.


>> data = load('ex2data1.txt');

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

>> X = data(:, 1:n-1);

>> y = data(:, n);

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



나눠진 데이터를 각각 y 데이터를 보고 1은 positive, 0은 negative로 하여 

두 데이터를 나누어 그래프에 표시해 보겠습니다.



function plotData(X, y)

% create new chart

figure; hold on;


% find positive, negative position

pos = find(y == 1);

neg = find(y == 0);


% LineSpec is red / circle

plot(X(pos, 1), X(pos, 2), 'ro');


% LineSpec is blue / asterisk

plot(X(neg, 1), X(neg, 2), 'b*');



xlabel('x score')

ylabel('y score')


legend('positive', 'negative')


% end chart

hold off;

end



y가 1인 데이터의 인덱스를 pos에 담고, 0인 데이터의 인덱스를 neg에 담아

각각을 plot한 펑션입니다.


legend와 label를 붙여주고 실행하면 아래와 같이 그래프로 나타낼 수 있습니다.


>> plotData(X, y);


실행 하면 아래와 같은 데이터 셋으로 구성 된 것을 확인 해볼 수 있습니다.






이번에는 새터를 자동으로 구해주는 다른 알고리즘인 Stochastic Gradient descent를 알아보도록 하겠습니다.


앞서 배운 Gradient descent에 Stochastic의 접두사를 붙혀서 SGD라고 불립니다.

GD는 "batch" Gradient descent 라고도 불리며 이것은 매 이터레이션 마다 모든 트래이닝 데이터를 구해주기 때문에 계산의 코스트가 높다는 단점이 있습니다.


SGD는 위 단점을 해결하고자 Sum을 하지 않고 자동 새터를 구해주는 알고리즘 입니다.





위와 같이 SGD는 GD와 거의 동일한데 몇가지 다른 점이 있습니다.


1. 먼저 데이터를 셔플 해준다. (가장 큰 특징)

- 이유는 첫번째 부터 접근을 안하고 임의의 수 부터 접근하여 새터값을 빨리 줄이려는 이유인 것 같음. 

(적정한 수가 랜덤으로 선택되어 일정 새터값으로 수렴 되기 때문에)

2. 매 이터레이션 마다 모든 데이터를 더하는 sum of all 생략

3. m으로 나누지 않는다.



위와 같이 진행되며

매번 마다 sum을 안하기 때문에 코스트가 적게 듭니다.


코드는


function [theta, J_history] = stochasticGradientDescent(x, y, theta, alpha, iterations)


    m = length(y); % number of rows

    n = size(x, 2); % number of features


    h = zeros(n, 1);

    J_history = zeros(iterations, 1);

    

    % data shuffle

    myperm = randperm(m);

    Xshuffle = x(myperm , :);

    Yshuffle = y(myperm);


    for iter=1:iterations

        for i=1:m

            for j=1:n

                h(j) = (theta' * Xshuffle(i, :)' -  Yshuffle(i)) * Xshuffle(i, j);

            end

            for j=1:n

                theta(j) = theta(j) - alpha * h(j);

            end

        end

        % add history

        J_history(iter) = computeCostMulti(Xshuffle, Yshuffle, theta);

    end

end


위와 같이 데이터를 처음 한번 셔플해주고(row의 순서가 바뀜)

sum이 없고 m으로 나눠주는 곳도 없습니다.


위와 같이 구한것에 단항의 데이터를 이용하여 새터와 코스트 펑션을 구해보면


>>  data = load('ex1data1.txt');

>>  n = size(data, 2);

>>  x = data(:, 1:n-1);

>>  y = data(:, n);

>>  m = length(x);

>>  x = [ones(m, 1), x]; % add x0 1

>>  theta = zeros(n, 1);

>>  alpha = 0.001;

>>  iterations = 1000;

>>  [theta, J_history] = stochasticGradientDescent(x, y, theta, alpha, iterations);

>> theta

theta =


  -3.9598

   1.2511


>> computeCostMulti(x, y, theta)

ans =  4.5857




와 앞에서 구한 GD와 비슷한 것을 볼 수 있습니다.


여러번 진행해 보면 진행할 때 마다 새터값이 변경됩니다.

(랜덤으로 셔플하기 때문에 특정 구간으로 수렴하는 것 같은데 정확히 잘 모르겠네요)


일단 여기서 SGD 설명을 마치며 아직 의문이 드는 사항이 몇개 있는데 이것은 추후 공부하고 추가 하도록 하겠습니다.

(현재는 알파값은 GD보다 더 작게, iteration은 더 크게 해야 좋은 수가 나오는 것 같습니다.)




'ML > octave구현 - w1' 카테고리의 다른 글

[octave] Normal equation  (0) 2016.03.13
[octave] Multiple Variable Gradient Descent  (0) 2016.03.11
[octave] feature mean normalization  (0) 2016.03.10
[octave] multiple variable cost function  (0) 2016.03.10
[octave] 임의 값 예측  (0) 2016.03.07

이전에 새터를 자동으로 구해주는 Gradient Descent 기법을 설명하였습니다.

하지만 적정한 알파(σ) 값을 지정해 주어야 하고

iteration 크기도 정해 주어야 값이 구해집니다.

(이말은 적정한 알파와 이터레이션 크기를 안해주면 잘 나오지 않는다는 의미도 됩니다.)


그리하여 알파와 이터레이션을 정해주지 않아도 자동으로 새터를 구해주는 Normal equation 기법에 대해 알아 봅시다.




새터를 구하는 공식은 위와 같습니다.


함수로 구현하면 


function theta = normalEquation(x, y)

theta = pinv(x' * x) * x' * y;

end


이럴경우 최소 오차가 GD와 얼마나 차이가 있을지를 확인해 보겠습니다.


다항일 경우

>> data = load('ex1data2.txt');

>> n = size(data, 2);

>> x = data(:, 1:n-1);

>> y = data(:, n);

>> m = length(x);

>> [x, mu, sigma] = meanNormalization(x);

>> x = [ones(m, 1), x]; % add x0 1

>> theta = normalEquation(x, y)

ans =


  3.4041e+005

  1.1063e+005

  -6.6495e+003


cost function을 구해보면

>> computeCostMulti(x, y, theta)

ans =   2.0433e+009


이며 이전에 구한 값 

theta =


  3.4041e+005

  1.1063e+005

  -6.6493e+003


코스트 펑션은

ans =   2.0433e+009


와 비슷합니다.


단항일 경우 어떨지 다시 비교해보면


>> data = load('ex1data1.txt');

>> y = data(:, 2);

>> m = length(y);

>> x = [ones(m, 1), data(:,1)];

>> theta = zeros(2, 1);

>> theta = normalEquation(x, y)

theta =


  -3.8958

   1.1930


>>computeCost(x, y, theta)

ans =  4.4770


이전에 구한 값은

theta =


  -3.6303

   1.1664


ans =  4.4834


와 같이 비슷합니다.


NE 기법이 GD와 결과도 비슷하고 계산도 빠르다는 것을 볼 수 있습니다.


각각의 장단점은 아래 그림과 같습니다.





GD나 NE를 적절히 사용하라고 하네요.

+ Recent posts