이전에 caret 패키지로 Data Scaling 하는 방법을 알아보았다.
2020/09/03 - [R] - [R] caret 패키지로 scale 하는 방법 :: scale in R (preProcess in caret) :: 표준화 vs 정규화
이번에는 caret 패키지를 이용하여 모델을 만들고, random search, grid search 로 모델을 튜닝하는 것까지 소개하려 한다.
Classification with KNN in caret package
실습에는 iris data 를 사용한다.
irir dataset (붓꽃 데이터셋)
150개의 레코드, 5개의 컬럼으로 구성
Sepal Length : 꽃받침 길이
Sepal Width : 꽃받침 너비
Petal Length : 꽃잎의 길이
Petal Width : 꽃잎의 너비
Species : 꽃의 종류(setosa / versicolor / virginica) :: Label
Sepal Length, Sepal Width, Petal Length, Petal Width 로 Species를 분류하는 문제를 해결하는 것이 목표이다.
편의를 위해 Species는 세 가지가 아니라 두 가지로 진행한다.
library(tidyverse)
data <- iris %>% mutate(Species = as.character(Species))
data <- data %>% filter(Species %in% c("setosa","versicolor"))
data$Species <- as.factor(data$Species)
(Species를 character형으로 바꾸지 않으면 두 개의 Species만 filtering해도 여전히 3개의 Factor Level을 가지고 있기 때문에 이후 모델링 과정에서 에러가 발생한다.)
> str(data)
'data.frame': 100 obs. of 5 variables:
$ Sepal.Length: num 5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
$ Sepal.Width : num 3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
$ Petal.Length: num 1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
$ Petal.Width : num 0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
$ Species : Factor w/ 2 levels "setosa","versicolor": 1 1 1 1 1 1 1 1 1 1 ...
1. Split data set (train/test)
전체 100건의 데이터셋에 대해 70%/30%로 train set과 test set을 분리한다.
(매번 같은 데이터셋을 만들기 위해 seed를 지정해 주었다. 생략 가능)
library(caret)
set.seed(1)
idx <- sample(1:nrow(data), nrow(data)*0.7)
train <- data[idx,]
test <- data[-idx,]
> nrow(train)
[1] 70
> nrow(test)
[1] 30
> table(train$Species)
setosa versicolor
34 36
> table(test$Species)
setosa versicolor
16 14
2. Modeling (Classification with KNN)
knn 알고리즘으로 iris 데이터에서 Species(꽃의 종류)를 분류하는 모델을 만든다.
(분류 알고리즘에는 knn 말고도 다양한 알고리즘이 존재하며, caret 패키지에서 제공하는 알고리즘 종류는 topepo.github.io/caret/available-models.html 에서 확인할 수 있다.)
2-1. tuning method = "none"
아무런 파라미터 없이 기본 코드는 다음과 같다.
tune <- caret::trainControl(method = "none")
model1 <- caret::train(Species ~ ., data = train,
method = "knn",
trControl = tune)
Cross Validation도, 파라미터 지정도, 튜닝도 없이 mthod = "none"으로 지정해 주었다.
* (참고) Cross Validation을 할 때는 method = "CV"로 지정해주고, number로 몇 개의 fold로 나눌지 정해준다.
아래는 5 fold Cross Validation 할 때 코드이다.
tune <- caret::trainControl(method = "CV", number = 5)
이를 test set 에 적용해 예측값을 뽑고, 실제값과 예측값의 confusion matrix를 뽑아 성능을 비교하는 코드는 다음과 같다.
preds1 <- predict(model1, newdata = test)
caret::confusionMatrix(preds1, test$Species)
> caret::confusionMatrix(preds1, test$Species)
Confusion Matrix and Statistics
Reference
Prediction setosa versicolor
setosa 16 0
versicolor 0 14
Accuracy : 1
95% CI : (0.8843, 1)
No Information Rate : 0.5333
P-Value [Acc > NIR] : 6.456e-09
Kappa : 1
Mcnemar's Test P-Value : NA
Sensitivity : 1.0000
Specificity : 1.0000
Pos Pred Value : 1.0000
Neg Pred Value : 1.0000
Prevalence : 0.5333
Detection Rate : 0.5333
Detection Prevalence : 0.5333
Balanced Accuracy : 1.0000
'Positive' Class : setosa
* confusion matirx에 대한 설명은 이전에 올려놓은 포스트를 참고
iris data set이 워낙 깨끗해서 아무런 파라미터 튜닝 없이도 결과가 너무 좋다.
하지만 현실에서 다룰 실제 데이터는 이렇게 깨끗하지 않고, 처음부터 모델의 결과가 이렇게나 좋기 쉽지 않다. 따라서 파라미터 튜닝 과정을 통해 모델을 고도화한다.
2-2. Parameter Tuning with Random Search in caret
caret 패키지에서는 각 모델 알고리즘 별 필요한 파라미터가 무엇인지 modelLookup(model = ) 을 통해 제공한다.
> caret::modelLookup("knn")
model parameter label forReg forClass probModel
1 knn k #Neighbors TRUE TRUE TRUE
* (참고) xgbLinear 모델은 다음과 같이 4개의 hyper parameter를 필요로 한다.
> caret::modelLookup("xgbLinear")
model parameter label forReg forClass probModel
1 xgbLinear nrounds # Boosting Iterations TRUE TRUE TRUE
2 xgbLinear lambda L2 Regularization TRUE TRUE TRUE
3 xgbLinear alpha L1 Regularization TRUE TRUE TRUE
4 xgbLinear eta Learning Rate TRUE TRUE TRUE
knn 알고리즘은 k 라는 하나의 파라미터를 필요로 한다. (참고로 k의 의미는 "탐색할 이웃의 수" 이다.)
랜덤 서치 방법으로 파라미터를 찾는 코드는 다음과 같다.
tuneLength를 지정하여 tuneLength개의 파라미터를 랜덤 하게 서치 한다.
Cross Validation을 해주지 않으면 에러가 나는데, 파라미터를 서치 하는 과정에서 validation set이 없으면 Accuracy를 계산하지 못해서가 아닐까 추측한다.
tune2 <- caret::trainControl(method = "CV", number = 5)
model2 <- caret::train(Species ~ ., data = train,
method = "knn",
trControl = tune2,
tuneLength = 20)
결과는 다음과 같다.
> model2
k-Nearest Neighbors
70 samples
4 predictor
2 classes: 'setosa', 'versicolor'
No pre-processing
Resampling: Cross-Validated (5 fold)
Summary of sample sizes: 56, 55, 56, 57, 56
Resampling results across tuning parameters:
k Accuracy Kappa
5 1.0000000 1.0000000
7 1.0000000 1.0000000
9 1.0000000 1.0000000
11 1.0000000 1.0000000
13 1.0000000 1.0000000
15 1.0000000 1.0000000
17 1.0000000 1.0000000
19 1.0000000 1.0000000
21 1.0000000 1.0000000
23 1.0000000 1.0000000
25 1.0000000 1.0000000
27 1.0000000 1.0000000
29 1.0000000 1.0000000
31 1.0000000 1.0000000
33 1.0000000 1.0000000
35 1.0000000 1.0000000
37 1.0000000 1.0000000
39 1.0000000 1.0000000
41 1.0000000 1.0000000
43 0.9857143 0.9714286
Accuracy was used to select the optimal model using the largest value.
The final value used for the model was k = 41.
랜덤 하게 뽑은 20개의 파라미터에 대해 validation set에 대한 Accuracy와 최종 선택된 k를 제공한다.
위에서 언급했듯 iris 데이터가 너무 깨끗해 어떤 k값을 주어도 Accuracy는 1로 나왔다.
각 k에 대한 Accuracy를 그래프로 확인할 수도 있다.
> plot(model2)
x축은 k, y 축은 Accuracy이다.
2-3. Parameter Tuning with Grid Search in caret
다음은 직접 지정한 파라미터 중 가장 좋은 값을 찾아주는 Grid Search 방법이다.
코드는 아래와 같다.
model3 <- caret::train(Species ~ ., data = train,
method = "knn",
trControl = tune2,
tuneGrid = expand.grid(k = 1:10))
tuneGrid 에 직접 지정한 파라미터의 범위를 넣어준다. 단, knn은 파라미터가 k 하나지만, xgbLinear 처럼 여러 개인 경우 모든 파라미터를 다 지정해 주어야 한다.
꼭 범위를 넣어준 필요는 없고 k = 2 처럼 하나의 값을 지정해 줄 수도 있다.
결과는 다음과 같다.
> model3
k-Nearest Neighbors
70 samples
4 predictor
2 classes: 'setosa', 'versicolor'
No pre-processing
Resampling: Cross-Validated (5 fold)
Summary of sample sizes: 56, 56, 56, 56, 56
Resampling results across tuning parameters:
k Accuracy Kappa
1 1 1
2 1 1
3 1 1
4 1 1
5 1 1
6 1 1
7 1 1
8 1 1
9 1 1
10 1 1
Accuracy was used to select the optimal model using the largest value.
The final value used for the model was k = 10.
Random Search와 마찬가지로 파라미터 값 별 Accuracy는 plot으로 그려 볼 수 있다.
데이터 셋의 크기가 크고, 지정해 주어야 할 파라미터의 수가 많으면 모든 값을 Grid Search로 하기에는 시간이 너무 오래 걸린다.
따라서 Random Search로 값을 먼저 찾아보고, 가장 좋았던 값 주변의 몇 개를 다시 Grid Search로 찾는 것을 추천한다.
'R' 카테고리의 다른 글
[R] Add an index (or counter) to a dataframe by group (1) | 2021.03.26 |
---|---|
[R] How to expand rows by date range using start and end date? (0) | 2021.03.26 |
[R] caret 패키지로 scale 하는 방법 :: scale in R (preProcess in caret) :: 표준화 vs 정규화 (0) | 2020.09.03 |
윈도우 작업 스케줄러에 R script 등록하기 (2) | 2020.03.05 |
[R] Nelson Rules in R (5) | 2020.02.04 |