Расстояние между двумя листьями в DecisionTreeClassifier - PullRequest
0 голосов
/ 04 декабря 2018

Есть ли способ вычисления расстояния между двумя листьями в дереве решений .

Под расстоянием я подразумеваю количество узлов, которые нужно пройти от одного листа к другому.

graph

Например, в этом примере график:

distance(leaf1, leaf2) == 1
distance(leaf1, leaf3) == 3
distance(leaf1, leaf4) == 4

Спасибо за любую помощь!

1 Ответ

0 голосов
/ 05 декабря 2018

Пример, использующий дополнительные пакеты Python, а именно networkx и pydot .По этой причине решение щедро комментируется.Вопрос был помечен scikit-learn, поэтому решение представлено на Python.

Некоторые данные и общий DecisionTreeClassifier:

# load example data and classifier
from sklearn.datasets import load_wine
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split

# for determining distance
from sklearn import tree
import networkx as nx
import pydot

# load data and fit a DecisionTreeClassifier
X, y = load_wine(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42)
clf = DecisionTreeClassifier(max_depth=3, random_state=42)
clf.fit(X_train, y_train);

Эта функция преобразует соответствие DecisionTreeClassifier вnetworkx ненаправленный MultiGraph с использованием tree.export_graphviz, pydot.graph_from_dot_data, nx.drawing.nx_pydot.from_pdyot и nx.to_undirected.

def dt_to_mg(clf):
    """convert a fit DecisionTreeClassifier to a Networkx undirected MultiGraph"""
    # export the classifier to a string DOT format
    dot_data = tree.export_graphviz(clf)
    # Use pydot to convert the dot data to a graph
    dot_graph = pydot.graph_from_dot_data(dot_data)[0]
    # Import the graph data into Networkx 
    MG = nx.drawing.nx_pydot.from_pydot(dot_graph)
    # Convert the tree to an undirected Networkx Graph
    uMG = MG.to_undirected()
    return uMG

uMG = dt_to_mg(clf)

Используйте nx.shortest_path_length, чтобы найти расстояние между любыми двумя узлами в дереве.

# get leaves
leaves = set(str(x) for x in clf.apply(X))
print(leaves)
{'10', '7', '9', '5', '3', '4'}

# find the distance for two leaves
print(nx.shortest_path_length(uMG, source='9', target='5'))
5

# undirected graph means this should also work
print(nx.shortest_path_length(uMG, source='5', target='9'))
5

shortest_path_length возвращает числокрая между source и target.Это не метрика расстояния, которую запрашивает OP.Я думаю количество узлов между ними было бы просто n_edges - 1.

print(nx.shortest_path_length(uMG, source='5', target='9') - 1)
4

Или найти расстояния для всех листьев и сохранить их в словаре или каком-либо другом полезном объекте для нисходящего потока.вычисление.

from itertools import combinations
leaf_distance_edges = {}
leaf_distance_nodes = {}
for leaf1, leaf2 in combinations(leaves, 2):
    d = nx.shortest_path_length(uMG, source=leaf1, target=leaf2)
    leaf_distance_edges[(leaf1, leaf2)] = d
    leaf_distance_nodes[(leaf1, leaf2)] = d - 1 

leaf_distance_nodes
{('4', '9'): 5,
 ('4', '5'): 2,
 ('4', '10'): 5,
 ('4', '7'): 4,
 ('4', '3'): 1,
 ('9', '5'): 4,
 ('9', '10'): 1,
 ('9', '7'): 2,
 ('9', '3'): 5,
 ('5', '10'): 4,
 ('5', '7'): 3,
 ('5', '3'): 2,
 ('10', '7'): 2,
 ('10', '3'): 5,
 ('7', '3'): 4}
...