ディシジョン ツリーの拡大

すべての教師あり ML モデルと同様に、ディシジョン ツリーは一連のトレーニング サンプルを最もよく説明するようにトレーニングされます。ディシジョンツリーの最適なトレーニングは NP 難しい問題ですしたがって、トレーニングは通常、ヒューリスティックを使用して行われます。ヒューリスティックは、簡単に作成できる学習アルゴリズムで、最適ではないものの、最適に近いディシジョン ツリーを提供します。

ディシジョン ツリーのトレーニングに使用されるほとんどのアルゴリズムは、欲張りな分割統治戦略で機能します。このアルゴリズムは、まず単一のノード(ルート)を作成し、ディシジョン ツリーを再帰的かつ強引に拡大します。

各ノードで、考えられるすべての条件が評価され、スコアが付けられます。このアルゴリズムは、「最良」の条件、つまり最も高いスコアを持つ条件を選択します。今のところは、スコアはタスクと相関する指標であり、その指標を最大化する条件が選択されていることだけを覚えておいてください。

たとえば、Palmer Penguins データセット(このコースの後半のコード例で使用します)では、ほとんどの Adelie ペンギンと Chinstrap ペンギンのくちばしの長さは 16 mm を超えていますが、Gentoo ペンギンのほとんどはくちばしが小さいです。したがって、bill_length_mm ≥ 16 という条件は、ジェントゥー ペンギンについてはほぼ完璧な予測を行いますが、アデリースとチンストラップを区別することはできません。アルゴリズムはおそらく、この条件を選択します。

1 つの状態から 2 つのリーフが発生します。条件は「bill_length_mm >= 16」です。
「はい」の場合、葉は「Adelie or Chinstrap」です。そうでない場合、葉は「Gentoo」です。

図 7. 木を育てるための最初のステップです。

 

その後、アルゴリズムが両方の子ノードで再帰的かつ独立して繰り返されます。条件を満たす条件が見つからなければ、ノードはリーフになります。リーフ予測は、例で最も代表的なラベル値として決定されます。

アルゴリズムは次のとおりです。

def train_decision_tree(training_examples):
  root = create_root() # Create a decision tree with a single empty root.
  grow_tree(root, training_examples) # Grow the root node.
  return root

def grow_tree(node, examples):
  condition = find_best_condition(examples) # Find the best condition.

  if condition is None:
    # No satisfying conditions were found, therefore the grow of the branch stops.
    set_leaf_prediction(node, examples)
    return

  # Create two childrens for the node.
  positive_child, negative_child = split_node(node, condition)

  # List the training examples used by each children.
  negative_examples = [example for example in examples if not condition(example)]
  positive_examples = [example for example in examples if condition(example)]

  # Continue the growth of the children.
  grow_tree(negative_child, negative_examples)
  grow_tree(positive_child, positive_examples)

特定のディシジョン ツリーをトレーニングするステップを詳しく見ていきましょう。

ステップ 1: ルートを作成します。

疑問符付きのノード。

ステップ 2: ノード 1 を拡張します。「x1 ≥ 1」という条件が見つかりました。 2 つの子ノードが作成されます。

2 つの未定義のノードにつながるルートノード。

ステップ 3: ノード 2 を拡張します。一致する条件が見つかりませんでした。ノードをリーフにします

2 つの未定義のノードにつながるルートノード。

ステップ 4: ノード 3 を拡張します。"x2 ≥ 0.5" の条件が見つかりました。2 つの子ノードが作成されます。

1 つのルートノード、1 つの条件、3 つのリーフです

ディシジョン ツリーを増やす別の方法も存在します。一般的な代替策は、分割統治戦略を使用するのではなく、ノードをグローバルに最適化することです。

YDF コード
YDF では、ディシジョン ツリーはデフォルトで上記の「欲張りな分割統治」アルゴリズムで成長します。また、growing_strategy="BEST_FIRST_GLOBAL" パラメータを使用してグローバルな拡張を有効にすることもできます。詳細については、 ドキュメントをご覧ください。

入力特徴の数とタイプによっては、特定のノードで考えられる条件の数が膨大になり、通常は無限になる可能性があります。たとえば、しきい値条件 $\mathrm{feature}_i \geq t$ の場合、$t \in \mathbb{R}$ に対して可能なすべてのしきい値の組み合わせは無限です。

最適な条件を見つけるためのルーチンは、スプリッターと呼ばれます。考えられる多くの条件をテストする必要があるため、ディシジョン ツリーをトレーニングする際のボトルネックがスプリッターです。

スプリッターによって最大化されるスコアは、タスクによって異なります。次に例を示します。

  • 情報ゲインGini(どちらも後で説明します)は、一般に分類に使用されます。
  • 回帰には、平均二乗誤差が一般的に使用されます。

スプリッター アルゴリズムは多数あり、それぞれで次のサポートが異なります。

  • 特徴のタイプ(数値、カテゴリ、テキストなど)
  • タスク(バイナリ分類、マルチクラス分類、回帰など)
  • 条件のタイプ(しきい値条件、セット内条件、傾斜条件など)
  • 正則化条件(しきい値条件の厳密なスプリッターや近似スプリッターなど)

さらに、同等のスプリッター バリアントがあり、メモリ使用量、CPU 使用量、計算分散などに関して異なるトレードオフがあります。

YDF コード
YDF では、自動的に検出された(または手動で指定した)特徴のタイプ、ハイパーパラメータ、各スプリッターの推定速度から、スプリッターが暗黙的に選択されます(トレーニング中に、YDF は小規模なモデルを実行して、各候補のスプリッターの速度を予測します)。