xgboost

Published

March 31, 2026

パッケージの概要

xgboostパッケージは、勾配ブースティング決定木(Gradient Boosting Decision Tree, GBDT)を高速に実装したパッケージとなります。分類問題、回帰問題のどちらの問題にも対応可です。

使用例(分類問題):PimaIndiansDiabetesデータの分類

PimaIndiansDiabetesデータを用いて、種々の項目からその患者が糖尿病患者であるかを判定するGBDTモデルを構築します。

データの確認

library(mlbench)
data(PimaIndiansDiabetes)
df <- PimaIndiansDiabetes
tar.idx <- 9

データの中身の確認です。(head)

head(df)
  pregnant glucose pressure triceps insulin mass pedigree age diabetes
1        6     148       72      35       0 33.6    0.627  50      pos
2        1      85       66      29       0 26.6    0.351  31      neg
3        8     183       64       0       0 23.3    0.672  32      pos
4        1      89       66      23      94 28.1    0.167  21      neg
5        0     137       40      35     168 43.1    2.288  33      pos
6        5     116       74       0       0 25.6    0.201  30      neg

データの中身の確認です。(str)

str(df)
'data.frame':   768 obs. of  9 variables:
 $ pregnant: num  6 1 8 1 0 5 3 10 2 8 ...
 $ glucose : num  148 85 183 89 137 116 78 115 197 125 ...
 $ pressure: num  72 66 64 66 40 74 50 0 70 96 ...
 $ triceps : num  35 29 0 23 35 0 32 0 45 0 ...
 $ insulin : num  0 0 0 94 168 0 88 0 543 0 ...
 $ mass    : num  33.6 26.6 23.3 28.1 43.1 25.6 31 35.3 30.5 0 ...
 $ pedigree: num  0.627 0.351 0.672 0.167 2.288 ...
 $ age     : num  50 31 32 21 33 30 26 29 53 54 ...
 $ diabetes: Factor w/ 2 levels "neg","pos": 2 1 2 1 2 1 2 1 2 2 ...

各変数の意味は以下の通りです。

変数名 データ型 概要
pregnant    num 妊娠回数    
glucose num 血漿グルコース濃度(負荷試験)
pressure     num 拡張期血圧 [mm Hg]    
triceps      num 上腕三頭筋皮膚襞の厚さ [mm ]
insulin      num 2時間血清インスリン [mu U/ml]
mass num BMI   
pedigree num 糖尿病血統機能
age num 年齢
diabetes Factor クラス変数(糖尿病の検査)

summaryを表示します。

summary(df)
    pregnant         glucose         pressure         triceps     
 Min.   : 0.000   Min.   :  0.0   Min.   :  0.00   Min.   : 0.00  
 1st Qu.: 1.000   1st Qu.: 99.0   1st Qu.: 62.00   1st Qu.: 0.00  
 Median : 3.000   Median :117.0   Median : 72.00   Median :23.00  
 Mean   : 3.845   Mean   :120.9   Mean   : 69.11   Mean   :20.54  
 3rd Qu.: 6.000   3rd Qu.:140.2   3rd Qu.: 80.00   3rd Qu.:32.00  
 Max.   :17.000   Max.   :199.0   Max.   :122.00   Max.   :99.00  
    insulin           mass          pedigree           age        diabetes 
 Min.   :  0.0   Min.   : 0.00   Min.   :0.0780   Min.   :21.00   neg:500  
 1st Qu.:  0.0   1st Qu.:27.30   1st Qu.:0.2437   1st Qu.:24.00   pos:268  
 Median : 30.5   Median :32.00   Median :0.3725   Median :29.00            
 Mean   : 79.8   Mean   :31.99   Mean   :0.4719   Mean   :33.24            
 3rd Qu.:127.2   3rd Qu.:36.60   3rd Qu.:0.6262   3rd Qu.:41.00            
 Max.   :846.0   Max.   :67.10   Max.   :2.4200   Max.   :81.00            

その他のPimaIndiansDiabetesデータのEDA(探索的データ解析)については他のパッケージのコード活用例を参照ください。

各種手法計算用の関数を定義します。

create_df_res <- function(cmat){
  TN <- cmat[1,1]
  FP <- cmat[1,2]
  FN <- cmat[2,1]
  TP <- cmat[2,2]
  
  # 正解率:どれだけ正しく分類できたかの割合
  acc <- round((TP + TN) / (TP + TN + FN + FP), 3)
  
  # 適合率:陽性と判定されたものがどれだけ正しく陽性であるかの割合
  prec <- round(TP / (TP + FP), 3)
  
  # 再現率(真陽性率):実際に陽性のものをどれだけ正しく陽性と判定できたかの割合
  rec <- round(TP / (TP + FN), 3)
  
  # F値:適合率と再現率の調和平均(両者はトレードオフの関係)
  Fval <- round(2 * rec * prec / (rec + prec), 3)
  
  # 真陰性率:実際に陰性のものをどれだけ正しく陰性と判定できたかの割合
  TNRat <- round(TN / (TN + FP), 3)
  
  df_rat <- data.frame(
    Item = c("正解率", "適合率", "再現率(真陽性率)", "F値", "真陰性率"), 
    Rate = c(acc, prec, rec, Fval, TNRat)
  )
  
  df_rat
}

data.frameの出力整形用の関数を定義します。

library(knitr)
library(kableExtra)

show_df <- function(df, cap=""){
  if(is_html_output()){
    kable(df, format = "html", caption = cap) %>%
      kable_styling(bootstrap_options = "striped", full_width = FALSE, position = "left")
  }else{
    kable(df, format = "pipe", caption = cap) 
  }
}

PimaIndiansDiabetesデータを、モデル生成のための訓練データとモデル評価のためのテストデータに分割します。データ割合は、訓練データ7割・テストデータ3割とします。確認のためにデータサイズを出力します。

# 再現性のためにシードを設定
set.seed(123)  

# データの分割
sample_indices <- sample(1:nrow(df), 0.7 * nrow(df))  
train_data <- df[sample_indices, ]
test_data <- df[-sample_indices, ]

# データサイズの確認
c(nrow(df), nrow(train_data), nrow(test_data))
[1] 768 537 231

モデルの構築

訓練データを用いてGBDTモデルを構築します。

library(xgboost)

データを準備します。データはxgboostで使用されるxgb.DMatrix型とします。全てのデータは数値でなくてはならない点にご注意ください。因子型(Factor)もNGとなります。目的変数は1:陰性・2:陽性ですが、扱いやすくするため-1して0:陰性・1:陽性として扱うことにします。

train_X <- as.matrix(train_data[-tar.idx])
train_y <- as.numeric(train_data[[tar.idx]]) - 1
dtrain <- xgb.DMatrix(data = train_X, label = train_y)

モデルを設定します。目的関数はparamsのobjectiveとして設定します。今回は二値の分類問題であるので”binary:logistic”を使用します。

model <- xgb.train(
  data = dtrain,
  nrounds = 100,
  params = list(objective = "binary:logistic", eval_metric = "logloss")
)

テストデータでの結果を確認します。こちらもまずはデータを準備します。

test_X <- as.matrix(test_data[-tar.idx])
res_act <- as.numeric(test_data[[tar.idx]]) - 1

予測結果を変数に格納します。結果は数値(小数)になっているため、分類(0 or 1)に変更します。

res_pred <- predict(model, as.matrix(test_X))
res_pred <- ifelse(res_pred > 0.5, 1, 0)

実際の結果と予測結果を比較できる混同行列を出力します。

(conf_mat <- table(res_act, res_pred))
       res_pred
res_act   0   1
      0 124  26
      1  32  49

評価指標を確認します。他のコード活用例との比較として、tuneRangerを用いてチューニングしたmlrの分類木において正解率0.719・F値0.545でしたので、高いモデル性能であることが分かります。

df_res <- create_df_res (conf_mat)
show_df(df_res)
Item Rate
正解率 0.749
適合率 0.653
再現率(真陽性率) 0.605
F値 0.628
真陰性率 0.827

ハイパーパラメータのチューニング

xgboostにおいてGBDT構築に使用される主なハイパーパラメータは以下の通りです。

パラメータ名 概要
eta    学習率(η)  
nrounds 作成する木の本数
min_child_weight 葉に必要な最小重み    
max_depth 木の高さ    
gamma 木の分割時に必要な最小改善量

このうち、max_depthの違いによるモデルの差を見てゆきます。まずはmax_depthを引数として訓練、性能検証を一度にやってくれる関数を作成します。

train_test.max_depth <- function(max_depth_){
  model <- xgb.train(
    data = dtrain,
    nrounds = 100,
    params = list(max_depth = max_depth_, objective = "binary:logistic", eval_metric = "logloss")
  )

  res_pred <- predict(model, as.matrix(test_X))
  res_pred <- ifelse(res_pred > 0.5, 1, 0)
  conf_mat <- table(res_act, res_pred)
  df_res <- create_df_res (conf_mat)
  
  df_res
}

max_depthを4, 6, 8, 10と変えたときのモデル性能を比較します。max_depthが8のときに正解率やF値が最も高くなっています。

n_loop <- 4
n_row  <- 5 

df_list <- vector("list", n_loop)

for (i in seq_len(n_loop)) {
  depth <- 4 + 2 * (i - 1)
  df_res <- train_test.max_depth(depth)
  df_list[[i]] <- df_res
  colnames(df_list[[i]])[2] <- paste0("depth = ", depth)
}

df_all <- Reduce(
  function(x, y) merge(x, y, by = "Item", all = TRUE, sort = FALSE),
  df_list
)

show_df(df_all)
Item depth = 4 depth = 6 depth = 8 depth = 10
正解率 0.736 0.749 0.762 0.749
適合率 0.632 0.653 0.659 0.642
再現率(真陽性率) 0.593 0.605 0.667 0.642
F値 0.612 0.628 0.663 0.642
真陰性率 0.813 0.827 0.813 0.807