본문 바로가기
Machine Learning/XGBoost

R에서 XGBoost 알고리즘 적용을 위한 데이터세트 이해하기

by 찐남 2021. 8. 31.
본 포스팅은 XGBoost 패키지 홈페이지에 있는 자료를 기반으로 작성하였습니다.

 

Introduction

 

이 포스팅의 목적은 XGBoost를 사용하여 분석을 위한 데이터 세트를 더 잘 탐색하고 이해하는 방법을 보여 주는 것입니다. 이 포스팅은 아무것도 예측하는 것이 아닙니다. XGBoost를 사용하여 데이터의 기능과 결과 간의 연결을 강조하는 방법을 설명합니다.

 

if (!require('xgboost')) install.packages('xgboost')
require(Matrix)
require(data.table)
if (!require('vcd')) install.packages('vcd')

 

(※ VCD 패키지는 포함된 데이터 세트 중 하나에만 사용됩니다.)

 

 

 

 

데이터 세트 준비

 

숫자형 변수 VS 범주형 변수

 

XGBoost는 숫자 벡터만 관리합니다. 그럼 범주형 데이터가 있는 경우 어떻게 해야 할까요? 범주형 변수에는 고정된 수의 다른 값이 있습니다. 예를 들어 Color라는 변수가 빨간색, 파란색 또는 녹색의 세 값 중 하나만 가질 수 있는 경우 Color는 범주형 변수입니다. 

 

R에서 범주형 변수를 factor라고 합니다(factor에 대한 더 자세한 설명은 R console에서 ?factor를 입력하면 알 수 있습니다.). 위의 질문에 답하기 위해 범주형 변수를 숫자형 변수로 변환합니다. 

 

범주형 변수에서 숫자형 변수로의 변환

 

Raw data 탐색

 

이 포스팅에서는 범주형 변수가 있는 조밀한(dense) data.frame(조밀한(dense) = 행렬에서 0이 거의 없음)을 숫자 feature들의 매우 희소한 행렬(sparse matrix, 희소한 = 행렬에서 0이 많음)로 변환하는 방법을 볼 것입니다. 우리가 보게 될 방법은 일반적으로 one-hot encoding이라고 합니다.

 

첫 번째 단계는 관절염 데이터 세트를 메모리에 로드하고 data.table 패키지로 래핑 하는 것입니다.

 

아래 예제 데이터를 다운로드 받으세요.

 

Arthritis.csv
0.00MB

 

 

Arthritis <- read.csv("Arthritis.csv", header = TRUE)
Arthritis$Sex <- as.factor(Arthritis$Sex)
Arthritis$Treatment <- as.factor(Arthritis$Treatment)
Arthritis$Improved <- as.ordered(Arthritis$Improved)
df <- data.table(Arthritis, keep.rownames = FALSE)

 

data.table은 R data.frame과 100% 호환되지만 구문이 더 일관되고 대규모 데이터 세트에 대한 성능이 R의 dplyr 및 Python의 Pandas 포함해서 동급 최고입니다. XGBoost R 패키지의 일부는 data.table을 사용합니다. 

 

데이터를 불러오고 가장 먼저 해야 하는 일은 data.table의 첫 번째 줄을 살펴보는 것입니다. 

 

head(df)

 

 

 

이제 각 열의 형식을 확인합니다.

 

str(df)

 

 

 

2개의 열에는 factor 유형이 있고,  하나는 ordinal(순서형) 유형입니다.

 

ordinal(순서형) 유형: 

  • 제한된 수의 값(예: factor)을 사용할 수 있습니다. 
  • 이 값은 순서가 지정됩니다(fator와 다름).

 

 

 

 

기존 feature를 기반으로 새로운 feature 생성

 

1) 나이를 10년 단위로 그룹화 하기

 

첫 번째 기능의 경우 실제 연령을 반올림하여 연령대를 만듭니다. 이러한 연령대를 factor로 변환해서 알고리즘이 독립적인 값으로 처리하도록 합니다. 이러한 변환에서 연령 간의 거리는 손실됩니다(즉, 정보 손실이 있습니다.).

 

head(df[,AgeDiscret := as.factor(round(Age/10,0))])

 

 

2) 두 그룹으로의 랜덤 분할

 

다음은 30세를 임의로 분할하여 실제 연령을 더욱 강력하게 단순화한 것입니다. 그리고, 아무 근거 없이 이 값을 선택합니다. 임의의 값을 기반으로 정보를 단순화하는 것이 좋은 전략인지는 나중에 알 수 있습니다.

 

head(df[ , AgeCat := as.factor(ifelse(Age > 30, "Old", "Young"))])

 

 

3) 상관관계가 있는 Feature를 추가했을 때의 위험성

 

이러한 새 feature는 기존 feature의 단순 변환이기 때문에 연령 feature와 높은 상관관계가 있습니다. 많은 기계 학습 알고리즘에서 상관 특성을 사용하는 것은 좋은 생각이 아닙니다. 때로는 예측이 덜 정확할 수 있으며 대부분의 경우 모델 해석이 거의 불가능합니다. 예를 들어, GLM은 feature 간의 상관관계가 없다고 가정합니다. 다행히도 decision tree 알고리즘(부스트 트리 포함)은 이러한 기능에 대해 매우 강건합니다. 그러므로 우리는 이 상황을 관리하기 위해 할 일이 없습니다. 

 

데이터 정제

 

ID feature에서 배울 것이 없기 때문에 ID를 제거합니다(일부 노이즈만 추가됨). 

 

df[,ID:=NULL]

 

Treatment 열에 대해 다른 값을 매핑시킵니다. 

 

levels(df[,Treatment])

 

 

One-hot encoding

 

다음 단계에서는 범주형 데이터를 더미 변수로 변환합니다. 이것은 원 핫 인코딩 단계입니다. 목적은 이진 특성 {0, 1}에서 각 범주 특성의 각 값을 변환하는 것입니다. 예를 들어, Treatment 열을 Placebo 및 Treated라는 두 개의 열로 대체합니다. 그들 각각은 바이너리가 될 것입니다. 따라서 변환 전 Treatment 열에 Placebo 값이 있는 observation은 변환 후 새로운 열 Placebo에 값 1을, 새로운 Treated 열에 값 0을 갖습니다. Treatment 열은 원-핫 인코딩 중에 사라집니다. Improved 열은 예측하려는 레이블 열이기 때문에 제외합니다. 

 

sparse_matrix <- sparse.model.matrix(Improved~.-1, data = df)
head(sparse_matrix)

 

 

위에서 사용된 Improved~.-1은 Improved 칼럼을 제외한 모든 범주형 feature들을 이진 값으로 변환하는 것을 의미합니다. -1은 1로 가득 찬 첫 번째 열을 제거하기 위해 여기에 있습니다(이 열은 변환에 의해 생성됨).
자세한 내용을 보려면 콘솔에 ?sparse.model.matrix를 입력해서 확인하시면 됩니다.


output 숫자형 벡터 생성(희소 행렬이 아님):

 

output_vector = df[,Improved] == "0"

 

  1. Y 벡터를 0으로 설정
  2. Improved == "0"이 TRUE인 행에 대해 Y를 1로 설정
  3. Y 벡터 반환

 

 

 

 

모델 생성

 

아래 코드는 매우 유용합니다. 자세한 내용은 xgboost 함수 문서를 보시면 됩니다. 

 

bst <- xgboost(data = sparse_matrix, label = output_vector, eval_metric = "error", max.depth = 4, eta = 1, nthread = 2, nrounds = 10, objective = "binary:logistic")

 

 

숫자 뒤에 표시되는 일부 train-error: 0.XXXXX 행을 볼 수 있습니다. 감소합니다. 각 라인은 모델이 데이터를 얼마나 잘 설명하는지 보여줍니다. 낮을수록 좋습니다. 너무 잘 맞는 모델은 과적합될 수 있습니다. 

 

여기서 숫자가 7행까지 감소한 다음 증가하는 것을 볼 수 있습니다. 그것은 아마도 우리가 과적합되고 있음을 의미할지도 모릅니다. 이 문제를 해결하려면 라운드 수를 nrounds = 4로 줄여야 합니다. 

 

Feature importance

 

feature importance 측정

 

feature importance data.table 빌드하기

 

아래 코드에서 sparse_matrix@Dimnames[[2]]는 희소 행렬의 열 이름을 나타냅니다. 이러한 이름은 feature의 원래 값입니다(각 이진 열 == 하나의 범주형 feature에 하나의 값입니다.). 

 

importance <- xgb.importance(feature_names = sparse_matrix@Dimnames[[2]], model = bst)
head(importance)

 

 

 

Gain 열은 우리가 찾고 있는 정보를 제공합니다. 보시는 것처럼 feature는 Gain별로 분류됩니다.

 

Gain은 feature가 있는 분기에 대한 정확도 향상을 나타냅니다. 그 아이디어는 feature X에 대한 새 분할을 분기에 추가하기 전에 일부 잘못 분류된 요소가 있었고, 이 feature를 분할에 추가한 후 두 개의 새 분기가 생기고, 이 분기 각각이 더 정확하다는 것입니다(한 분기는 다음과 같이 말합니다. 당신의 관찰이 이 분기에 있다면 그것은 1로 분류되어야 하고 다른 분기는 정반대라고 말해야 합니다).

 

Cover는 feature와 관련된 관측치의 상대적인 양을 측정합니다. 

 

Frequency는 Gain을 측정하는 더 간단한 방법입니다. 생성된 모든 트리에서 해당 feature가 사용된 횟수만 계산합니다. 왜 사용해야 하는지 모른다면, 사용하지 말아야 합니다. 

 

Feature Importance 그리기

 

이 모든 것이 좋지만 결과를 그림으로 표현하는 것이 훨씬 더 좋습니다. 

 

xgb.plot.importance(importance_matrix = importance)

 

 

Feature는 2개의 클러스터(흥미로운 기능… 및 기타)로 분할되었습니다. 

 

 

데이터 세트와 학습 매개변수에 따라 클러스터가 3개 이상 있을 수 있습니다.
기본값은 10으로 제한하는 것이지만 이 제한을 늘릴 수 있습니다.

 

위의 도표에 따르면 이 데이터 세트에서 치료 효과를 예측하는 가장 중요한 feature는 다음과 같습니다. 

 

  • 나이
  • 위약을 받았는지 여부
  • 성별은 세 번째이지만 흥미롭지 않은 feature 그룹에 이미 포함되어 있습니다.
  • 그리고 생성된 feature(AgeDiscret)가 표시됩니다. 그들의 기여도가 매우 낮다는 것을 알 수 있습니다.

 

 

 

 

이 결과가 의미가 있습니까?

 

이러한 각 feature와 레이블 사이의 일부 Chi2를 확인해 보겠습니다. 더 높은 Chi2는 더 나은 상관관계를 의미합니다. 

 

c2 <- chisq.test(df$Age, output_vector)
print(c2)

 

 

나이와 질병 소멸 사이의 피어슨 상관관계는 35.48입니다.

 

c2 <- chisq.test(df$AgeDiscret, output_vector)
print(c2)

 

 

Age의 첫 번째 단순화는 Pearson 상관관계가 8.26입니다.

 

c2 <- chisq.test(df$AgeCat, output_vector)
print(c2)

 

 

30세에 젊은이와 노인 사이에 완벽하게 무작위적인 분할로 만든 feature는 2.36의 낮은 상관관계를 가지고 있습니다. 예상할 수 있는 결과입니다. 

 

마치며...

 

방금 살펴본 것처럼, 일반적으로 정보를 단순화하여 정보를 파괴하는 것은 모델을 개선하지 않습니다. Chi2는 단지 그것을 보여주기 위해서 분석한 내용입니다. 그러나 더 복잡한 경우에는 결과와의 연결을 보다 명확하게 하는 기존 feature를 기반으로 새 feature를 만드는 것이 알고리즘에 도움이 되고 모델을 개선할 수 있습니다. 여기에서 연구된 사례는 그것을 보여주기에는 충분히 복잡하지 않습니다. 다른 feature와 상관관계가 높은 유용하지 않은 새 feature를 추가하더라도 부스팅 트리 알고리즘이 가장 좋은 것을 선택할 수 있음을 알 수 있습니다. 이 경우에는 Age입니다. 이 시나리오에서는 feature 간의 독립성을 가정하는 선형 모델은 스마트하게 작동하지 않을 수 있습니다. 

 

 

 

 

 

반응형

댓글