Notice
Recent Posts
Recent Comments
Link
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Archives
Today
Total
관리 메뉴

이지훈님의 블로그

Logistic Regression 본문

ML

Logistic Regression

개발자입니다. 2017. 7. 10. 03:51

Logistic Regression < 위키피디아 >

독립 변수의 선형 결합을 이용하여 사건의 발생 가능성을 예측하는데 사용되는 통계 기법이다.

Logistic Regression은 Regression(회귀)이름이 붙어있지만 Classification문제[비가온다 vs 비가 안온다, 종양이다 vs 아니다]를 해결한다.



선형회귀를 이용해서 분류를 한다면? < 고1, 참고2 >



0.7을 기준으로 비가 온다(y = 1), 비가 오지않는다(y=0)로 구분한다고 가정하자.

[그림 1]과 같은 경우로 결과가 나왔으면 '괜찮네'라고 생각할 수 있다.

하지만 [ 그림 2 ] 와 같이 오른쪽에 특이한 녀석을 추가하여 학습하면 분류는 실패할 것이다.



                   



또한 선형회귀는 0과 1 사이의 값을 가지지 않을수도 있다. (우리가 원하는 것은 0또는 1이다.)


반면에 Logistic Regression은 0과 1사이의 값으로 제한하는 로지스틱 곡선(Sigmoid Function, Logistic Function)을 사용한다. 로지스틱 회귀는 선형회귀와 유사하지만 오즈비의 로그변환을 사용한다.



 

  


   로지스틱 곡선


   

  

x의 값에 상관없이 y는 무조건 0과 1사이의 값을 갖는다.




본격적인 Logistic Regression 설명 전에 오즈비에 대한 설명부터 하겠다.



오즈비 < 정말 잘 설명한 블로그 >


     


오즈비란 x가 한 단위 증가할 때,  y = 1일 확률과 Y = 0일 확률의 비의 증가율이다. 

조금 더 쉽게 설명하면 오즈비 =  p / 1- p 로

사건이 발생할 확률 / 사건이 발생하지 않을 확률로 표현할 수 있다.



여기서 우리가 원하는건 x의 범위는 [-∞, ∞], y의 범위는 [0. 1] 이다.

오즈비를 조금 변환해야 한다.



오즈비에 자연로그(자연상수 e를 밑으로 하는 로그)를 취한다.



(독립 변수들의 선형 결합)


이제 x의 범위는 [0,1] y의 범위는 [-∞, ∞]이다.



식을 변형하자.



역수를 취하고 p에 대한 함수로 만들어야 한다.


















Data (다운로드,  데이터셋 보기 )


아래 데이터를 분류해보자. (Income항목과 Residence Length항목은 정규화가 필요해 보인다.)



Maximum Likelihood Estimation ( 최대우도법 )

어떤 확률변수에서 표집한 값들을 토대로 그 확률변수의 모수를 구하는 방법이다. 어떤 모수가 주어졌을 때, 원하는 값들이 나올 가능도를 최대로 만드는 모수를 선택하는 방법이다. ( 'X-variable 대해 likelihood를 가장 크게 해 주는 theta를 찾는 것', )


방법은 위키피디아의 설명을 붙여넣겠다.




아래 그림에서 가능도가 최대가 되기 위해서는 Buy(1)과 같이 target이 0인 경우에는 ( 1 - target )을 해준다. 만약 ( 1 - target )을 하지 않으면 가능도는 0.1 X 0.9가 되므로 적절치 않다. 이걸 수식으로 나타내면 









Gradient Descent 


Hypothesis


 



h(x)는 hypothesis(가설)이다.

hypothesis의 의미는 우리가 원하는 y값을 예측해주는 모델이다.

머신러닝에서 Hypothesis와 Model은 종종 동일한 의미로 사용된다.






Cost Function

최대우도법을 사용하여 log함수로 만들어 주고, 양변에 -을 곱하여 최대값 문제를 최소값으로 만들어준다.

그리고 cost는 모든 데이터들로부터의 평균 비용을 구하기 때문에 1/m을 붙여준다.






Partial Derivation < 참고 >


g(z)=ddz11+ez=1(1+ez)2ez=1+ez1(1+ez)2=11+ez1(1+ez)2=11+ez(111+ez)=g(z)(1g(z)



복잡하다....





Code

이제 위의 데이터셋을 학습해보자.

처음에는 아무생각없이 했는데 알고보니까 label이 너무 불균형(imbalance)하다.

때문에 neg와 pos를 랜덤하게 25개씩 뽑아서 학습시켰다.

이런경우 다른 처리방법도 많은데.. 일단 빨리 끝내기위해 위와 같은 방법을 사용했다.

acc는 80~90사이

소스가 깔끔하지 않다는 것에 주의하자. (ㅠㅠ)

github : https://github.com/jihoonLee/Simple-MachineLearning

import os
import numpy as np
import math
import random

def sigmoid(x):
    return 1 / (1 + np.exp(-x))

def predict(x):
    if x > 0.5:
        return 1.
    else :
        return 0.

def shuffle_data(pos, neg, size):
    pos_tmp = pos[np.random.choice(pos.shape[0], size=(size,))]
    neg_tmp = neg[np.random.choice(neg.shape[0], size=(size,))]
    shuffle = np.concatenate( (pos_tmp, neg_tmp), axis=0 )
    np.random.shuffle(shuffle)
    return shuffle[:, 2:], shuffle[:, 1]

def load(path):
    train_data = []
    train_label = []

    csv = np.genfromtxt(path, delimiter=',', dtype=float, skip_header=1)
    length = csv.shape[0]
    tmp_arr = np.ones((length, 1))
    csv = np.hstack((csv, tmp_arr))
    csv[:,2] = csv[:,2]/csv[:,2].max()
    csv[:,9] = csv[:,9]/csv[:,9].max()

    pos = csv[np.where(csv[:,1]==1.)]
    neg = csv[np.where(csv[:,1]==0.)]

    for i in range(20):
        data, label = shuffle_data(pos, neg, 25)
        train_data.append(data)
        train_label.append(label)
    test_data, test_label = shuffle_data(pos, neg, 50)
    return train_data, train_label, test_data, test_label

path = os.path.dirname(os.path.abspath(__file__)) + '/KidCreative.csv'
train_data, train_label, test_data, test_label = load(path)
learning_rate = 0.00001
m, n = train_data[0].shape
weight = np.ones(n)

for i in range(100000):
    if i%1000==0 and i!=0:
        print ('iteration : %d' %(i))

    for data, label in zip(train_data, train_label):
        acc = 0.
        weight_tmp = np.zeros(n)
        for x, y in zip(data, label):
            h = sigmoid(np.dot(x, weight))
            error = (h - y)
            weight_tmp += (1./m * learning_rate * x * error)
        weight = weight - weight_tmp

acc=0.
for x, y in zip(data, label):
    h = sigmoid(np.dot(x, weight))
    error = (h - y)
    weight_tmp += (1./m * learning_rate * x * error)
    if predict(h) == y:
        acc += 1
print ('acc - %.2f' % (acc/m))


'ML' 카테고리의 다른 글

Naive Bayesian Classification (python code)  (0) 2017.07.18
Decision Tree + C4.5알고리즘  (0) 2017.07.03
Decision Tree + ID3알고리즘  (0) 2017.07.01
Linear Regression  (0) 2017.04.20
Linear Classifier  (0) 2016.07.13
Comments