R のデシジョン ツリー: 例を含む分類ツリー

⚡ スマートサマリー

R言語の決定木は、単純なイエス・ノーのルールを用いてデータを枝に分割し、各葉が単一の支配的なクラスを持つまで続けます。このチュートリアルでは、タイタニック号生存データセットに対して、rpart分類木を構築、プロット、評価、および調整します。

  • 🌳 コア定義: ツリーは予測変数空間を再帰的に分割し、各ノードでクラスの不純度を最も低減する分割を選択する。
  • 🔄 データの準備: 順序付けられたタイタニックファイルを sample() でシャッフルし、識別子列を削除し、因子を変換し、NA 行を削除します。
  • 🛠️ モデル構文: rpart(survived~., data = data_train, method = 'class') を呼び出し、rpart.plot(fit, extra = 106) で結果をレンダリングします。
  • ⚙️ チューニング: rpart.control() は minsplit、minbucket、maxdepth、cp を公開し、精度を 79.90 パーセントに向上させます。
  • 📊 評価: table() 関数を使って混同行列を作成し、対角線を合計で割ると、テスト精度は 78.47% になります。

R のデシジョン ツリー

ディシジョン ツリーとは何ですか?

決定木 決定木は、分類と回帰の両方のタスクを実行できる汎用性の高い機械学習アルゴリズムです。複雑なデータセットにも適合できる非常に強力なアルゴリズムです。さらに、決定木はランダムフォレストの基本的な構成要素であり、ランダムフォレストは現在利用可能な最も強力な機械学習アルゴリズムの1つです。

コードで構築する前に、ツリーがどこで分岐するかをどのように決定するのかを知っておくと役立ちます。

決定木はどのように機能するのでしょうか?

決定木は、データセットを、3 種類のノードから構築されたイエスまたはノーの質問のフローチャートに変換します。 ルート すべてのトレーニング観察を保持し、 内部ノード 1 つの予測変数について質問し、データを 2 つに分割します。 葉っぱ 分割を停止し、多数派クラスを返します。

成長は貪欲法と呼ばれる手順に従います 再帰的二分分割:

  1. すべての候補者の内訳を評価する。 各予測変数とカットオフポイントについて、結果として得られる2つのグループの純度がどの程度低いかを測定する。
  2. 一番良いものを残しなさい。 不純物を最も低減する分割方法が、そのノードで問われる問題となる。
  3. 子供一人一人に対してこれを繰り返す 制御ルール(minsplit、minbucket、maxdepth、またはcp)によって停止されるまで。
  4. プルーン。 cpは、費用対効果のない枝を剪定することで、ツリーがトレーニングセットを記憶するのを防ぎます。

各質問は1つの変数を閾値と比較するため、このアルゴリズムはスケーリングやダミーコーディングを必要としません。

決定木におけるジニ係数とエントロピーの比較

その不純物は2つの方法で測定でき、rpartではどちらかを選択できます。

基準 ジニ指数 エントロピー(情報利得)
式 1 – クラス比率の二乗の合計 -p と log2(p) の合計
範囲(2クラス) 0〜0.5 0〜1
計算 より速く、対数なし 処理速度が遅く、対数を使用します。
rpart設定 デフォルト parms = list(split = “information”)
fit_entropy <- rpart(survived~., data = data_train, method = 'class',
    parms = list(split = "information"))

実際には、どちらの基準もほとんどの場合同じ分割結果を示すため、デフォルトのジニ係数は安全な選択肢と言える。

決定木の利点と欠点

トレードオフを考慮することで、単一のツリーで十分な場合と、複数のツリーを組み合わせたアンサンブルに移行すべき場合が分かります。

優位性

  • 完全に解釈可能: 適合モデルは、あらゆる関係者が理解できる図である。
  • 最小限の前処理: スケーリングや正規化は不要で、係数はそのまま機能します。
  • 両方のタスクを処理します。 method = 'class' は分類器に適合し、method = 'anova' は回帰木に適合します。
  • トレーニングが速い: 大規模なデータセットも数秒で処理できるため、ツリー構造は有用な最初の基準となる。

デメリット

  • 高い分散: 訓練データにわずかな変更を加えるだけで、全く異なるツリーが生成される可能性がある。
  • 過学習を起こしやすい: 制約のない木は、cpとmaxdepthによって制限されない限り、すべての葉が純粋になるまで成長します。
  • 軸に平行な分割のみ: 斜めの境界線には、階段状の切り込みを多数入れる必要がある。

最初の 2 つの弱点に対する対策は、多くの木を平均化することです。 ランダムフォレスト ありません。

R言語で決定木を学習および可視化する方法

Rで最初の決定木を作成するには、次の7つのステップを実行します。

  • ステップ 1: データをインポートする
  • ステップ 2: データセットをクリーンアップする
  • ステップ 3: トレーニング/テスト セットを作成する
  • ステップ 4: モデルを構築する
  • ステップ 5: 予測を立てる
  • ステップ6:パフォーマンスを測定する
  • ステップ 7: ハイパーパラメータを調整する

ステップ 1) データをインポートする

タイタニック号の運命に興味がある場合は、このビデオをご覧ください。 Youtube。 このデータセットの目的は、氷山との衝突後にどの人が生き残る可能性が高いかを予測することです。 データセットには 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 の乗客の特徴を決して認識しないことを意味します。この間違いにより、予測が不十分になります。

この問題を解決するには、sample() 関数を使用します。

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値が含まれています。クリーンアップ処理は3つの段階で実行されます。

  • 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, Cabinet, 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')): 変数 survivald にラベルを追加します。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) トレーニング/テスト セットを作成する

モデルをトレーニングする前に、次の XNUMX つの手順を実行する必要があります。

  • トレーニング セットとテスト セットを作成する: トレーニング セットでモデルをトレーニングし、テスト セットで予測をテストします (つまり、未確認のデータ)。
  • コンソールから rpart.plot をインストールします

一般的な方法は、データを 80/20 に分割し、データの 80 パーセントをモデルのトレーニングに使用し、20 パーセントを予測に使用することです。 XNUMX つの別々のデータ フレームを作成する必要があります。 モデルの構築が完了するまでは、テスト セットには触れたくないでしょう。 XNUMX つの引数を取る関数名 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: XNUMX行目から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列です。

関数 prop.table() を 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 に設定されており、2 番目のクラスの確率と各ノードの観測値の割合が表示されます。 ビネット 他の選択肢について詳しくは、こちらをご覧ください。

出力:

 R で決定木のモデルを構築する

グラフの最上部にあるルートノードから開始し、深さ0(全3階層)から始めます。

  1. 一番上は全体的な生存確率です。 事故で生き残った乗客の割合を示します。 乗客の41パーセントが生存した。
  2. このノードは、乗客の性別が男性かどうかを尋ねます。もしそうであれば、ルートの左の子ノード(深さ1)に進みます。63%が男性で、生存確率は21%です。
  3. 3.5 番目のノードでは、男性乗客の年齢が 19 歳以上かどうかを尋ねます。 もしそうなら、生存の可能性はXNUMXパーセントです。
  4. どのような特徴が生存の可能性に影響を与えるかを理解するために、このような作業を続けます。

デシジョン ツリーの多くの特徴の XNUMX つは、データの準備がほとんど必要ないことです。 特に、フィーチャのスケーリングやセンタリングは必要ありません。

デフォルトでは、rpart() 関数は ジーニ 不純度の尺度を用いて各分割を選択します。ジニ係数が高いほど、そのノード内のクラスの混合度が高いことを意味するため、アルゴリズムは常にジニ係数が最も低くなる分割を選択します。

ステップ 5) 予測を立てる

テスト データセットを予測できます。 予測を行うには、predict() 関数を使用できます。 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 説明

  • detect(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) パフォーマンスを測定する

分類タスクの精度尺度を計算するには、 混同行列:

その 混同行列 分類パフォーマンスを評価するには、これがより良い選択です。 一般的な考え方は、True インスタンスが False に分類される回数をカウントすることです。

R の決定木のパフォーマンスを測定する

混同行列の各行は実際のターゲットを表し、各列は予測されたターゲットを表します。この行列の最初の行は、死亡した乗客(ネガティブクラス)を考慮しています。106人が死亡と正しく分類されました(真陰性15人が生存者として誤って分類されたが、偽陽性2行目は生存者について検討しています。58人が正しく識別されました(真陽性)一方、30人が見逃された(偽陰性).

計算できます 精度テスト 混同行列から:

R の決定木のパフォーマンスを測定する

これは、行列の合計に対する真の陽性と真の陰性の割合です。 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

以下のように進めていきます。

  • 精度を返す関数を構築する
  • 最大深度を調整する
  • ノードを分割する前にノードに必要なサンプルの最小数を調整します。
  • リーフノードに必要なサンプルの最小数を調整する

精度を表示する関数を作成できます。 以前に使用したコードをラップするだけです。

  1. 予測:predict_unseen <- 予測(fit, data_test, type = 'class')
  2. テーブルの生成: table_mat <- table(data_test$survived, detect_unseen)
  3. 精度の計算: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.

図書館 DevOps Tools Engineer試験のObjective 演算 CLASS 技術パラメータ Details
パーツ R で分類ツリーを訓練する rpart() class 式、DF、メソッド
パーツ 回帰ツリーを訓練する rpart() 分散分析 式、DF、メソッド
パーツ 木を植える rpart.plot() フィットモデル
ベース 予測する predict() class 適合モデル、タイプ
ベース 予測する predict() PROB 適合モデル、タイプ
ベース 予測する predict() ベクトル 適合モデル、タイプ
パーツ 制御パラメータ rpart.control() ミンスプリット アルゴリズムが分割を実行する前に、ノード内の観測の最小数を設定します。
最小バケット 末端ノード(つまりリーフノード)の最小観測数を設定します。
最大深度 最終ツリーの任意のノードの最大深度を設定します。ルートノードは深度0として扱われます。
パーツ 制御パラメーターを使用してモデルをトレーニングする rpart() 数式、DF、メソッド、コントロール

注: トレーニング データでモデルをトレーニングし、目に見えないデータセット、つまりテスト セットでパフォーマンスをテストします。

よくあるご質問

どちらも分類木と回帰木に適合します。rpart() は、cp による組み込みの交差検証剪定を備えた CART を実装しており、rpart.plot と組み合わせて明確な図を作成できるため、より一般的な選択肢となっています。

cp は、分割が維持されるために必要な最小限の改善値を設定します。値が大きいほど積極的に枝刈りが行われ、生成されるツリーは小さくなります。printcp() と plotcp() を使用して、交差検証誤差が最小となる値を見つけてください。

はい。rpart() は、予測変数に欠損値がある観測値を最も類似した分岐に振り分けるために、代理分割を使用します。このチュートリアルでは、サンプルデータセットをシンプルに保つためだけに、代わりに na.omit() を呼び出しています。

決定木は、信用、保険、医療などの分野における説明可能なAIの基盤となっており、規制当局が決定の背後にある正確な理由を要求する場合がある。また、勾配ブースティングやランダムフォレストモデルにおける基本的な学習器としても用いられる。

はい。AIアシスタントは、分割ルールを分かりやすい言葉に翻訳したり、テストするcp値を提案したり、printcp()の出力で過学習を警告したりできます。提案を実行する前に、必ずご自身のクロスバリデーション結果と照らし合わせて確認してください。