R의 결정 트리: 예제가 포함된 분류 트리
⚡ 스마트 요약
R의 의사결정 트리는 각 리프 노드가 하나의 지배적인 클래스를 가질 때까지 간단한 예/아니오 규칙을 사용하여 데이터를 분기합니다. 이 가이드에서는 타이타닉 생존 데이터셋에 대해 rpart 분류 트리를 구축하고, 시각화하고, 평가하고, 튜닝하는 방법을 보여줍니다.

의사결정나무란 무엇입니까?
의사 결정 트리 의사결정 트리는 분류 및 회귀 작업을 모두 수행할 수 있는 다재다능한 머신러닝 알고리즘입니다. 복잡한 데이터셋에도 잘 적응하는 매우 강력한 알고리즘입니다. 특히, 의사결정 트리는 오늘날 가장 강력한 머신러닝 알고리즘 중 하나인 랜덤 포레스트의 핵심 구성 요소입니다.
코드로 트리를 구축하기 전에 트리가 어디에서 분기할지 결정하는 방식을 아는 것이 도움이 됩니다.
의사결정 트리는 어떻게 작동하나요?
의사결정 트리는 데이터셋을 세 가지 유형의 노드로 구성된 예/아니오 질문의 흐름도로 변환합니다. 뿌리 모든 훈련 관찰을 담당합니다. 내부 노드 하나의 예측 변수에 대한 질문을 하고 데이터를 두 부분으로 나눕니다. 잎 분할을 중지하고 다수 클래스를 반환합니다.
성장은 탐욕스러운 절차를 따릅니다. 재귀적 이진 분할:
- 모든 후보군을 평가하십시오. 각 예측 변수와 절단점에 대해, 결과적으로 생성되는 두 그룹이 얼마나 불순해지는지를 측정합니다.
- 가장 좋은 것을 남겨두세요. 불순물을 가장 많이 줄이는 분할 방법이 해당 노드에서 제기되는 질문이 됩니다.
- 각 아이에게 똑같이 반복합니다. 제어 규칙(minsplit, minbucket, maxdepth 또는 cp)이 중지할 때까지.
- 치다. cp는 자체적으로 수익을 내지 못하는 가지를 잘라내어 트리가 학습 데이터 세트를 기억하는 것을 막습니다.
각 질문은 하나의 변수를 임계값과 비교하기 때문에 알고리즘은 스케일링이나 더미 코딩이 필요하지 않습니다.
의사결정 트리에서 지니 계수와 엔트로피의 비교
그 불순물은 두 가지 방법으로 측정할 수 있으며, rpart를 사용하면 원하는 방법을 선택할 수 있습니다.
| 기준 | 지니 인덱스 | 엔트로피(정보 이득) |
|---|---|---|
| 공식 | 1 – 제곱된 계급 비율의 합 | -p 곱하기 log2(p)의 합 |
| 범위(두 클래스) | 0 ~ 0.5 | 0 ~ 1 |
| 계산 | 더 빠르고, 로그 함수는 필요 없습니다. | 속도가 느리고 로그를 사용합니다. |
| rpart 설정 | 태만 | parms = list(split = “정보”) |
fit_entropy <- rpart(survived~., data = data_train, method = 'class', parms = list(split = "information"))
실제로 두 기준 모두 대부분의 경우 동일한 분할을 선택하므로 기본값인 지니 계수를 사용하는 것이 안전한 선택입니다.
의사결정 트리의 장점과 단점
이러한 장단점을 통해 단일 트리로 충분한 시점과 앙상블로 전환해야 하는 시점을 알 수 있습니다.
장점
- 완전히 해석 가능함: 적합된 모델은 모든 이해관계자가 이해할 수 있는 다이어그램입니다.
- 최소한의 전처리: 별도의 스케일링이나 정규화가 필요하지 않으며, 팩터는 기본적으로 작동합니다.
- 두 가지 작업을 모두 처리합니다. `method = 'class'`는 분류기를 적합시키고 `method = 'anova'`는 회귀 트리를 적합시킵니다.
- 훈련 속도가 빠릅니다: 대규모 데이터 세트는 몇 초 만에 처리되므로 트리 구조가 유용한 첫 번째 기준점이 됩니다.
단점
- 높은 분산도: 훈련 데이터의 작은 변화만으로도 완전히 다른 계통수가 생성될 수 있습니다.
- 과적합되기 쉬움: 제약이 없는 트리는 cp와 maxdepth가 제한하지 않는 한 모든 잎이 순수해질 때까지 성장합니다.
- 축 평행 분할만 해당: 대각선 경계에는 계단식 절단면이 많이 필요합니다.
처음 두 가지 약점에 대한 해결책은 많은 나무를 평균내는 것인데, 이것이 바로 랜덤 포레스트 않습니다.
R에서 의사결정 트리를 학습시키고 시각화하는 방법
R에서 첫 번째 의사결정 트리를 구축하려면 다음 7단계를 거쳐야 합니다.
- 1단계: 데이터 가져오기
- 2단계: 데이터 세트 정리
- 3단계: 학습/테스트 세트 만들기
- 4단계: 모델 구축
- 5단계: 예측하기
- 6단계: 성능 측정
- 7단계: 초매개변수 조정
1단계) 데이터 가져오기
타이타닉의 운명이 궁금하다면 다음 영상을 시청하세요. 유튜브. 이 데이터 세트의 목적은 빙산과의 충돌 후 어떤 사람들이 생존 가능성이 더 높은지 예측하는 것입니다. 데이터 세트에는 13개의 변수와 1309개의 관측치가 포함되어 있습니다. 데이터 세트는 변수 X를 기준으로 정렬됩니다.
set.seed(678) path <- 'https://raw.githubusercontent.com/guru99-edu/R-Programming/master/titanic_data.csv' titanic <-read.csv(path) head(titanic)
출력:
## X pclass survived name sex ## 1 1 1 1 Allen, Miss. Elisabeth Walton female ## 2 2 1 1 Allison, Master. Hudson Trevor male ## 3 3 1 0 Allison, Miss. Helen Loraine female ## 4 4 1 0 Allison, Mr. Hudson Joshua Creighton male ## 5 5 1 0 Allison, Mrs. Hudson J C (Bessie Waldo Daniels) female ## 6 6 1 1 Anderson, Mr. Harry male ## age sibsp parch ticket fare cabin embarked ## 1 29.0000 0 0 24160 211.3375 B5 S ## 2 0.9167 1 2 113781 151.5500 C22 C26 S ## 3 2.0000 1 2 113781 151.5500 C22 C26 S ## 4 30.0000 1 2 113781 151.5500 C22 C26 S ## 5 25.0000 1 2 113781 151.5500 C22 C26 S ## 6 48.0000 0 0 19952 26.5500 E12 S ## home.dest ## 1 St Louis, MO ## 2 Montreal, PQ / Chesterville, ON ## 3 Montreal, PQ / Chesterville, ON ## 4 Montreal, PQ / Chesterville, ON ## 5 Montreal, PQ / Chesterville, ON ## 6 New York, NY
tail(titanic)
출력:
## X pclass survived name sex age sibsp ## 1304 1304 3 0 Yousseff, Mr. Gerious male NA 0 ## 1305 1305 3 0 Zabour, Miss. Hileni female 14.5 1 ## 1306 1306 3 0 Zabour, Miss. Thamine female NA 1 ## 1307 1307 3 0 Zakarian, Mr. Mapriededer male 26.5 0 ## 1308 1308 3 0 Zakarian, Mr. Ortin male 27.0 0 ## 1309 1309 3 0 Zimmerman, Mr. Leo male 29.0 0 ## parch ticket fare cabin embarked home.dest ## 1304 0 2627 14.4583 C ## 1305 0 2665 14.4542 C ## 1306 0 2665 14.4542 C ## 1307 0 2656 7.2250 C ## 1308 0 2670 7.2250 C ## 1309 0 315082 7.8750 S
헤드 및 테일 출력에서 데이터가 섞이지 않은 것을 확인할 수 있습니다. 이것은 큰 문제입니다! 기차 세트와 테스트 세트 간에 데이터를 분할할 때 다음을 선택합니다. 만 클래스 1과 2의 승객(클래스 3의 승객은 관찰의 상위 80%에 포함되지 않음)은 알고리즘이 클래스 3의 승객의 특징을 결코 볼 수 없음을 의미합니다. 이러한 실수는 잘못된 예측으로 이어질 것입니다.
이 문제를 극복하기 위해 샘플() 함수를 사용할 수 있습니다.
shuffle_index <- sample(1:nrow(titanic)) head(shuffle_index)
의사결정트리 R 코드 설명
- Sample(1:nrow(titanic)): 1부터 1309까지(즉, 최대 행 수) 인덱스의 무작위 목록을 생성합니다.
출력:
## [1] 288 874 1078 633 887 992
이 인덱스를 사용하여 타이타닉 데이터 세트를 섞습니다.
titanic <- titanic[shuffle_index, ]
head(titanic)
출력:
## X pclass survived ## 288 288 1 0 ## 874 874 3 0 ## 1078 1078 3 1 ## 633 633 3 0 ## 887 887 3 1 ## 992 992 3 1 ## name sex age ## 288 Sutton, Mr. Frederick male 61 ## 874 Humblen, Mr. Adolf Mathias Nicolai Olsen male 42 ## 1078 O'Driscoll, Miss. Bridget female NA ## 633 Andersson, Mrs. Anders Johan (Alfrida Konstantia Brogren) female 39 ## 887 Jermyn, Miss. Annie female NA ## 992 Mamee, Mr. Hanna male NA ## sibsp parch ticket fare cabin embarked home.dest## 288 0 0 36963 32.3208 D50 S Haddenfield, NJ ## 874 0 0 348121 7.6500 F G63 S ## 1078 0 0 14311 7.7500 Q ## 633 1 5 347082 31.2750 S Sweden Winnipeg, MN ## 887 0 0 14313 7.7500 Q ## 992 0 0 2677 7.2292 C
2단계) 데이터세트 정리
여러 변수에 NA 값이 포함되어 있습니다. 정리 작업은 세 단계로 진행됩니다.
- home.dest, cabin, name, X, ticket 변수를 삭제하세요.
- pclass에 대한 요인 변수를 생성하고 생존했습니다.
- NA를 버리세요
library(dplyr) # Drop variables clean_titanic <- titanic %>% select(-c(home.dest, cabin, name, X, ticket)) %>% #Convert to factor level mutate(pclass = factor(pclass, levels = c(1, 2, 3), labels = c('Upper', 'Middle', 'Lower')), survived = factor(survived, levels = c(0, 1), labels = c('No', 'Yes'))) %>% na.omit() glimpse(clean_titanic)
Code 설명
- select(-c(home.dest, Cabin, name, X, ticket)): 불필요한 변수 삭제
- pclass = factor(pclass, levels = c(1,2,3), labels= c('Upper', 'Middle', 'Lower')): 변수 pclass에 레이블을 추가합니다. 1은 Upper, 2는 Middle, 3은 Lower가 됩니다.
- factor(survived, levels = c(0,1), labels = c('No', 'Yes')): 변수 survived에 레이블을 추가합니다. 0은 'No', 1은 'Yes'가 됩니다.
- na.omit(): NA 관찰을 제거합니다.
출력:
## Observations: 1,045 ## Variables: 8 ## $ pclass <fctr> Upper, Lower, Lower, Upper, Middle, Upper, Middle, U... ## $ survived <fctr> No, No, No, Yes, No, Yes, Yes, No, No, No, No, No, Y... ## $ sex <fctr> male, male, female, female, male, male, female, male... ## $ age <dbl> 61.0, 42.0, 39.0, 49.0, 29.0, 37.0, 20.0, 54.0, 2.0, ... ## $ sibsp <int> 0, 0, 1, 0, 0, 1, 0, 0, 4, 0, 0, 1, 1, 0, 0, 0, 1, 1,... ## $ parch <int> 0, 0, 5, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 2, 0, 4, 0,... ## $ fare <dbl> 32.3208, 7.6500, 31.2750, 25.9292, 10.5000, 52.5542, ... ## $ embarked <fctr> S, S, S, S, S, S, S, S, S, C, S, S, S, Q, C, S, S, C...
3단계) 열차/테스트 세트 생성
모델을 훈련하기 전에 다음 두 단계를 수행해야 합니다.
- 기차 및 테스트 세트 만들기: 기차 세트에서 모델을 훈련하고 테스트 세트(즉, 보이지 않는 데이터)에서 예측을 테스트합니다.
- 콘솔에서 rpart.plot 설치
일반적인 관행은 데이터를 80/20으로 분할하는 것입니다. 데이터의 80%는 모델을 훈련하는 데 사용되며 20%는 예측에 사용됩니다. 두 개의 별도 데이터 프레임을 생성해야 합니다. 모델 구축을 마칠 때까지 테스트 세트를 건드리고 싶지 않습니다. 세 개의 인수를 사용하는 함수 이름 create_train_test()를 만들 수 있습니다.
create_train_test(df, size = 0.8, train = TRUE) arguments: -df: Dataset used to train the model. -size: Size of the split. By default, 0.8. Numerical value -train: If set to `TRUE`, the function creates the train set, otherwise the test set. Default value sets to `TRUE`. Boolean value.You need to add a Boolean parameter because R does not allow to return two data frames simultaneously.
create_train_test <- function(data, size = 0.8, train = TRUE) { n_row = nrow(data) total_row = size * n_row train_sample <- 1: total_row if (train == TRUE) { return (data[train_sample, ]) } else { return (data[-train_sample, ]) } }
Code 설명
- function(data, size=0.8, train = TRUE): 함수에 인수를 추가합니다.
- n_row = nrow(data): 데이터세트의 행 수를 계산합니다.
- total_row = size*n_row: 기차 세트를 구성하기 위해 n번째 행을 반환합니다.
- train_sample <- 1:total_row : 첫 번째 행부터 n번째 행까지 선택
- if (train ==TRUE){ } else { }: 조건이 true로 설정되면 열차 세트를 반환하고 그렇지 않으면 테스트 세트를 반환합니다.
기능을 테스트하고 치수를 확인할 수 있습니다.
data_train <- create_train_test(clean_titanic, 0.8, train = TRUE) data_test <- create_train_test(clean_titanic, 0.8, train = FALSE) dim(data_train)
출력:
## [1] 836 8
dim(data_test)
출력:
## [1] 209 8
학습 데이터셋은 836행 8열로 구성되어 있으며, 테스트 데이터셋은 209행 8열로 구성되어 있습니다.
무작위화 프로세스가 올바른지 확인하려면 table()과 결합된 prop.table() 함수를 사용합니다.
prop.table(table(data_train$survived))
출력:
## ## No Yes ## 0.5944976 0.4055024
prop.table(table(data_test$survived))
출력:
## ## No Yes ## 0.5789474 0.4210526
두 데이터세트 모두 생존자 수는 약 40%로 동일합니다.
rpart.plot 설치
rpart.plot은 conda 라이브러리에서 사용할 수 없습니다. 콘솔에서 설치할 수 있습니다.
install.packages("rpart.plot")
4단계) 모델 구축
이제 모델을 구축할 준비가 되었습니다. rpart() 의사결정 트리 함수의 구문은 다음과 같습니다.
rpart(formula, data=, method='') arguments: - formula: The function to predict - data: Specifies the data frame - method: - "class" for a classification tree - "anova" for a regression tree
클래스를 예측하기 때문에 클래스 방법을 사용합니다.
library(rpart) library(rpart.plot) fit <- rpart(survived~., data = data_train, method = 'class') rpart.plot(fit, extra = 106)
Code 설명
- rpart(): 모델을 피팅하는 함수입니다. 인수는 다음과 같습니다.
- 살아남았다 ~.: 의사결정나무의 공식
- data = data_train: 데이터세트
- method = 'class': 이진 모델 피팅
- rpart.plot(fit, extra=106): 트리를 그립니다. extra 인수를 106으로 설정하면 두 번째 클래스의 확률과 각 노드에 포함된 관측치의 비율이 표시됩니다. 자세한 내용은 다음을 참조하십시오. 소품 다른 선택 사항에 대한 자세한 내용은
출력:
그래프의 최상단이자 깊이 0(3단계 중)인 루트 노드에서 시작합니다.
- 맨 위에는 전반적인 생존 확률이 있습니다. 이는 충돌 사고에서 살아남은 승객의 비율을 보여줍니다. 승객 중 41%가 생존했다.
- 이 노드는 승객의 성별이 남성인지 묻습니다. 남성인 경우 루트의 왼쪽 자식 노드(깊이 1)로 이동합니다. 해당 노드의 승객 중 63%가 남성이며 생존 확률은 21%입니다.
- 두 번째 노드에서는 남성 승객이 3.5세 이상인지 묻습니다. 그렇다면 생존 확률은 19%다.
- 어떤 기능이 생존 가능성에 영향을 미치는지 이해하기 위해 계속 그렇게 진행합니다.
의사결정나무의 많은 특성 중 하나는 데이터 준비가 거의 필요하지 않다는 것입니다. 특히 기능 확장이나 센터링이 필요하지 않습니다.
기본적으로 rpart() 함수는 다음을 사용합니다. 지니 각 분할을 선택하는 데 사용되는 불순도 측정 지표입니다. 지니 계수 값이 높을수록 해당 노드 내 클래스들이 더 많이 혼합되어 있다는 의미이므로, 알고리즘은 항상 지니 계수를 가장 낮추는 분할을 선택합니다.
5단계) 예측하기
테스트 데이터 세트를 예측할 수 있습니다. 예측을 하려면 예측() 함수를 사용할 수 있습니다. R 의사 결정 트리에 대한 예측의 기본 구문은 다음과 같습니다.
predict(fitted_model, df, type = 'class') arguments: - fitted_model: This is the object stored after model estimation. - df: Data frame used to make the prediction - type: Type of prediction - 'class': for classification - 'prob': to compute the probability of each class - 'vector': Predict the mean response at the node level
이제 테스트 세트에 포함된 209명의 승객 각각에 대해 모델이 그들이 충돌에서 살아남을 것으로 예상하는지 여부를 예측해야 합니다.
predict_unseen <-predict(fit, data_test, type = 'class')
Code 설명
- 예측(fit, data_test, type = 'class'): 테스트 세트의 클래스(0/1)를 예측합니다.
이제 예측된 클래스와 실제 결과를 비교해 보세요.
table_mat <- table(data_test$survived, predict_unseen)
table_mat
Code 설명
- table(data_test$survived, predict_unseen): 예측된 클래스와 실제 결과를 비교하는 분할표를 생성합니다.
출력:
## predict_unseen ## No Yes ## No 106 15 ## Yes 30 58
행은 실제 값이고 열은 예측값입니다. 모델은 생존하지 못한 사람 106명과 생존한 사람 58명을 정확하게 식별했지만, 생존하지 못한 사람 15명을 생존자로, 생존한 사람 30명을 사망한 것으로 잘못 분류했습니다.
6단계) 성과 측정
다음을 사용하여 분류 작업에 대한 정확도 측정값을 계산할 수 있습니다. 혼란 매트릭스:
The 혼란 매트릭스 분류 성능을 평가하는 것이 더 나은 선택입니다. 일반적인 아이디어는 True 인스턴스가 False로 분류된 횟수를 계산하는 것입니다.
혼동 행렬의 각 행은 실제 목표를 나타내고, 각 열은 예측된 목표를 나타냅니다. 이 행렬의 첫 번째 행은 사망한 승객(음성 클래스)을 고려합니다. 106명이 사망으로 정확하게 분류되었습니다.진정한 부정), 15명은 생존자로 잘못 분류되었습니다.거짓 긍정두 번째 행은 생존자를 고려합니다. 58명이 정확하게 식별되었습니다.진정한 긍정), 반면 30건은 누락되었습니다.위음성).
당신은 계산할 수 있습니다 정확도 테스트 혼동 행렬에서:
이는 행렬의 합에 대한 참양성과 참음성의 비율입니다. R을 사용하면 다음과 같이 코딩할 수 있습니다.
accuracy_Test <- sum(diag(table_mat)) / sum(table_mat)
Code 설명
- sum(diag(table_mat)): 대각선의 합
- sum(table_mat): 행렬의 합입니다.
테스트 세트의 정확도를 인쇄할 수 있습니다.
print(paste('Accuracy for test', accuracy_Test))
출력:
## [1] "Accuracy for test 0.784688995215311"
테스트 세트에서의 정확도는 0.7847, 즉 78.47%입니다. 모델이 얼마나 과적합되었는지 확인하기 위해 훈련 세트에서 동일한 과정을 반복해 보세요.
7단계) 초매개변수 조정
R의 의사결정 트리에는 적합도의 측면을 제어하는 다양한 매개변수가 있습니다. rpart 의사결정 트리 라이브러리에서 rpart.control() 함수를 사용하여 매개변수를 제어할 수 있습니다. 다음 코드에서 튜닝할 매개변수를 소개합니다. 다음을 참조할 수 있습니다. 소품 다른 매개변수의 경우.
rpart.control(minsplit = 20, minbucket = round(minsplit/3), maxdepth = 30) Arguments: -minsplit: Set the minimum number of observations in the node before the algorithm perform a split -minbucket: Set the minimum number of observations in a terminal node, i.e. the leaf -maxdepth: Set the maximum depth of any node of the final tree. The root node is treated as depth 0
우리는 다음과 같이 진행합니다:
- 정확도를 반환하는 함수 생성
- 최대 깊이 조정
- 노드가 분할되기 전에 노드에 있어야 하는 최소 샘플 수를 조정합니다.
- 리프 노드에 있어야 하는 최소 샘플 수를 조정합니다.
정확도를 표시하는 함수를 작성할 수 있습니다. 이전에 사용한 코드를 간단히 래핑하면 됩니다.
- 예측: 예측_unseen <- 예측(fit, data_test, 유형 = '클래스')
- 생성 테이블: table_mat <- table(data_test$survived, 예측_unseen)
- 정확도 계산: Accuracy_Test <- sum(diag(table_mat))/sum(table_mat)
accuracy_tune <- function(fit) { predict_unseen <- predict(fit, data_test, type = 'class') table_mat <- table(data_test$survived, predict_unseen) accuracy_Test <- sum(diag(table_mat)) / sum(table_mat) accuracy_Test }
이제 매개변수를 조정하고 기본 모델보다 성능이 향상되는지 확인해 보세요. 정확도는 0.7847을 넘어야 합니다.
control <- rpart.control(minsplit = 4,
minbucket = round(5 / 3),
maxdepth = 3,
cp = 0)
tune_fit <- rpart(survived~., data = data_train, method = 'class', control = control)
accuracy_tune(tune_fit)
출력:
## [1] 0.7990431
다음 매개변수를 사용하여:
minsplit = 4
minbucket = round(5/3)
maxdepth = 3
cp = 0
정확도가 0.7847에서 0.7990으로 향상되었으므로, 조정된 트리는 기본 구성보다 약 1.4%포인트 더 우수합니다.
R에서의 의사결정 트리: 빠른 함수 참조
아래 표는 위의 7단계에서 사용된 모든 함수와 해당 함수를 제공하는 패키지, 그리고 함수가 필요로 하는 매개변수를 나열합니다. R.
| 도서관 | 목표 | 함수 | 클래스 | 파라미터 | 세부 정보 |
|---|---|---|---|---|---|
| 부품 | R의 열차 분류 트리 | 르파트() | 수업 | 수식, df, 방법 | |
| 부품 | 회귀 트리 훈련 | 르파트() | 노바 | 수식, df, 방법 | |
| 부품 | 나무를 그려라 | rpart.plot() | 장착 모델 | ||
| 기지 | 예측 | 예측 () | 수업 | 장착 모델, 유형 | |
| 기지 | 예측 | 예측 () | 조사 | 장착 모델, 유형 | |
| 기지 | 예측 | 예측 () | 벡터 | 장착 모델, 유형 | |
| 부품 | 제어 매개 변수 | rpart.control() | 미스플릿 | 알고리즘이 분할을 수행하기 전에 노드의 최소 관측 수를 설정합니다. | |
| 미니버킷 | 최상위 노드(즉, 리프 노드)의 최소 관측치 수를 설정합니다. | ||||
| 최대 깊이 | 최종 트리의 각 노드에 대한 최대 깊이를 설정합니다. 루트 노드는 깊이가 0으로 간주됩니다. | ||||
| 부품 | 제어 매개변수를 사용하여 모델 학습 | 르파트() | 수식, df, 방법, 제어 |
참고: 훈련 데이터로 모델을 훈련하고 보이지 않는 데이터 세트, 즉 테스트 세트에서 성능을 테스트하십시오.



