[R] LDA, QDA, 나이브 베이즈로 주식 시장 예측

sunnyboy·2024년 10월 13일

Data Mining

목록 보기
3/9

지난 포스트에서 Smarket 데이터 셋의 주식 가격 상승 여부를 Logistic Regression으로 분류해 보았다.

LDA

이번에는 LDA를 이용하려고 하는데, R에서는 MASS 라이브러리의 lda() 함수를 이용하여
모형을 적합시킬 수 있다.

> library(MASS)
> lda.fit = lda(Direction ~ Lag1 + Lag2, data = Smarket.train)
> lda.fit
Call:
lda(Direction ~ Lag1 + Lag2, data = Smarket.train)

Prior probabilities of groups:
    Down       Up 
0.491984 0.508016 

Group means:
            Lag1        Lag2
Down  0.04279022  0.03389409
Up   -0.03954635 -0.03132544

Coefficients of linear discriminants:
            LD1
Lag1 -0.6420190
Lag2 -0.5135293

이제 출력 결과들을 살펴보자.

Prior probabilities of groups에 따르면 사전 확률은 π^1=\hat\pi_1= 0.49,  π^2=\ \hat\pi_2= 0.51 이라는 것을 알 수 있다.

그리고 Group means가 같이 제공되는데, 이 값은 LDA에서 μk\mu_k의 추정치로 사용되는 값이다.
이를 통해 주가가 상승한 날에는 이전 이틀간의 수익률이 음수일 가능성이 높고,
주가가 하락한 날에는 이전 이틀간의 수익률이 양수일 가능성이 높다는 것을 파악할 수 있다.

Coefficients of linear discriminants에는 선형 판별 함수의 계수를 제공한다. 따라서 선형 판별 함수는 다음과 같다.

0.6420190Lag10.5135293Lag2+C-0.6420190\cdot Lag1 - 0.5135293 \cdot Lag2 + C

predict() 함수는 세 가지 객체가 포함되어 있는데, 첫 번째 객체인 class에는 주가 변동에 대한 예측, 두 번째 객체인 posterior에는 각 관측값이 해당 클래스에 속할 사후확률, 세 번째 객체 x에는 선형 판별 함수에 관측치 X=xX=x를 넣어 계산한 결과가 포함되어 있다.

> lda.pred = predict(lda.fit, newdata = Smarket.2005)
> names(lda.pred)
[1] "class"     "posterior" "x"

LDA에서의 적중률은 약 56%로 Logistic Regression과 크게 다르지 않다.

> lda.class = lda.pred$class
> table(lda.class, Direction.2005)
         Direction.2005
lda.class Down  Up
     Down   35  35
     Up     76 106
> mean(lda.pred$class == Direction.2005)
[1] 0.5595238

QDA

이번에는 QDA를 적용해보자. 마찬가지로 MASS 라이브러리의 qda() 함수를 사용하면 된다.

> qda.fit = qda(Direction ~ Lag1 + Lag2, data = Smarket.train)
> qda.fit
Call:
qda(Direction ~ Lag1 + Lag2, data = Smarket.train)

Prior probabilities of groups:
    Down       Up 
0.491984 0.508016 

Group means:
            Lag1        Lag2
Down  0.04279022  0.03389409
Up   -0.03954635 -0.03132544

LDA와 거의 비슷하지만 출력값에 판별 함수가 포함되지 않는다.
예측의 적중률을 보면 약 60%로, 주식 시장을 정확히 예측하기 어렵다는 점을 고려하면 꽤 높은 값이다.

> qda.pred = predict(qda.fit, newdata = Smarket.2005)
> names(qda.pred)
[1] "class"     "posterior"
> mean(qda.pred$class == Direction.2005)
[1] 0.5992063

Naive Bayes

마지막으로 나이브 베이즈 모델을 적합시켜 보자. e1071 라이브러리의 naiveBayes() 함수를 사용하면 된다.

> nb.fit = naiveBayes(Direction ~ Lag1 + Lag2, data = Smarket.train)
> nb.fit

Naive Bayes Classifier for Discrete Predictors

Call:
naiveBayes.default(x = X, y = Y, laplace = laplace)

A-priori probabilities:
Y
    Down       Up 
0.491984 0.508016 

Conditional probabilities:
      Lag1
Y             [,1]     [,2]
  Down  0.04279022 1.227446
  Up   -0.03954635 1.231668

      Lag2
Y             [,1]     [,2]
  Down  0.03389409 1.239191
  Up   -0.03132544 1.220765

출력된 결과를 통해 클래스 별 각 변수의 추정된 평균과 표준편차을 알 수 있는데,
예를 들어 Direction = Down일 때 Lag1의 평균은 0.0428이고 표준편차는 1.23이다.

> nb.pred = predict(nb.fit, newdata = Smarket.2005)
> mean(nb.pred == Direction.2005)
[1] 0.5912698

나이브 베이즈의 클래스 적중률은 약 59%로, QDA보다는 약간 낮지만 LDA보다는 훨씬 더 좋은 성능이다.
여기서 predict() 함수로 각 관측값이 특정 클래스에 속할 확률, 즉 Posterior의 추정치를 생성할 수도 있다.

> nb.preds = predict(nb.fit, Smarket.2005, type = "raw")
> nb.preds[1:5, ]
          Down        Up
[1,] 0.4873164 0.5126836
[2,] 0.4762492 0.5237508
[3,] 0.4653377 0.5346623
[4,] 0.4748652 0.5251348
[5,] 0.4901890 0.5098110
profile
Data Analysis, ML, Backend 이것저것 합니다

0개의 댓글