정의

- K개의 fold를 만들어서 진행하는 교차검증


사용 이유

- 총 데이터 갯수가 적은 데이터 셋에 대하여 정확도를 향상시킬수 있음

- 이는 기존에 Training / Validation / Test 세 개의 집단으로 분류하는 것보다, Training과 Test로만 분류할 때 학습 데이터 셋이 더 많기 때문

- 데이터 수가 적은데 검증과 테스트에 데이터를 더 뺐기면 underfitting 등 성능이 미달되는 모델이 학습됨




과정 

- 기존 과정과 같이 Training Set과 Test Set을 나눈다

- Training을 K개의 fold로 나눈다 

- 위는 5개의 Fold로 나눴을때 모습이다

- 한 개의 Fold에 있는 데이터를 다시 K개로 쪼갠다음, K-1개는 Training Data, 마지막 한개는 Validation Data set으로 지정한다

- 모델을 생성하고 예측을 진행하여, 이에 대한 에러값을 추출한다

- 다음 Fold에서는 Validation셋을 바꿔서 지정하고, 이전 Fold에서 Validatoin 역할을 했던 Set은 다시 Training set으로 활용한다

- 이를 K번 반복한다




과정(이어서)
- 각각의 Fold의 시도에서 기록된 Error를 바탕(에러들의 평균)으로 최적의 모델(조건)을 찾는다
- 해당 모델(조건)을 바탕으로 전체 Training set의 학습을 진행한다
- 해당 모델을 처음에 분할하였던 Test set을 활용하여 평가한다

단점
- 그냥 Training set / Test set 을 통해 진행하는 일반적인 학습법에 비해 시간 소요가 크다


LSTM은 RNN에서 파생된 것으로, 순차적인 입력 데이터간 간격이 커도 좋은 성과를 보여주는 것을 특징으로 한다.

이는 RNN이 가지는 Long-term dependency 문제점을 LSTM은 가지고 있지 않기 떄문이다. 해당 문제점은 예측에 필요한 정보와 정보간 간격이 클때 그 예측 능력이 현저하게 감소하는 것을 뜻한다. 

보편적으로, 대부분의 경우에 LSTM은 RNN보다 좋은 퍼포먼스를 보여주는 경향을 가진다.


다만 RNN역시 신경망의 한 종류이기 때문에, 그 과정에 있어서 설명력이 떨어진다는 단점을 가진다.

하지만 우리는 어떤 순서에 의하여 가격 예측을 하는지 그 과정이 필요한 것은 아니기 때문에, LSTM을 선택하기로 하였다.


LSTM의 자세한 수학적 원리는 웹의 여러 매체에 소개되어 있으며, 해당 포스팅에서는 간단하게 작동 원리만

설명하면 아래와 같다.



첫번째 인픗으로 일차 예측을 진행하고, 그 다음 인풋과 기존 인풋을 바탕으로 한 예측값을 조합하여 다시 재예측을 진행한다.

이런식으로 n번째 인풋값 전 n-1번까지의 인풋값을 통해 낸 예측결과는 n번째 인풋을 활용한 예측값에 영향을 주는 것이다.


해당 과정을 계속해서 진행하여 최종 아웃풋을 산출한다.


*딥러닝 부분을 구현하는 것에 있어서 어려움이 있었기 때문에, 도움을 받았음을 알려드립니다.



우리는 예측 모델을 통해 raio(상승/하락 비율)을 예측했고, 그 예측 결과인 비율에 해당 시간의 close(종가)를 곱해주게 되면 예측 가격이 나오게 된다.

칼럼에 대해 설명하자면 2015-03-13 15:00을 기준으로 6시간 뒤는 2015년 3월 13일 21:00, 그 뒤는 14일 03:00 .. 이 되는 것이다.

따라서 칼럼에서 실제 24시간 뒤가 다음 칼럼에서 여섯시간 뒤와 동일한 것을 발견할 수 있다.


따라서 우리는 각 시간대별로 6시간, 12시간, 18시간, 24시간 예측값에 대한 오차율을 구할 수 있으며, 오차율의 절대값 평균은 아래와 같다.


즉 시간이 지날수록 오차율이 높아지는 것을 발견할 수 있다.

사실 일반적인 에측에서 정확도 98퍼센트면 매우 높다고 생각할수도 있으나 트레이딩의 특성상

1퍼센트~2퍼센트의 차이가 큰 돈의 이익과 손실을 불러올 수 있다는 점에서 부족할 수 있다는 생각 역시 든다.


 

특히나 급격한 하락장(패닉셀 등)이 발생할때는 예측치가 크게 어긋나는 모습을 보였는데, 물론 평균치로 보면 크게 문제가 없지만

순간 순간의 오차율이 큰 손실을 불러올 수 있다는 점에서 보완이 필요하다는 생각이 들었다.


 

전처리는 거의 다 끝났고, 이제 학습 데이터와 테스트 데이터로 나눠보도록 하겠다.

비율은 보통 자율적으로 선택하지만 보편적으로 0.7~0.75사이로 학습데이터를, 그 나머지를 테스트 데이터로 부여하게 된다.


코드는 아래와 같다.


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
31
32
33
import numpy as np
import math
import csv
##train set : 3125개 , test: 1041개
= open("./20개씩묶고_컬럼별정규화.csv"'r', newline='')
rdr = csv.reader(f)
 
data = []
for j, i in enumerate(rdr):
    if(j!=0): #label 제외하고 읽어옴.
        data.append(i)
np.random.shuffle(data)
 
ratio = 0.75
count = int(math.ceil(len(data)*ratio))
print(len(data), count)
train = data[:count]
test = data[count:]
 
o1 = open("./trainset.csv"'w', newline='')
wr1 = csv.writer(o1)
for i in train:
    wr1.writerow(i)
 
o2 = open("./testset.csv"'w', newline='')
wr2 = csv.writer(o2)
for i in test:
    wr2.writerow(i)
 
f.close()
o1.close()
o2.close()
'''
cs


해당 코드를 실행시 4163개의 Train data, 3123개의 Test data로 나눠진 것을 확인할 수 있다.




저번 포스팅에 이어서 전처리를 마무리해보도록 하겠다.

코딩 전 엑셀로 정리를 해준 부분은 다음과 같다 


null 값이 들어있는 행을 모두 삭제하며, 그 전 보조지표로 추가했던 sma120을 삭제한다.

null값을 삭제하는 이유는 해당 데이터들이 있으면 제대로된 학습이 되지 않기 때문이며, sma120을 삭제하는 이유는 해당 지표를 변수로 쓰려면 

처음 119개 행들이 null값으로 출력되기 때문에 지나치게 데이터의 갯수가 줄어들기 때문이다. 


따라서 아래와 같이 정리해주게 된다.


정리를 해준 후, 각 행별로 타겟을 추가해주기 위한 코딩을 진행해준다. 

여기서 타겟은 해당 칼럼 기준으로 6, 12, 18, 24시간 뒤 가격을 타겟으로 쓰기 위해 해당 행에 맞게 칼럼을 추가해준다.

이해가 가지 않는다면 아래 그림을 보면 된다.


즉 우리는 low ~ signal까지의 칼럼으로 target 6, 12, 18, 24 칼럼을 예측하는 모델을 만드려 하는 것이다.


해당 과정을 진행하는 코드는 아래와 같다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import csv
 
#하루 4개씩 있어야됨, 6시간봉
= open("./중복제거최종데이터_전처리전.csv"'r', newline='')
rdr = csv.reader(f)
= open("./타겟추가데이터2_새로운방식.csv"'w', newline='')
wr = csv.writer(o)
wr.writerow(['time','low''high','open','close','volume','sma5','sma20''sma120''ema12','ema26','dn','mavg','up','pctB','rsi14','macd','signal','target_after6','target_after12','target_after18','target_after24']) # 필터 자리 놔둠
 
queue = []
for j,i in enumerate(rdr): #i는 행 값 (날짜부터 지표 다 포함)
    if(j!=0): #label 제외하고 읽어옴.
        queue.append(i) 
        if(j>4): #
            data = queue.pop(0# 1차원배열 
            data.append(queue[0][4])  # append 해서 옆쪽으로 붙인다 
            data.append(queue[1][4]) #4는 close 자리 
            data.append(queue[2][4]) 
            data.append(queue[3][4])
            wr.writerow(data)
 
 
f.close()
o.close()
cs


if문 안쪽 4번 칼럼은 close자리이고,  data.append(queue[0][4]) ~  data.append(queue[3][4]) 는 6시간~24시간을 뜻히는 것을 알 수 있다.

코드에서 볼 수 있는 것처럼 사이즈 4의 큐를 이용하여, 큐의 특성인 FIFO를 이용하여 순서에 맞게 종가를 새 칼럼으로 append 하였다. 




오늘은 Rattle을 사용한 기계학습을 통한 알고리즘을 구현해볼 것이다.

말은 복잡하지만 지금까지 라이브러리를 통해 구현한 SVM, neuralnet, decision tree 등 다양한 학습 알고리즘을

GUI로 작동하는 프로그램으로 구현하는 것이다.



rattle 패키지를 설치하고 실행한다.



요런 창이 뜬다. 상당히 직관적이여서 쉽게 사용할 수 있지만 간단히 몇가지 실습을 진행해 보겠다.

오늘 실습할 데이터는 KNN 구현때 사용했던 유방암 진단 데이터를 사용할 것이다 (클릭시 이동).



cancer 데이터는 이런식으로 되어있는데, 숫자의 편차가 크기때문에 정규화를 진행해 보도록 하겠다.



정규화할 칼럼을 선택한 후, 위에 실행을 눌러준다 



스크롤을 내려보면 R01_로 시작하는 정규화된 칼럼들이 추가되었을 것이다. 이제 정규화 된 칼럼들을 제외한 나머지 칼럼들을

삭제해보도록 하자. 위에 클린업을 체크하고 실행을 눌러준다. 



아래와 같은 메세지가 뜬다면 성공이다.


이제 이렇게 전처리된 데이터를 활용하여 의사결정트리를 만들어 보겠다.

방법은 아래와 같다. 



실행을 누른 후, 오른쪽 Draw를 누르면 R스튜디오 플럿 창에 아래와 같은 그림이 나온다.

.


의사결정트리에 대해 알고싶다면 이전 포스팅 으로 가보자.



이렇게 의사결정트리 구현을 마무리 하였으면, 이 결과를 평가하고 csv파일로 저장할 것이다.


전체 에러 4.7%로 비교적 준수한 결과를 보여주고 있다.



Score 선택후 실행을 눌러서 CSV파일을 저장할 수 있다.



CSV파일을 열어보면 왼쪽이 진짜 진단결과고, 오른쪽이 의사결정트리를 통한 예측 결과인 것을 알 수 있다.


이를 응용하여 SVM, neuralnet 등 다양한 알고리즘을 구현할 수 있다.

참고로 Log를 보면 구현 결과를 R언어로 다시 한번 볼 수 있으니 참고해도 좋다.





오늘은 R로 상품추천기술중 하나인 IBCF와 UBCF를 구현해 보겠다.



sample.csv


샘플데이터는 아래와 같이 생겼다.



데이터에 대하여 간단히 설명하면, V1과 V2, 그리고 V3는 각각 사용자식별번호, 아이템번호, 구매 횟수를 뜻한다.

즉 이미 전처리가 어느정도 완료되어 있는 데이터를 바탕으로, 우리는 사용자 베이스 추천, 아이템 베이스 추천을 진행하도록 하겠다. 


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
##########################################
## 온라인 유통회사의 추천 시스템 사례 ####
##########################################
## step.1 preparing the data #####
 
# 데이터 로딩
data<-read.csv("sample.csv",head=FALSE, sep =",")
View(data)
 
# 추천시스템 패키지를 인스톨
install.packages("recommenderlab")
 
 
# 패키지를 로딩
library(recommenderlab)
 
 
# 데이터형을 realRatingMatrix로 변환
<-as(data, "realRatingMatrix")
 #바이너리는 산 횟수가 0 1 (샀다 안샀다) 리얼레이팅은 진짜 횟수 (0~) 
cs


우리가 사용할 패키지는 recommenderlab 이며, 없다면 설치하도록 하자.

아래 행의 realRatingMatrix 는 진짜 횟수에 대한 것으로, 우리는 V3칼럼에서 볼 수 있는 것처럼 샀는지 안샀는지의 유무가 아닌

얼마나 구매했는지를 바탕으로 모델을 만들어야 하기 때문에 realRatingMatrix를 사용한다.


binary 일 경우네는 쉽게 이야기해 더미 변수처럼 1 0 으로 샀냐 안샀냐만 구분해주는 것이다.


1
2
3
4
5
6
7
8
9
10
## Step.2 Training a model on the data ###
 
# 머신러닝을 위해 학습데이터선정
# 전체데이터의 90%를 학습데이터로 선정
trainingData<- sample(4945,4500#(4950개중 4500개 추출 )
trainingSet<- r[trainingData]
 
# 행의 총합 5개 이상의 아이템만 선택, 많이 팔리지 않은 아이템을 제외시킴
trainingSet<-trainingSet[rowCounts(trainingSet) > 5#아이템이 적은것은 왜곡된 추천결과 보내줄수 있음 
as(trainingSet,"matrix")  
cs


이제 모델을 생성하기 위한 작업을 해보자.

코드에서 볼 수 있는 것처럼 트레이닝셋과 테스트셋을 구분하기 위하여 추출을 해주는데, 이 과정에서 구매 횟수가 5보다 낮은것은

제외하도록 한다. 그 이유는 구매가 적으면 아웃라이어처럼 결과에 왜곡을 줄 수 있기 때문이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# scheme 지정과 표시
# 추천의 평가방식을 저장 
# split은 분할, crosss는 교차검정 
# train 은 모델만드는 데이터 비율로서 아래 코드는 이를 80%로, 나머지 20%를 평가셋으로 한 것을 의미
# given 은 사람당 평가하는 아이템 수 
# K는 시뮬레이션 반복횟수
scheme <- evaluationScheme(trainingSet,method="split", train = .8,
                           given = 6
                           goodRating = 4,
                           k = 3)
    #추천의 평가방식을 지정하고 저장 - 중요하다
    #교차검정(crosstable) - 전체 데이셋을 k개로 나눈다 
    # train - 모델을 만드는 데이터 비율 - 위 코드는 80퍼로 만듬
    # given 은 사람당 평가하는 아이템 수 
    # goodrating = 실제 사용 등급이 4이상이면 모두 평가에 포함 
    # 시뮬레이션 실행할때마다 결과가 바뀜 - 너무많이 돌리면 개선이 덜 되고, 적게돌리면  편차 큼 
cs


위는 상품추천기술의 핵심 함수라고 할 수 있는 evaluationScheme 함수이다. 설명은 주석을 참고하면 된다.

.




위는 또다른 핵심 함수인 Recommender에 대한 설명이다. 여기서 우리는 UBCF 와 IBCF를 구분해서 각각 모델을 생성하게 된ㄷ.

파라미터로는 cosine와 pearson 두 가지가 있으며, 선택해주면 된다.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 추천모델생성
mUBCF <- Recommender(trainingSet,method="UBCF",
                     parameter="Cosine")
 
mUBCF
 
mIBCF <- Recommender(trainingSet,method="IBCF",
                     parameter="Cosine")
 
mIBCF
 
# 추천을 받을 사용자리스트 (Testset)
recommenderUserList<-r[-trainingData] # 트레이닝데이터 반대되는 행들을 테스트셋으로 
 #트레이닝셋을 쓰지않고 데이터를 쓰는 이유는 이미 4500명에 대한 
 #트레이닝데이터를 만들었기 때문에 445명에 대한 테스트셋을 만들위해 추천리스트 다시 설정 
 
cs


위와 같이 코딩을 해주면 되고, 아래 -trainingData는 아까 설정한 트레이닝데이터를 제외한 나머지를 테스트 데이터로 사용하겠다는 뜻이다.



상품추천기술은 개인화 기술이라고 불리며 그 핵심 기술인 협업 필터링은 아래와 같은 특징을 가진다


협업필터링(Collaborative filtering) 

  • 공동여과기법 
  • 기호가 유사한 다른 사람이 좋아하는 상품을 추천하는 기법 
  • 자동화된 구전효과


글로만 보면 잘 이해가 안될텐데, 아래 사진을 같이 보자.



아래는 새로운 고객인 10번 고객과 기존 고객들간의 유사도를 계산하여 선호도를 계산하는 과정이다.

표에 있는 검은색 숫자가 기존에 유자10이 가지고 있던 선호도이고, 빨갠색 글자가 기존 고객과 비교를 통해

유사한 고객들과의 연관성을 바탕으로 예상되는 추천도를 계산한 것이다.


이 때 사용되는 계산법이 피어슨스 계수(Parson correlation coefficient) 이다.



이런식으로 특정 유저 두 명간 상관관계(유사도)를 피어슨스 계수를 통해 측정하는데,

이 때 나타난 그래프의 기울기가 1에 가까울수록 유사하다고 할 수 있우며, 최저는 당연히 0이다.


이러한 협업 필터링은 다시 두 가지로 분류할 수 있다.


유저 기반(UBCF)

  • 해당 유저와 취향이(성향) 비슷한 유저가 좋게 평가한 것을 추천 

  • 더 정교함

  • 유저가 신규 진입할때마다 계산해야 해서 구현에 시간이 더 걸린다

상품 기반(IBCF)

  • 상품간 유사도 바탕

  • 신규 진입할때마다 계산할 필요가 없음(미리 계산해놓을수 있음) 


UBCF를 그림으로 표시해보면 아래와 같다.





이 때 중요한건 수치가 중요한게 아니고, 그래프의 모양이 비슷해야 유사도가 높다는 것이다.

즉 유저 1과 Alice는 점수의 절대치에 있어서는 유사도를 찾기 힘들지만, 그 패턴은 동일하기 때문에 (유저1을 위로 2점씩 끌어올리면 Alice와 겹친다) 유사하다고 판단할수 있다.



이론상으로 유저들간 유사도를 계산하는 공식은 위와 같은데, 엑셀을 사용하면 비교적 쉽게 할 수 있다.




위 유사도를 구한 결과에서 상위 두 개의 유저를 선택하여(이 경우에는 U1, U2) 이 둘이 평가한 것을 바탕으로 Alice가 U5를 어떻게 평가할지 

그 추정치를 구하는 공식은 위와 같다. 

즉 우리는 UBCF기법을 사용하면 Alice가 아이템 5의 평가를 4.87로 할 것이라는걸 추측할 수 있다. 



다음은 IBCF를 알아보도록 하자. 아래 그림을 참고하면 된다.


IBCF는 코사인 유사도를 바탕으로 그 유사도를 계산한다. 


마찬가지로 엑셀로 유사도를 계산하도록 한다.


위와 같은 추천시스템의 평가지표로는 아래와 같은 지표들이 있다.


정확도(precision, accuracy) 

사용자가 실제 선택한 아이템 수  / 전체 측정된 아이템 수 


재현율(recall) 

맞는 추천 아이템 수 / 사용자가 선택한 전체 아이템 수 


F측정치 (F measure) 

(2*정확도*재현율) / (정확도 + 재현율) 


범위(coverage)

추천이 가능한 사용자 수(or 아이템 수) / 전체 사용자 수 (or 아이템 수) 





오늘은 저번 포스팅에서 설명하였던 SVM 을 구현할 예정이다.

테스트 데이터셋은 아래 링크에서 받을 수 있다.



https://archive.ics.uci.edu/ml/datasets/letter+recognition


데이터셋의 변수를 확인해보자.





변수마다 뭘 뜻하는지는 정확히 모르겠고, 여튼 글자 모양(좌표)에 대한 변수라고 생각하면 되겠다.
즉 letters마다 좌표, 넓이 등이 다르다는 것에 착안하여 모델을 만들고, 새롭게 들어오는 데이터들을 성공적으로 분류하는 것을 목표로 한다 

코드는 아래와 같다.


1
2
3
4
5
6
7
8
9
10
## step.1 preparing the data #####
# 데이터 읽기와 구조 확인
letters<-read.csv("letter.csv")
str(letters) #상형문자의 특징들 
 
summary(letters) #최대최소값이 비슷하기 때문에 굳이 정규화 필요 없다 
 
# Training (80%)와 Test(20%) 나누기
letters_train<-letters[1:16000,]
letters_test<-letters[16001:20000,]
cs


특징을 확인하고 학습용과 검증용 데이터로 나눈다. 



1
2
3
4
5
6
## Step 2: Training a model on the data ----
# 단순 선형 SVM을 훈련으로 시작
install.packages("kernlb")
library(kernlab)
letters_classfier<-ksvm(letter~. , data = letters_train, 
                        kernel="vanilladot"# 선형커널 
cs

우리가 사용할 라이브러리는 "kernlab" 라는 라이브러리다.

분류 모델을 만드는 핵심 함수는 ksvm함수인데, 설명은 아래와 같다.




우리의 경우는 letters를 예측할거고, 예측에 사용하는 데이터 프레임 속성은 전부 다 사용하니깐 .로 표시한다.

data 에는 학습용 데이터를 써주고, 사용할 kernel 종류는 vaniladot 을 사용하기로 한다.

여러 kernel 타입이 있는데, 목적에 맞게 선택하여 모델을 만들면 된다.



1
2
3
4
## Step 3: Evaluating model performance ----
# 테스트 데이터셋에 대한 예측
letter_predictions<-predict(letters_classfier,letters_test)
#response - 예측된 범주 인지, probabilities - 예측된 확률인지  / 안쓰면 response 
cs

그 후 predict 함수를 사용하여 예측을 하게 된다. 

해당 함수는 predict(사용할 모델, 예측하고싶은 데이터셋, response or probabilities) 를 사용하면 된다

여기서 response는 예측된 범주일 경우, probailities 는 확률일 경우 사용한다.

우리는 알파벳의 확률 예측이 아니고 범주를 나누는 것이니 response를 사용하기로 하는데, 디폴트 값이 response여서 따로 써줄필요는 없다.


1
2
3
4
# 테스트 데이터 셋 문자와 예측된 문자 비교
View(table(letter_predictions,letters_test$letter))
 
 
cs
이렇게 View 와 table명령어를 사용하면, 예측값과 진짜 검증 데이터의 letter 컬럼이 얼마나 일치하는지 확인해볼 수 있다.



이런식으로 예측값이 인데 진짜 letters컬럼 값이 A일 경우, B일 경우, C일 경우.. 이런식으로 쭉 확인할 수 있다.
하지만 이럴경우 가독성이 떨어지고, 직관성이 떨어지기 때문에 아래 코드를 통해 간단하게 정확도를 확인 할 수 있다. 

1
2
3
4
5
6
7
8
9
10
# look only at agreement vs. non-agreement
# 일치/불일치 예측을 표시하는 TRUE/FALSE 벡터 생성
agreement<-letter_predictions == letters_test$letter
 
# 4000개 중 레코드 어떻게 나오는 지 식별
table(agreement) ## 3357개 정확히 식별 / 643개 틀리게 식별 
 
# agreement실행결과 
FALSE  TRUE 
  643  3357 
cs

 

즉 우리는 3357개를 정확히 식별했고, 643개를 잘못 식별했음을 알 수 있다.




SVM 에 대해 좀 더 자세한 설명을 원하신다면 해당 포스팅 에서 보실 수 있습니다


서포트 벡터 머신은 2차원에서 머무르는 것이 아닌, 3차원 등 차원을 높여서 데이터를 나누는 과정을 뜻한다

즉 고차원에서 데이터를 분류할 수 있는 일종의 칸막이를 만드는 것이다.


이를 좀 더 정확히 설명하면


SVM

 데이터에 있는 특성들을 kernel 함수를 이용하여 입체공간에 데이터를 분류할 수 있는 *판을 만들어 주는 것 

 *판 = 초평면(Hyperplane) 


SVM 의 목표

 Maximum margin hyperplane 을 찾는 것, 즉 마진을 최대화하는 초평면을 찾는 것 


이제 마진은 뭔지, 맥시멈 마진은 어떻게 찾는지 알아보도록 하자.




다시 한번 용어를 정리해보면


Hyperlane 초평면

- 데이터들을 분류할 수 있는 칸막이


Support vectors 서포트 벡터

- 초평면에서 가장 가까운 데이터들  


Margin 마진

- 양쪽 Support vectors와 hyperplane 간의 거리의 합 


이해가 잘 가지 않으면, 그림을 보면 직관적으로 알 수 있다.


즉 서포트 벡터들의 거리인 마진의 최대치 (Maximum margin)을 찾는 것이 서포트 벡터 머신의 목표이며

이 마진의 최대치를 보여주는 초평면이 최종 초평면이 되는 것이다. 


서포트 벡터 머신의 장단점은 아래와 같다.


장점

1.     분류문제나 예측문제 동시에 쓸 수 있다.

2.     신경망 기법에 비해서 과적합 정도가 덜하다.

3.     예측의 정확도가 높음.

4.     사용하기 쉽다

 

단점

1.     Kernel과 모델 파라미터를 조절하기 위한 테스트를 여러 번 해봐야 최적화된 모형을 만들 수 있다.

2.     모형 구축 시간이 오래걸린다

3.     결과에 대한 설명력이 떨어진다


이번 포스팅에선 변수에 따라 콘크리트 강도를 예측하는 모델을 신경망을 통해서 만들어 보겠다.

샘플 데이터는 아래 링크에서 다운로드할 수 있다.


https://archive.ics.uci.edu/ml/datasets/Concrete+Compressive+Strength




총 1030개의 데이터가 있으며, cement ~ age등의 정도에 따른 콘크르티의 strength 변수의 예측 모델을 만드는 것이 목표이다.



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
## step.1 preparing the data #####
# 데이터 읽기와 구조 확인
concrete <- read.csv("concrete.csv",stringsAsFactors = TRUE)
str(concrete) # 신경망은 정규화를 해줘야 한다 
 
View(concrete)
#  정규화 함수
normalize<-function(x){
  return ((x-min(x))/(max(x)-min(x)))
}
 
# 전체 데이터 프레임에 정규화 적용
concrete_norm<-as.data.frame(lapply(concrete,normalize))
 
 
# 0과1 사이에 범위 확인
summary(concrete_norm$strength)
 
# 본래 데이터의 최소값, 최대값 비교
summary(concrete$strength)
 
# 훈련과 테스트 데이터 생성
concrete_train<-concrete_norm[1:773,]
concrete_test<-concrete_norm[774:1030,]
View(concrete_test)
cs


위는 데이터 전처리 과정에 대한 코드이다.


우선 csv를 불러오고, str로 살펴본 결과 데이터가 퍼져 있으며로 정규화 함수를 이용하여 정규화를 진행한다 

(KNN 구현 포스팅에 더 자세히 있다).


lapply 함수는 lapply(적용하고싶은 대상 변수, 적용할 함수) 식으로 구성하면 된다.

이렇게 정규화를 끝냈으면 이를 다시 7대 3으로 훈련용 데이터와 테스트 데이터로 분류한다


1
2
3
4
5
6
7
8
9
10
## Step 2: Training a model on the data ----
# neuralnet 모델 훈련
#install.packages("neuralnet")
library(neuralnet)
 
# 하나의 은닉 뉴런에 대한 단순한 ANN
concrete_model<- neuralnet(strength ~ 
                             cement + slag  + ash + water + superplastic + coarseagg +fineagg + age,
                           data = concrete_train)
 
cs


오늘 사용할 라이브러리는 neuralnet 라이브러리를 사용할 것이다.


neuralnet에서 신경망을 통한 모델 생성 역할을 담당하고 있는 라이브러리는 "neuralnet" 함수이다

(라이브러리 이름과 동일하다)

neuralnet 함수의 구성은 아래와 같다.



좀 더 자세히 설명하면,


neuralnet 함수의 제일 앞부분에는 target 변수(예측 하고싶은 변수 - 우리의 경우는 strength 이다) 

predictors 부분에는 위 타겟변수를 예측하는데 활용할 변수들을 쓴다


구분 기호는 위 예시처럼 +를 사용하면 되며, 다시 예를들어 neuralnet(A ~ B + C + D) 라고 한다면, 

A 변수를 B, C, D를 조합하여 예측한다는 것이다.


data 는 학습용 데이터 셋을 써주면 되고, hidden은 몇 개의 은닉층을 가질 것이냐에 대한 것이다.

(이 역시 이전 포스팅에 더 자세히 나와있다)


1
2
3
4
5
6
7
8
9
# 망(network) 시각화
plot(concrete_model)
 
## Step 3: Evaluating model performance ----
# 모델 결과
model_results<-compute(concrete_model, concrete_test[1:8]) #9는 예측값 
 
# 강도값 예측
predicted_strength<-model_results$net.result #예측값을 봐야하기때문에 net.result
cs


망 시각화를 해보고싶다면 plot 함수를 사용할 수 있지만, 어차피 봐도 모른다.


compute는 모델을 평가하는데 쓰이는 함수로, compte(평가에 사용할 모델,이 모델을 활용하여 분석할 변수들(cement ~ age))로 사용가능하다.

이렇게 결과를 model_results 변수에 담고, 이를 마지막으로 평가하기 위해서 net.result를 활용하여 예측된 강도값을 담는다


참고로 net.result 값 (예측된 strength 값들은 다음과 같다) 


이걸 수동으로 진짜 값과 맞는지 대조해볼수는 없는 노릇이다.

따라서 아래와 같이 예측값에 대한 평균적인 상관계수를 구할수 있다. 


1
2
3
4
# 예측값과 실제값간의 상관 관계 확인
# 결과 값이 다양하게 측정됨(매번 다르게 측정)
cor(predicted_strength,concrete_test$strength)
  #1에 가까울수록 좋다 
cs




즉 오늘 우리가 만든 모델은 0.8 (80퍼)의 상관계수를 가진다.





신경망 이론의 좀 더 자세한 설명 및 파이선 구현 코드는 이곳을 클릭하세요


암상자 기법은 오른쪽 그림처럼 다양하게 섞여 있는 데이터들 사이에서 분류선을 잘 만들어 주는 기법이다.

하지만 '암상자'에서 알 수 있는 것처럼, 해당 알고리즘엔 큰 단점이 있는데 그 과정을 설명하기 애매하다는 것이다.


이 예시로는 추후에 포스팅할 SVM과 신경망 등이 포함되며, 해당 기법들은 예측 정확도는 높지만

그 결과 도출을 위한 과정을 설명하기 애매해다는 단점이 있다.


우선, 암상자 기법중 하나인 신경망 이론에 대하여 알아보자.


신경망은 크게 입력 - 은닉 - 출력층으로 나누어진다. 


이 때 입력층에서 출력층으로 가며 데이터마다 가중치를 부여해, 출력층에서 최적의 예측값을 낸다는게 목표인데,

해당 과정은 다음과 같다.


은닉층에서 연산을 거쳐서 출력값을 나오게 하는 것임. 즉 선마다 가중치가 있어서 이에 따라 분석 – 

신경망은 가중치를 결정하는 것 


Feed-forward  / Back-propagation Neural net  - 출력된 값을 보고 정답하고 다르면 역전파(가중치를 뒤로 조정하면서) 최적화된 가중치를 만들어 낸다 


이 때 은닉층은 자유롭게 결정할 수 있는데, 우리가 진행하고 있는 비즈니스 애널리틱스에서는 보통 3계층의 형태를 많이 사용한다. 

그 이유는 해당 은닉층으로도 충분히 분석이 가능하기 때문이다.

위 사진은 해당 노드가 어떻게 가중치를 적용하여 인풋을 받고, 이를 다시 다음 노드로 보내주는지 설명하고 있다.


이를 활성화 함수 라고 하는데, 이 활성화 함수는 


활성화 함수 (Activation function)

-       Combination function(결합함수)

모든 인풋들을 하나의 value로 합침

가중치를 거친 합

                        A lot of flexibility in the choice of combination functions


-       Transfer function(전이함수)  



로 설명할 수 있다.


즉 결합함수 부분은 가중치를 적용하여 들어온 input value들을 하나로 합치고,

전이함수는 이렇게 합친 value를 다음 노드로 전송하는 역할을 담당한다.



시그모이드 함수는 input value를 0~1사이로 보정한다


이 때 전이함수는 해당 값을 보정하여 전송하기도 하는데, 이러한 함수들에는 시그모이드, 가우시안 함수 등이 있다. 




위에서 볼 수 있는 것처럼, 가중치를 적용하여 그 값을 계산하고, 이렇게 합친 값을 시그모이드 함수로 

보정하여 다음 노드로 전송하는 것을 알 수 있다.


.

이러한 신경망 기법의 장단점은 아래와 같다.


장점

  • 신경망은 범주도 나눌 수 있고 특정한 값을 예측할 수 있다 ‘(Numeric prediction 가능)

  • 복잡한 패턴임에도 불구하고 모형 만들 수 있음

  • 데이터에 대한 가정을 거의 하지 않는다  - 어차피 데이터 패턴을 외우는 것이기 때문

  • 분류나 예측 결과가 좋다


단점

  • 모델을 만드는데 시간이 오래걸리며 (복잡하면) 컴퓨터 능력이 많이 필요함

  • Overfitting 문제가 발생할 가능성이 있다

  • 예측값은 있지만 (결과는 있지만) 과정을 이해할 수 없다 따라서 실무적으로 사용하는데 문제가 있을수 있음(고객에게 설명을 해줄 수 없다




부스팅은 앙상블 기법중 하나이다. 앙상블 기법은 모형 하나를 만드는 것이 아닌

여러 개의 모형을 만들어서 평균을 내서 예측을 하는 것이다.


예를 들어서 700명의 데이터 중에서 500명만 뽑아서 예측 작업을 한다면, 

복원추출을 사용하여 모델을 여러번 만들게 되면 각 셋마다 완벽히 중복되지 않는

여러 셋을 만들수 있는 것이다.


즉 앙상블 기법은 단독 모델로 예측하는 것이 아닌 여러 모델을 생성하여 예측을 하고

평균을 통해 이 결과를 예측하는 기법이다.


저번 포스팅에서 진행했던 실습을 이어서 해보자.


1
2
3
4
5
6
#10 trial 과 부스트드 결정 트리
credit_boost10<-C5.0(credit_train[-17],credit_train$default,
                     trials=10)
credit_boost10
summary(credit_boost10)
  #r=900개의 (10번) 시도중 3.4퍼 (31개) 만 오류남
cs


소스코드는 기존과 동일하지만, 달라진 점이 있다면 trials (시도)를 10으로

즉 10번 시도한 평균치를 바탕으로 모델을 생성한다.




summary(credit_boost10) 을 통해 확인해보면 

900번의 시도중 에러가 31개로 부스팅 시도 전보다 줄어든 것을 확인할 수 있다.



1
2
3
4
5
6
credit_boost_pred10<-predict(credit_boost10,credit_test)
 
CrossTable(credit_test$default,credit_boost_pred10,
           prop.chisq=FALSE,prop.c=FALSE,prop.r=FALSE,
           dnn=c("actual default""predict default"))
            #오차율이 23퍼센트로 줄어들었다 
cs

위에서 생성한 예측 모델을 활용하여 test 데이터를 예측한다.


이 결과를 CrossTable로 확인해보면 오차율이 23퍼센트로 감소했음을 확인할수있다.

해당 프로세스와 동일하게 부스팅을 100번으로 맞추고 시도해 보면

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 
#100 trials 과 부스트드 결정 트리 
credit_boost100<-C5.0(credit_train[-17],credit_train$default,
                     trials=100)
credit_boost100
summary(credit_boost100)
  #900번 시도중 오차0 
 
credit_boost_pred100<-predict(credit_boost100,credit_test)
 
CrossTable(credit_test$default,credit_boost_pred100,
           prop.chisq=FALSE,prop.c=FALSE,prop.r=FALSE,
           dnn=c("actual default""predict default"))
          #오차율이 22퍼센트로 줄어들었다 
cs

이렇게 진행할 수 있으며, 크로스테이블을 활용하여 결과를 확인해 본다면
오차가 줄어든 것을 확인할 수 있다.

이처럼 부스팅 기법은 복원추출을 바탕으로 여러 모델을 만들어 그 평균치를 활용하기 때문에 기존에 1회 시도했을때의 예측보다 예측의 정확도가 높아지는 경향을 보인다.




+ Recent posts