이번에 알아볼 Logistic regression은 classification에 가장 기본적으로 사용되는 방법입니다. 이전에 알아봤던 regression은 response가 연속된 실수 값을 예측할 때 사용했던 방법이고, classification이라는 것은 response가 몇 개의 class로 구성된 데이터를 분류할 경우 사용하는 방법입니다.

Logistic regression의 가장 큰 장점이라 할 수 있는 것은 바로 $X$가 주어졌을 때에 $Y$가 어떤 class $k$로 속할 확률을 구할 수 있다는 점입니다. 즉, $Pr(Y=k|X)$를 구할 수 있게 해준다는 점이죠.

좀 더 자세히 예제를 통해 알아보겠습니다.

require(ISLR)
names(Smarket) #names 함수를 통해 어떤 variable들이 있는지 파악합니다.
## [1] "Year"      "Lag1"      "Lag2"      "Lag3"      "Lag4"      "Lag5"     
## [7] "Volume"    "Today"     "Direction"
summary(Smarket) #summary는 데이터를 한 눈에 요약해주는 함수로 유용하게 사용합니다.
##       Year           Lag1                Lag2          
##  Min.   :2001   Min.   :-4.922000   Min.   :-4.922000  
##  1st Qu.:2002   1st Qu.:-0.639500   1st Qu.:-0.639500  
##  Median :2003   Median : 0.039000   Median : 0.039000  
##  Mean   :2003   Mean   : 0.003834   Mean   : 0.003919  
##  3rd Qu.:2004   3rd Qu.: 0.596750   3rd Qu.: 0.596750  
##  Max.   :2005   Max.   : 5.733000   Max.   : 5.733000  
##       Lag3                Lag4                Lag5         
##  Min.   :-4.922000   Min.   :-4.922000   Min.   :-4.92200  
##  1st Qu.:-0.640000   1st Qu.:-0.640000   1st Qu.:-0.64000  
##  Median : 0.038500   Median : 0.038500   Median : 0.03850  
##  Mean   : 0.001716   Mean   : 0.001636   Mean   : 0.00561  
##  3rd Qu.: 0.596750   3rd Qu.: 0.596750   3rd Qu.: 0.59700  
##  Max.   : 5.733000   Max.   : 5.733000   Max.   : 5.73300  
##      Volume           Today           Direction 
##  Min.   :0.3561   Min.   :-4.922000   Down:602  
##  1st Qu.:1.2574   1st Qu.:-0.639500   Up  :648  
##  Median :1.4229   Median : 0.038500             
##  Mean   :1.4783   Mean   : 0.003138             
##  3rd Qu.:1.6417   3rd Qu.: 0.596750             
##  Max.   :3.1525   Max.   : 5.733000

그럼 이 Smarket이라는 데이터셋은 무엇을 의미하는 것일까요?

  • Year는 해당 데이터가 관측된 년도를 의미합니다.
  • Lag1은 하루 전의 수익률을 나타냅니다.
  • Lag2는 이틀 전의 수익률을 나타냅니다.
  • 이렇게 Lag5까지 5일 전까지의 수익률을 가지고 있습니다.
  • Volume은 몇 주가 거래되었는지를 나타냅니다.
  • Today는 오늘의 수익률을 나타냅니다.
  • Direction은 오늘 시장이 Up인지 Down인지를 나타내는 우리가 예측하고 싶은 response입니다.

결국 우리가 하고 싶은 것은, 주식 시장에서 주식이 오를지 내릴지를 알고싶어 하는 것입니다. 이것만 잘 하면 떼돈을 벌 수 있겠죠!? ㅋㅋㅋ

#Lag1~5와 Volume의 변수를 이용하여 logistic regression model을 만듭니다.
glm.fit=glm(Direction~Lag1+Lag2+Lag3+Lag4+Lag5+Volume,
            data=Smarket,family=binomial)
summary(glm.fit)
## 
## Call:
## glm(formula = Direction ~ Lag1 + Lag2 + Lag3 + Lag4 + Lag5 + 
##     Volume, family = binomial, data = Smarket)
## 
## Deviance Residuals: 
##    Min      1Q  Median      3Q     Max  
## -1.446  -1.203   1.065   1.145   1.326  
## 
## Coefficients:
##              Estimate Std. Error z value Pr(>|z|)
## (Intercept) -0.126000   0.240736  -0.523    0.601
## Lag1        -0.073074   0.050167  -1.457    0.145
## Lag2        -0.042301   0.050086  -0.845    0.398
## Lag3         0.011085   0.049939   0.222    0.824
## Lag4         0.009359   0.049974   0.187    0.851
## Lag5         0.010313   0.049511   0.208    0.835
## Volume       0.135441   0.158360   0.855    0.392
## 
## (Dispersion parameter for binomial family taken to be 1)
## 
##     Null deviance: 1731.2  on 1249  degrees of freedom
## Residual deviance: 1727.6  on 1243  degrees of freedom
## AIC: 1741.6
## 
## Number of Fisher Scoring iterations: 3

사실 glm이라는 함수는 일반적인 linear model을 만드는데도 사용되는데, logistic regression을 하기 위해서 family=binomial을 붙여주는 것입니다. 이것이 없으면 그냥 linear regression을 하는 것이니 주의하세요!

요약된 것을 보니.. 이럴수가.. 어느 변수 하나 중요한 것이 없네요.. 이것은 무엇을 의미할까요? 결국 주식시장이 어떻게 돌아갈지는 예측할 수 없다는 슬픈 소식이네요.. 하긴 이렇게 예측하면 다들 일 떼려쳤겠죠? :) 그래도 기왕 모델을 만들었으니 성능을 알아봅시다.

glm.probs=predict(glm.fit,type="response") 
glm.probs[1:5]
##         1         2         3         4         5 
## 0.5070841 0.4814679 0.4811388 0.5152224 0.5107812

Up일지 Down일지 확률을 구하는 방법은 간단합니다. predict함수를 사용하는데, 반드시 type="response"로 설정해 주셔야 합니다. 처음 5개만 간단히 살펴보면, 0에서 1 사이의 값을 가짐을 확인할 수 있죠. 얼핏 보기에도 다 0.5 근처에 있는 것이 어느 것 하나 확실하게 분류를 할 수 없나 보네요 ^^;

그럼 이제 확률이 0.5를 넘으면 Up으로, 그것보다 낮으면 Down으로 분류해 봅시다.

glm.pred=ifelse(glm.probs>0.5,"Up","Down") #확률이 0.5보다 높으면 Up, 낮으면 Down으로 분류합니다.
attach(Smarket)
## The following objects are masked from Smarket (pos = 5):
## 
##     Direction, Lag1, Lag2, Lag3, Lag4, Lag5, Today, Volume, Year
## 
## The following objects are masked from Smarket (pos = 7):
## 
##     Direction, Lag1, Lag2, Lag3, Lag4, Lag5, Today, Volume, Year
table(glm.pred,Direction) #table명령을 통해 쉽게 대조해 볼 수 있습니다.
##         Direction
## glm.pred Down  Up
##     Down  145 141
##     Up    457 507
mean(glm.pred==Direction) #제대로 예측한 비율을 봅시다.
## [1] 0.5216

제대로 예측한 비율이 0.52정도 나오네요!! 이것만 해도 엄청난 것 아닙니까 라고 좋아하고 싶지만… 실제로는 그렇지가 않답니다. 왜냐면 이것은 training data에 대한 것이지 test data에 대한 수치가 아니기 때문입니다. 우리가 중요시 하는 것이 우리가 이미 아는 것을 잘 예측하는 것 뿐만이 아니라 앞으로 우리가 볼 데이터를 잘 예측하는 것이지 않겠습니까? 이렇게 training data에서만 높은 성능을 갖고 실제로 test data에서 성능이 나쁜 경우를 overfit되었다고 표현합니다.

그럼 이제 데이터를 둘로 나눠서 2005년 이전 데이터로 training을 하여 모델을 만들고, 그 이후의 데이터를 가지고 모델을 평가해 보겠습니다.

train = Year<2005 #2005년 이전의 데이터를 training data로
#subset을 명시해서 training data로만 model을 만듭니다.
glm.fit=glm(Direction~Lag1+Lag2+Lag3+Lag4+Lag5+Volume,
            data=Smarket,family=binomial, subset=train)
#이제 예측을 할 때 !train, 즉 test data를 가지고 예측을 해서
glm.probs=predict(glm.fit,newdata=Smarket[!train,],type="response") 
glm.pred=ifelse(glm.probs >0.5,"Up","Down")
Direction.2005=Smarket$Direction[!train]
table(glm.pred,Direction.2005) #table로 현황을 보고
##         Direction.2005
## glm.pred Down Up
##     Down   77 97
##     Up     34 44
mean(glm.pred==Direction.2005) #옳게 예측한 것의 비율을 구합니다.
## [1] 0.4801587

0.48이라.. 결국 0.5보다 낮다는 얘기는, 동전 던지기보다도 못한 처참한 결과네요… ㅠㅠ 결국 training data에서 아무리 좋은 성능을 가져도 그것 자체가 overfitting이기 때문에 test data에서까지 좋은 성능을 가지지라고 장담할 수는 없는 것입니다.

우리의 주식시장 예측은 결국 실패로 돌아갔지만, 그래도 logistic regression에 대해 배워볼 수 있었다는 수확이 있네요 ^^