ガイド
初期段階で機械学習に関する事前調査を行っており、ランダムフォレストの移行に関する論文のアルゴリズムを再現しましたが、sklearn の決定木の API を継承・拡張する必要があり、そのためには下位構造の理解が必要です。デシジョン ツリーの層が設計され、達成されます。この記事では、この詳細について簡単に紹介し、共有します。
デシジョン ツリーは古典的な機械学習アルゴリズムです。ID3、C4.5、CART など、いくつかのメジャー バージョンの反復を経ています。sklearn に構築されたデシジョン ツリーの実装は、主に標準の CART ツリーに基づいていますが、いくつかの違いがあります。原理の詳細、決定木のアルゴリズム原理については、過去の記事:楽しい!を参照してください。決定木の基本原理を 5000 語でわかりやすく説明します。デシジョン ツリーは、分類と回帰の両方に使用できます。同時に、多くの統合アルゴリズムの基礎を構成するため、機械学習の分野で重要な役割を果たします。統合アルゴリズムについては、過去の記事を参照してください。画像は機械学習の紹介、アンサンブル学習アルゴリズム。
分類デシジョン ツリーを例として、sklearn のデシジョン ツリーがどのように設計および実装されているかを調査するには、まずどの属性とインターフェイスがデシジョン ツリーに組み込まれているかを確認します。 dir 属性を使用して、どの属性がデシジョン ツリーに含まれているかを確認します。初期決定ツリー (ここでは、「_」で始まる属性は通常、組み込みのプライベート属性であるため、フィルターで除外されます)、結果は次のとおりです。
上記のインターフェイスは、主に属性と関数の 2 つのカテゴリに分類されます (これはナンセンスのようです。プログラミング言語のクラスの定義を理解している人は誰でも、クラスには主に属性と関数が含まれていることを知っています。属性は値に対応し、機能は機能の達成に対応します)。どれが属性でどれが関数であるかを明確に区別する必要がある場合は、ipython インタープリターのオートコンプリート機能を使用できます。
上記の結果をざっと見てみると、属性は主に ccp_alpha: 枝刈り係数、class_weight: クラスの重み、criterion: 分割基準など、決定木の初期化時のパラメータであり、その他に主な機能も実装されています。決定木 (fit: モデルのトレーニング、predict: モデルの予測など) によって決定されます。
この記事の焦点は、トレーニングされた「ツリー」をデシジョン ツリーに保存する方法を検討することです。そのため、さらに iris データ セットを使用してデシジョン ツリーをトレーニングし、再度 dir 関数を呼び出して、どのような属性とインターフェイスが保存されたかを確認します。追加した:
セットの差分セットを通じて、トレーニング前後のデシジョン ツリーに主に 6 つの属性 (関数ではなくすべての属性) が追加されていることは明らかであり、属性名からその意味を推測するのは簡単です。
classes_: 分類ラベルの値、つまり y の一意の値セット
max_features_: 特徴の最大数
n_classes_: カテゴリの数 (2 カテゴリや複数カテゴリなど)、つまり、classes_ 属性の長さ
n_features_in_: 古いバージョンの sklearn の n_features_ に相当する入力特徴の数は非推奨となり、n_features_in_ が推奨されます
n_outputs: 複数の出力の数、つまり決定木は、単一の分類問題を実装するために使用できるだけでなく、複数の分類問題を同時に実装することもできます。たとえば、一連の文字特性が与えられた場合、これは次の目的で使用されます。男性か女性か、太っているか痩せているか、背が高いかを同時に判断する3つの分類問題、つまり3つの出力です(多分類と多出力のタスクを区別する必要があります)
Tree_: この Tree_ が今日のこの記事の焦点であることは間違いありません。これは、デシジョン ツリーのトレーニング後に設定される新しい属性であり、デシジョン ツリーがどのように保存されるかを格納します。
次に、tree_ 属性をさらに調べてみましょう。まず、tree_ 属性を出力して、これが Tree オブジェクトであることを確認し、sklearn でファイル パスを指定します。
help メソッドを通じて Tree クラスの概要を確認できます。
上記のドキュメント文書の最初の文では、決定ツリーについて次のように明確に説明されています。
バイナリ決定木の配列ベースの表現。
つまり、配列表現に基づくバイナリ分類決定木、つまりバイナリ ツリーです。また、この二分木において、配列のi番目の要素は決定木のi番目のノードの情報を表し、ノード0は決定木のルートノードを表す。では、各ノードにはどのような情報が含まれているのでしょうか? 上記のドキュメントにノードのファイル名がリストされていることに気付きました: _tree.pxd. これを見ると、ノードの定義が次のとおりであることが簡単にわかります。
これは cython の定義構文ですが、その属性フィールドの型と意味を推測するのは難しくありません。次に例を示します。
left_child: 現在のノードの左側の子ノードのインデックスを表すサイズ タイプ (符号なし整数)
right_child: left_child に似ています
feature: サイズ タイプ。現在のノードが分割に使用する特徴インデックスを表します。つまり、トレーニング セット内の分割に特徴のどの列が使用されるかを表します。
しきい値: double 型で、現在のノードが対応する特徴を選択するときの分割しきい値を表します。通常、このしきい値以下の場合は左の子ノードに入り、それ以外の場合は右の子ノードに入ります。
n_node_samples: サイズ タイプ。トレーニング中にノードに入るサンプルの総数を表します。明らかに、親ノードの n_node_samples は、その左右の子ノードの n_node_samples の合計に等しくなります。
これまでのところ、デシジョン ツリー内の単一ノードの属性定義と実装は基本的に推論されていますが、デシジョン ツリー全体はどのようにしてすべてのノードを結び付けるのでしょうか? トレーニング済みデシジョン ツリーの Tree_ 属性を再度使用して、どのようなインターフェイスがあるかを確認し、さらに組み込みのプライベート属性をフィルターで除外して、次の結果を取得します。
もちろん、ipython インタープリターのオートコンプリート機能を使用して、各インターフェイスが属性であるか関数であるかをさらに確認することもできます。
これらの属性の多くは、ノード定義の前の説明で説明されていますが、ここでは次の属性値に注目する必要があります。
node_count: デシジョンツリー内のノードの総数
Children_left: 各ノードの左側の子の配列
Children_right: 各ノードの右側の子の配列
機能: 各ノードは分割機能インデックス配列を選択します
しきい値: 各ノードは分割特徴しきい値配列を選択します
値: 各ノードに分類される各タイプのサンプル数の統計
n_leaves: リーフノードの総数
おそらく、より重要なのはこれらです。各属性のデータがどのように格納されるかをさらに理解するために、例としてアヤメのデータ セットを取り上げ、max_ Depth = 2 (ルート ノードは Depth = 0 に対応) でデシジョン ツリーをトレーニングし、次の値を確認します。
次のことがわかります。
トレーニングされたデシジョン ツリーには、3 つのリーフ ノードを含む 5 つのノードが含まれます。
Children_left と Children_right の 2 つの属性により、0 番目のノード (つまり、ルート ノード) の左側の子ノード インデックスが 1、右側の子ノード インデックスが 2 であることがわかります。最初のノードは両方とも -1 で、これはこのノードがリーフ ノードであることを意味します。2 番目のノードの左側と右側の子ノードはそれぞれ 3 と 4 で、内部ノードでありさらに分割されていることを示します。
特徴としきい値の 2 つの属性を通じて、0 番目のノード (ルート ノード) はインデックス 3 の特徴 (4 列目の特徴に対応) を使用して分割されており、その最適なセグメンテーションしきい値は 0.8 であることがわかります。1 番目のノードは次の理由によります。これはリーフ ノードであるため、分割されておらず、対応する特徴フィールドとしきい値フィールドは両方とも -2 です。
value 属性を通じて、各ノードに該当するさまざまなサンプルの数を表示できます。iris データ セットは 3 カテゴリの問題であり、デシジョン ツリーには 5 つのノードがあるため、value の値は 5×3 の 2 次元です。たとえば、配列の最初の行は、ルート ノードに含まれるサンプル数が [50, 50, 50] であることを表し、2 行目は、左の子ノードに含まれるサンプル数が [50, 0, 0] であることを表します。はすでに pure であるため、これ以上の分割は行われません。
さらに、各リーフ ノードに対応するラベル値はツリー内で直接マークされませんが、value 属性を通じて取得できます。つまり、各リーフ ノードで最も多くのサンプルに該当するカテゴリが対応するラベルです。対応するラベルがわかるだけでなく、数字の比率を計算することで対応する確率も得られるとも言われています。
上記の推測を手動で検証するために虹彩データ セットを取得し、分割特徴 3 としきい値 0.8 でルート ノードを分割し、次のように左側の子ノードに該当するサンプルのカウント結果を取得します。 -class サンプルは分割後に残ります。つまり、サンプル数は [50, 0, 0] でまったく同じです。
さらに、2 つの属性 Children_left と Children_right の子ノード間の対応関係を通じて、バイナリ ツリーの走査方法が事前順序走査、つまりルート-左-右の順序であると実際に推論できます。上記の決定木は、分割後の二分木に相当します。概略図は次のとおりです。
関連書籍: