01 분석 과정
-01 모델링
-02 의사결정나무 ( #10 10일차_분류분석)
02 앙상블 모형
03 랜덤포레스트
01 분석 과정
분석기획 → 데이터 수집 → 데이터 처리 → 모델링 → 평가 → 튜닝 → 전개
- 데이터 수집의 경우
회사의 경우 업무 목적에 따라 DB가 세팅되어 있다 (데이터 마트).
분석용 서버를 구축해야할 때, 기존 DB에서 새 DB로 데이터를 이동시키는 것을 Data migration이라고 한다.
이 때 ETL, API 등을 통해 내부 데이터를 분석용 DB에 적재하게 된다.
외부 데이터를 가져와야하는 경우 크롤링 등의 다양한 방법이 존재한다.
- 데이터 처리
EDA(분포시각화, 기술통계량확인, 노이즈확인)
결측치 처리
이상치 처리
변수 변환(스케일링, 파생변수생성, 단순변환(지수, 역수, 로그 등) 등)
데이터분리(훈련 / 검증 / 평가) : 평가점수의 일반화를 위하여 진행한다.
- 튜닝
튜닝의 경우 매개변수(하이퍼파라미터)에 대한 튜닝이며, 과적합 등을 확인한다.
상황에 따라 데이터 처리 과정으로 돌아가 계속하여 해당 과정을 반복한다.
- 전개
시스템구축
모니터링
생애주기(lifycycle) 설정
리모델링 계획
-01 모델링
- 수집한 데이터를 한 건씩 기계(알고리즘)에 학습
- 학습된 데이터를 사용하여 유의미한 패턴을 찾는 과정
모델링 방법은 분석기법에 따라 다르다
분석기법(지도학습)
1) 회귀분석
- 회귀분석을 도와주는 다양한 알고리즘이 있다.
- 선형회귀, 다중회귀, 릿지, 라쏘, 엘라스틱넷 등
2) 분류분석
- 의사결정나무, 랜덤포레스트, 그래디언트부스팅, 에이다부스팅, SVM, Knn 등
-02 의사결정나무 ( #10 10일차_분류분석)
- 정확도는 학습하는 과정에서 올라가는 것
- 정지규칙, 가지치기는 모델의 단순화를 위해 수행
- 하이퍼파라미터 튜닝은 과적합 방지, 일반화를 위해 수행하는 것이며 정확도를 위해 수행하는 것이 아님
[ 예제 - 의사결정나무를 사용한 분류분석 (iris) ]
목표 : iris의 speices(y)를 정확하게 예측하는 분류모형 생성
1. 데이터 탐색 (EDA)
1) 기술통계량
summary(iris)
2) 시각화
2-1) 교차산점도 : 상관관계, y분류의 직접적인 변수 확인
Species 중 분류에 있어서 어떤 변가 가장 강력한가를 교차 산점도를 통해 확인할 수도 있다.
plot(iris[,-5], col = iris$Species)
2-2) 이상치
boxplot(iris[,-5])
2. 데이터 처리
변수 변환, 변수 선택, 스케일링, ...
tree 기반 모델의 장점은 스케일링을 고려하지 않아도 됨
3. 모델링
1) 훈련 / 평가 데이터 분리 (7:3)
sample(1:45, 6)
sample(1:45, 6, replace = T) # 같은 숫자가 여러번 나와도 될 때
set.seed(0)
rn <- sample(1:nrow(iris), nrow(iris) * 0.7)
iris_train <- iris[rn, ]
iris_test <-iris[-rn, ]
2) 학습
install.packages('rpart')
library(rpart)
m1 <- rpart(Species ~ .,iris_train)
m1
3) 모델결과 시각화
plot(m1)
text(m1, cex = 0.7)
install.packages('rpart.plot')
library(rpart.plot)
4) 평가 (일반화 성능)
train / test score
4-1) train score
predict 할 때는 x를 가지고 y를 추정하는 것이기 때문에 y에 대한 값이 필요하지 않다.
predict(m1, newdata = iris_train[,-5])
> predict(m1, newdata = iris_train[,-5])
setosa versicolor virginica
142 0 0.0000000 1.00000000
68 0 0.9189189 0.08108108
129 0 0.0000000 1.00000000
43 1 0.0000000 0.00000000
14 1 0.0000000 0.00000000
51 0 0.9189189 0.08108108
85 0 0.9189189 0.08108108
21 1 0.0000000 0.00000000
각 class별 확률이 출력된다.
pre_tr <- predict(m1, newdata = iris_train[,-5], type = 'class')
> predict(m1, newdata = iris_train[,-5], type = 'class')
142 68 129 43
virginica versicolor virginica setosa
14 51 85 21
setosa versicolor versicolor setosa
106 74 7 73
virginica versicolor setosa versicolor
79 37 105 110
예측 결과가 출력된다.
pre_tr == iris_train$Species
> pre_tr == iris_train$Species
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[8] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[15] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[22] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[29] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[36] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[43] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[50] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[57] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[64] TRUE TRUE TRUE TRUE TRUE FALSE TRUE
[71] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[78] TRUE FALSE TRUE TRUE TRUE TRUE TRUE
[85] TRUE TRUE TRUE TRUE FALSE TRUE TRUE
[92] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
[99] TRUE TRUE TRUE TRUE TRUE TRUE TRUE
예측 결과와 실제 데이터 사이의 비교를 진행한다.
TRUE의 경우 예측 성공, FALSE의 경우 예측 실패이다.
맞춘 데이터 / 전체 데이터
sum(pre_tr == iris_train$Species) / nrow(iris_train) * 100
> sum(pre_tr == iris_train$Species) / nrow(iris_train) * 100
[1] 97.14286
4-2) test score
pre_te <- predict(m1, newdata = iris_test[,-5], type = 'class')
sum(pre_te == iris_test$Species) / nrow(iris_test) * 100
> sum(pre_te == iris_test$Species) / nrow(iris_test) * 100
[1] 93.33333
** 일반적으로
train_score가 test_score보다 높게 나온다.
만약 train_score가 teset_score보다 낮은 경우는 모델이 너무 단순해서 발생하는 결과일 수 있음
-> 모델 복잡도 증가
5) 하이퍼파라미터 튜닝
m1 <- rpart(Species ~ ., iris_train)
? rpart
# rapart control 기본 세팅 확인하기
rpart.control(minsplit = 20, minbucket = round(minsplit/3), cp = 0.01,
maxcompete = 4, maxsurrogate = 5, usesurrogate = 2, xval = 10,
surrogatestyle = 0, maxdepth = 30, ...)
# minbucket, minsplit 은 같은 맥락이다. (추가분류를 할 오뷴류 기준)
# minbucket : the minimum number of observations in any terminal <leaf> node. If only one of minbucket or minsplit is specified, the code either sets minsplit to minbucket*3 or minbucket to minsplit/3, as appropriate.
# 따라서 minsplit은 minbucket * 3이라 minsplit을 튜닝하여도 minbucket이 자동으로 변경된다.
# maxdepth : depth 의 최대값 설정
# minbucket 7 -> 2
m2 <- rpart(Species ~ ., iris_train, minbucket = 2)
** 이전 모델과 비교 시각화
par(mfrow = c(1,2))
prp(m1, type = 4, extra = 3)
prp(m2, type = 4, extra = 3)

과적합 판단 기준도 명확하지 않다.
훈련 데이터 : 테스트 데이터 = 90 : 70의 경우 과적합이라고 할 수도 있지만, 원래 훈련 데이터의 정답률을 고려하였을 때,
90이 나온다해서 무조건 과적합이라고 할 수는 없다.
(통상 10% 이상의 차이가 났을 때 과적합이라고 말한다.)
** 평가점수 비교
pre_tr2 <- predict(m2, newdata = iris_train, type = 'class')
pre_te2 <- predict(m2, newdata = iris_test, type = 'class')
sum(pre_tr2 == iris_train$Species) / nrow(iris_train) * 100
sum(pre_te2 == iris_test$Species) / nrow(iris_test) * 100
> sum(pre_tr2 == iris_train$Species) / nrow(iris_train) * 100
[1] 99.04762
> sum(pre_te2 == iris_test$Species) / nrow(iris_test) * 100
[1] 93.33333
6) 추가 정보
의사결정나무를 비롯한 tree 기반 알고리즘은 변수를 자동으로 선택해준다.
따라서 상관이 없어보이는 변수라하더라도 사전에 제거할 필요가 없다.
변수의 중요도가 불순도 감소량에 대한 기여도로 책정된다.
변수의 중요도 확인하기
m2$variable.importance
> m2$variable.importance
Petal.Width Petal.Length Sepal.Length Sepal.Width
65.47082 62.23230 40.28970 28.93208
위의 시각화를 보았을 때 Sepal에 관련된 항목이 보이지 않던 이유가 다음과 같다.
최종모델이 의사결정나무로 이용될 수도 있으나, 변수선택의 근거를 찾기 위해서도 사용할 수 있다.
예를 들어 SVM 모델이 최종 구현해야하는 모델인데 변수를 제거하는데에 있어 근거가 부족한 경우,
이와 같이 tree 모델을 사용하여 변수를 선택할 수 있다.
(변수선택에 있어 의사결정나무를 사용하는 예시) = 변수선택을 임베디드 기법으로 해보겠다 등으로 언급할 수 있음.
m2$cptable
> m2$cptable
CP nsplit rel error xerror xstd
1 0.50724638 0 1.00000000 1.17391304 0.06235975
2 0.44927536 1 0.49275362 0.59420290 0.07244996
3 0.02898551 2 0.04347826 0.04347826 0.02474098
4 0.01000000 3 0.01449275 0.05797101 0.02842804
nsplit : 분리한 수, 따라서 nslit + 1이 최종 depth가 된다 (3+1 = 4, depth는 4가 된다.)
가지치기시 참고한다.
만약에 한 번 split한 지점까지만 학습, 그 이후의 경우 모두 가지치기를 원한다면
cp값은 nsplit이 1인 지점의 값을 가지게 된다.
m3 <- rpart(Species ~ ., iris_train, cp = 0.4492754)
> m3
n= 105
node), split, n, loss, yval, (yprob)
* denotes terminal node
1) root 105 69 virginica (0.3333333 0.3238095 0.3428571)
2) Petal.Length< 2.45 35 0 setosa (1.0000000 0.0000000 0.0000000) *
3) Petal.Length>=2.45 70 34 virginica (0.0000000 0.4857143 0.5142857) *
m2 <- rpart(Species ~ ., iris_train)
▲ minbucket으로 인해 값이 미세하게 조정되기 때문에 이 코드 기준으로 CP를 참고해야 한다.
m2 <- rpart(Species ~ ., iris_train, minbucket = 2)
-03 불순도
- 하나의 노드에 얼마나 많은 범주(class)들이 혼합되어 있는지를 나타내는 척도
- 뿌리노드 > 끝노드
- 정보이득(Information Gain), 카이제곱 통계량 : 불순도 감소량 측정 척도 (부모노드, 자식노드 불순도 측정이 선행되어야 함)
- 지니 지수, 엔트로피 지수 : 한 노드의 불순도 측정 척도
1) 카이제곱통계량
2) 지니 지수
3) 엔트로피 지수
02 앙상블 모형
- 서로 다른 동일한 / 다른 알고리즘을 결합하여 만든 모형
1) 부트스트랩
학습된 데이터를 만드는 과정까지만을 부트스트랩으로 정의
서로 크기가 같으면서 내부 구조가 다른 학습 데이터셋을 만드는 과정
복원추출 허용 -> 동일한 데이터가 반복 추출될 수 있으며 단 한 번도 추출되지 않은 데이터도 존재
2) 배깅 (Bootstrap + aggregating)
부트스트랩으로 만들어진 서로 다른 학습데이터를 각 학습기에 적용하여 각 학습기의 결과를 최종 결합(평균 또는 다수결)하여 결론을 내는 모형
각 모델을 병렬로 학습 -> cpu core 효율성 극대화 가능
각 모델이 서로 독립적일 수 있음
ex) 랜덤포레스트
3) 부스팅
이전 모델을 보완하여 이후 모델을 계속 만드는 과정
모델끼리 서로 독립적이지 않음
ex) 그래디언트 부스팅, 에이다 부스팅
03 랜덤포레스트
의사결정나무를 여러개 결헙하여 만든 앙상블 모형
배깅 모형 (각 독립적인 트리가 각각 학습을 하는 형태)
목표) 서로 독립적인 트리를 구성
1) 부트스트랩 : 학습데이터를 다르게 구성
2) 임의성 정도 : 매 분리마다 모든 설명변수를 고려하여 최적의 변수를 선택하는 것이 아닌, mtry로 설정된 설명변수만 랜덤하게 선택한 뒤 그 변수 중 가장 중요도가 높은 변수로 최적분리 진행
* 임의성 정도가 클수록 모든 트리가 비슷해짐
* 임의성 정도가 작을수록 모든 트리가 독립적임
[ 랜덤포레스트 - iris의 품종분류 ]
install.packages('randomForest')
library(randomForest)
## S3 method for class 'formula'
randomForest(formula, data=NULL, ..., subset, na.action=na.fail)
## Default S3 method:
randomForest(x, y=NULL, xtest=NULL, ytest=NULL, ntree=500,
mtry=if (!is.null(y) && !is.factor(y))
max(floor(ncol(x)/3), 1) else floor(sqrt(ncol(x))),
weights=NULL,
replace=TRUE, classwt=NULL, cutoff, strata,
sampsize = if (replace) nrow(x) else ceiling(.632*nrow(x)),
nodesize = if (!is.null(y) && !is.factor(y)) 5 else 1,
maxnodes = NULL,
importance=FALSE, localImp=FALSE, nPerm=1,
proximity, oob.prox=proximity,
norm.votes=TRUE, do.trace=FALSE,
keep.forest=!is.null(y) && is.null(xtest), corr.bias=FALSE,
keep.inbag=FALSE, ...)
## S3 method for class 'randomForest'
print(x, ...)
# step1) 데이터분리(train / test)
set.seed(0)
rn <- sample(1:150, 105)
> sample(1:150, 105)
[1] 142 68 129 43 14 51 85 21 106 74 7 73 79 37 105 110 34 150 126 89 33 84 35 70
[25] 141 42 38 111 20 28 122 44 87 127 40 119 25 117 39 145 125 6 24 32 146 2 45 18
[49] 22 78 65 113 118 99 75 81 13 116 131 48 92 23 148 29 94 102 121 91 130 104 143 31
[73] 17 139 83 64 60 123 134 10 1 147 59 26 15 58 98 108 135 76 53 12 112 63 132 88
[97] 144 93 82 19 67 128 69 97 96
iris_train <- iris[rn, ]
iris_test <- iris[-rn, ]
# step2) 모델링
m1 <- randomForest(Species ~., data = iris_train)
> m1
Call:
randomForest(formula = Species ~ ., data = iris_train)
Type of random forest: classification
Number of trees: 500
No. of variables tried at each split: 2
OOB estimate of error rate: 3.81%
Confusion matrix:
setosa versicolor virginica class.error
setosa 35 0 0 0.00000000
versicolor 0 32 2 0.05882353
virginica 0 2 34 0.05555556
# ntree (트리의 개수) default 는 500개이며 필요시 조정하면 된다.
# No. of variables tried at each split : 2 <- mtry (변수의 수), 설명변수의 수에 따라 변동된다
# OOB estimate of error rate <- 오분류율
| setosa | versicolor | virginica | class.error | |
| setosa | 정분류 | 오분류 | 오분류 | 0.00.... |
| versicolor | 오분류 | 정분류 | 오분류 | 0.05.... |
| virginica | 오분류 | 오분류 | 정분류 | 0.05.... |
# step3) 평가
# 정확도(accuracy) : 맞춘개수 / 총개수
pre_tr1 <- predict(m1, newdata = iris_train, type = 'class')
pre_te1 <- predict(m1, newdata = iris_test, type = 'class')
sum(pre_tr1 == iris_train$Species) / nrow(iris_train) * 100
sum(pre_te1 == iris_test$Species) / nrow(iris_test) * 100
> sum(pre_tr1 == iris_train$Species) / nrow(iris_train) * 100
[1] 100
> sum(pre_te1 == iris_test$Species) / nrow(iris_test) * 100
[1] 93.33333
# step4) 파라미터 튜닝
1) ntree : 트리의 수 (default : 500)
- 트리의 수가 많을수록 예측력 향상
- 일정 이상 커지면 예측력 변화가 없음 (elbow point)
vscore_tr <- c() ; vscore_te <- c()
for (i in 1:500) {
# 모델 형성 및 학습
m1 <- randomForest(Species ~., data = iris_train, ntree = i)
# 예측
pre_tr1 <- predict(m1, newdata = iris_train, type = 'class')
pre_te1 <- predict(m1, newdata = iris_test, type = 'class')
# 점수
vscore_tr <- c(vscore_tr, sum(pre_tr1 == iris_train$Species) / nrow(iris_train) * 100)
vscore_te <- c(vscore_te, sum(pre_te1 == iris_test$Species) / nrow(iris_test) * 100)
}
dev.new()
plot(1:500, vscore_tr, type = 'o', col = 'red', ylim = c(80, 100),
xlab = 'ntree', ylab = 'accuracy')
lines(1:500, vscore_te, type = 'o', col = 'blue')
legend('topright', c('train_score', 'test_score'), lty = 1, col = c('red', 'blue'),
inset = c(0.03, 0.03))

트리의 개수를 약 20개 이상 만들 필요는 없음으로 판단한다.
2) mtry(임의성정도) : 트리 학습 시 최적 분리 조건을 생성하는 설명변수의 수
- mtry만큼을 랜덤하게 선택한 후 선택된 변수 중 가장 좋은 변수를 최적 분리 조건으로 사용
- 너무 작으면 낮은 정확도 또는 과적합 문제 발생
- 너무 크면 서로 유사한 트리가 생성됨 -> 과적합 문제 발생
vscore_tr <- c() ; vscore_te <- c()
for (i in 1:ncol(iris[,-5])) {
# 모델 형성 및 학습
m1 <- randomForest(Species ~., data = iris_train, mtry = i)
# 예측
pre_tr1 <- predict(m1, newdata = iris_train, type = 'class')
pre_te1 <- predict(m1, newdata = iris_test, type = 'class')
# 점수
vscore_tr <- c(vscore_tr, sum(pre_tr1 == iris_train$Species) / nrow(iris_train) * 100)
vscore_te <- c(vscore_te, sum(pre_te1 == iris_test$Species) / nrow(iris_test) * 100)
}
dev.new()
plot(1:4, vscore_tr, type = 'o', col = 'red', ylim = c(80, 100),
xlab = 'mtry', ylab = 'accuracy')
lines(1:4, vscore_te, type = 'o', col = 'blue')
legend('topright', c('train_score', 'test_score'), lty = 1, col = c('red', 'blue'),
inset = c(0.03, 0.03))

'아이티윌_데이터 분석 55기 > 강의내용 필기_통계 및 분석' 카테고리의 다른 글
| #13 13일차_군집분석 및 평가 ·해석, 변수 스케일링, 회귀분석 (0) | 2026.04.29 |
|---|---|
| #12 12일차_교차검증, 분류모형, 군집분석 (0) | 2026.04.28 |
| #10 10일차_분류분석 (0) | 2026.04.24 |
| #9 9일차_교차분석, 변수 선택 (0) | 2026.04.23 |
| #8 8일차_가설검정 절차, 문제풀이 (0) | 2026.04.22 |