Einführung
Der Entscheidungsbaum-Klassifizierer ist ein populares Machine-Learning-Algorithmus, der für Klassifizierungs- und Regressionsprobleme verwendet wird. Es ist ein baum-basiertes Modell, das den Merkmalsraum in eine Reihe von nicht überlappenden Regionen aufteilt und den Zielwert für jede Region vorherzusagt. In diesem Lab werden wir lernen, wie man die Struktur des Entscheidungsbaums analysiert, um weitere Einblicke in die Beziehung zwischen den Merkmalen und dem vorherzusagenden Ziel zu erhalten.
VM-Tipps
Nachdem der VM-Start abgeschlossen ist, klicken Sie in der oberen linken Ecke, um zur Registerkarte Notebook zu wechseln und Jupyter Notebook für die Übung zu öffnen.
Manchmal müssen Sie einige Sekunden warten, bis Jupyter Notebook vollständig geladen ist. Die Validierung von Vorgängen kann aufgrund von Einschränkungen in Jupyter Notebook nicht automatisiert werden.
Wenn Sie bei der Lernphase Probleme haben, können Sie Labby gerne fragen. Geben Sie nach der Sitzung Feedback, und wir werden das Problem für Sie prompt beheben.
Ein Entscheidungsbaum-Klassifizierer trainieren
Zunächst müssen wir einen Entscheidungsbaum-Klassifizierer mit dem load_iris-Datensatz aus scikit-learn anpassen. Dieser Datensatz enthält 3 Klassen mit jeweils 50 Instanzen, wobei jede Klasse auf eine Art von Iris-Pflanze Bezug nimmt. Wir werden den Datensatz in Trainings- und Testsets unterteilen und einen Entscheidungsbaum-Klassifizierer mit maximal 3 Blättern anpassen.
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
iris = load_iris()
X = iris.data
y = iris.target
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
clf = DecisionTreeClassifier(max_leaf_nodes=3, random_state=0)
clf.fit(X_train, y_train)
Analysiere die Struktur des binären Baums
Der Entscheidungsbaum-Klassifizierer hat ein Attribut namens tree_, das den Zugang zu niedriger Ebene-Attributen wie node_count, der Gesamtzahl der Knoten, und max_depth, der maximalen Tiefe des Baums, ermöglicht. Es speichert auch die gesamte binäre Baumstruktur, dargestellt als eine Anzahl paralleler Arrays. Mit diesen Arrays können wir die Baumstruktur durchlaufen, um verschiedene Eigenschaften wie die Tiefe jedes Knotens und ob er ein Blatt ist, zu berechnen. Folgender Code berechnet diese Eigenschaften:
import numpy as np
n_nodes = clf.tree_.node_count
children_left = clf.tree_.children_left
children_right = clf.tree_.children_right
feature = clf.tree_.feature
threshold = clf.tree_.threshold
node_depth = np.zeros(shape=n_nodes, dtype=np.int64)
is_leaves = np.zeros(shape=n_nodes, dtype=bool)
stack = [(0, 0)] ## starte mit der Wurzelknoten-ID (0) und ihrer Tiefe (0)
while len(stack) > 0:
## `pop` stellt sicher, dass jeder Knoten nur einmal besucht wird
node_id, depth = stack.pop()
node_depth[node_id] = depth
## Wenn das linke und rechte Kind eines Knotens nicht gleich ist, haben wir
## einen Split-Knoten
is_split_node = children_left[node_id]!= children_right[node_id]
## Wenn es sich um einen Split-Knoten handelt, füge linkes und rechtes
## Kind und Tiefe zur `stack` hinzu, damit wir durch sie iterieren können
if is_split_node:
stack.append((children_left[node_id], depth + 1))
stack.append((children_right[node_id], depth + 1))
else:
is_leaves[node_id] = True
print(
"Die binäre Baumstruktur hat {n} Knoten und hat die "
"folgende Baumstruktur:\n".format(n=n_nodes)
)
for i in range(n_nodes):
if is_leaves[i]:
print(
"{space}node={node} ist ein Blattknoten.".format(
space=node_depth[i] * "\t", node=i
)
)
else:
print(
"{space}node={node} ist ein Split-Knoten: "
"gehen Sie zu Knoten {left}, wenn X[:, {feature}] <= {threshold} "
"sonst zu Knoten {right}.".format(
space=node_depth[i] * "\t",
node=i,
left=children_left[i],
feature=feature[i],
threshold=threshold[i],
right=children_right[i],
)
)
Visualisiere den Entscheidungsbaum
Wir können den Entscheidungsbaum auch mit der plot_tree-Funktion aus dem tree-Modul von scikit-learn visualisieren.
from sklearn import tree
import matplotlib.pyplot as plt
tree.plot_tree(clf)
plt.show()
Entscheidungsweg und Blattknoten abrufen
Wir können den Entscheidungsweg von interessierenden Proben mit der decision_path-Methode abrufen. Diese Methode gibt eine Indikatormatrix aus, die uns ermöglicht, die Knoten zu ermitteln, durch die die interessierenden Proben gehen. Die Blatt-IDs, die von interessierenden Proben erreicht werden, können mit der apply-Methode erhalten werden. Dies gibt ein Array der Knoten-IDs der Blätter zurück, die von jeder interessierenden Probe erreicht werden. Mit den Blatt-IDs und der decision_path können wir die Aufteilungsbedingungen ermitteln, die zur Vorhersage einer Probe oder einer Gruppe von Proben verwendet wurden. Folgender Code ruft den Entscheidungsweg und die Blattknoten für eine Probe ab:
node_indicator = clf.decision_path(X_test)
leaf_id = clf.apply(X_test)
sample_id = 0
## erhalte IDs der Knoten, durch die `sample_id` geht, d.h., Zeile `sample_id`
node_index = node_indicator.indices[
node_indicator.indptr[sample_id] : node_indicator.indptr[sample_id + 1]
]
print("Regeln, die zur Vorhersage von Probe {id} verwendet werden:\n".format(id=sample_id))
for node_id in node_index:
## gehe zum nächsten Knoten, wenn es ein Blattknoten ist
if leaf_id[sample_id] == node_id:
continue
## überprüfe, ob der Wert der aufgeteilten Eigenschaft für Probe 0 unter der Schwelle liegt
if X_test[sample_id, feature[node_id]] <= threshold[node_id]:
threshold_sign = "<="
else:
threshold_sign = ">"
print(
"Entscheidungsknoten {node} : (X_test[{sample}, {feature}] = {value}) "
"{inequality} {threshold})".format(
node=node_id,
sample=sample_id,
feature=feature[node_id],
value=X_test[sample_id, feature[node_id]],
inequality=threshold_sign,
threshold=threshold[node_id],
)
)
Bestimme gemeinsame Knoten für eine Gruppe von Proben
Für eine Gruppe von Proben können wir die gemeinsamen Knoten bestimmen, durch die die Proben gehen, indem wir die decision_path-Methode und die toarray-Methode verwenden, um die Indikatormatrix in ein dichtes Array umzuwandeln.
sample_ids = [0, 1]
## boolescher Array, das die Knoten angibt, durch die beide Proben gehen
common_nodes = node_indicator.toarray()[sample_ids].sum(axis=0) == len(sample_ids)
## erhalte Knoten-IDs mithilfe der Position im Array
common_node_id = np.arange(n_nodes)[common_nodes]
print(
"\nDie folgenden Proben {samples} teilen die Knoten {nodes} im Baum.".format(
samples=sample_ids, nodes=common_node_id
)
)
print("Dies entspricht {prop}% aller Knoten.".format(prop=100 * len(common_node_id) / n_nodes))
Zusammenfassung
In diesem Lab haben wir gelernt, wie man die Struktur des Entscheidungsbaums analysiert, um weitere Einblicke in die Beziehung zwischen den Merkmalen und der Zielvariable zu erhalten, die vorhergesagt werden soll. Wir haben gesehen, wie man die binäre Baumstruktur abruft, den Entscheidungsbaum visualisiert und den Entscheidungsweg und die Blattknoten für eine einzelne Probe oder eine Gruppe von Proben abruft. Diese Techniken können uns helfen, besser zu verstehen, wie der Entscheidungsbaum-Klassifizierer seine Vorhersagen trifft, und uns dabei unterstützen, das Modell zu optimieren, um seine Leistung zu verbessern.