Thursday, July 7, 2022

Convertion Decision Trees into Desision lists of rules (Python)

 Деревья решений и списки решений — два популярных языка гипотез, которые имеют немало общего. Ключевое отличие состоит в том, что деревья решений можно рассматривать как неупорядоченные наборы правил, где каждый лист дерева соответствует одному правилу с частью условия, состоящей из соединения всех меток ребер на пути от корня к этому листу. Иерархическая структура дерева гарантирует, что правила в наборе не перекрываются, то есть каждый пример может быть покрыт только одним правилом. Это дополнительное ограничение упрощает классификацию (отсутствие конфликтов из-за нескольких правил), но может привести к более сложным правилам. Например, было показано, что списки решений (упорядоченные наборы правил) с не более чем k условиями на правило строго более выразительны, чем деревья решений глубины k.Более того, ограничение алгоритмов обучения дерева решений непересекающимися правилами накладывает сильные ограничения.

========================

Список решений (также называемый упорядоченным набором правил) представляет собой набор отдельных правил классификации, которые в совокупности образуют классификатор. В отличие от неупорядоченного набора правил, списки решений имеют неотъемлемый порядок, что делает классификацию довольно простой. Для классификации нового экземпляра правила проверяются по порядку, и прогнозируется класс первого правила, которое охватывает экземпляр. Если не срабатывает индуцированное правило, вызывается правило по умолчанию, которое обычно предсказывает класс большинства.


(.env) boris@boris-All-Series:~/DecisionTree$ cat ConvertionDTree.py

from matplotlib import pyplot as plt

from sklearn import datasets

from sklearn.tree import DecisionTreeClassifier 

from sklearn import tree

import numpy as np

# Prepare the data data

iris = datasets.load_iris()

X = iris.data

y = iris.target

# Fit the classifier with max_depth=3

clf = DecisionTreeClassifier(max_depth=3, random_state=1234)

model = clf.fit(X, y)

text_representation = tree.export_text(clf, feature_names=iris.feature_names)

print(text_representation)

print('Decision Tree has been built','\n')

from sklearn.tree import _tree

def get_rules(tree, feature_names, class_names):

    tree_ = tree.tree_

    feature_name = [

        feature_names[i] if i != _tree.TREE_UNDEFINED else "undefined!"

        for i in tree_.feature

    ]

    paths = []

    path = []

    def recurse(node, path, paths):

        if tree_.feature[node] != _tree.TREE_UNDEFINED:

            name = feature_name[node]

            threshold = tree_.threshold[node]

            p1, p2 = list(path), list(path)

            p1 += [f"({name} <= {np.round(threshold, 3)})"]

            recurse(tree_.children_left[node], p1, paths)

            p2 += [f"({name} > {np.round(threshold, 3)})"]

            recurse(tree_.children_right[node], p2, paths)

        else:

            path += [(tree_.value[node], tree_.n_node_samples[node])]

            paths += [path]

    recurse(0, path, paths)

    # sort by samples count

    samples_count = [p[-1][1] for p in paths]

    ii = list(np.argsort(samples_count))

    paths = [paths[i] for i in reversed(ii)]

    rules = []

    for path in paths:

        rule = "if "

        for p in path[:-1]:

            if rule != "if ":

                rule += " and "

            rule += str(p)

        rule += " then "

        if class_names is None:

            rule += "response: "+str(np.round(path[-1][0][0][0],3))

        else:

            classes = path[-1][0][0]

            l = np.argmax(classes)

            rule += f"class: {class_names[l]} (proba: {np.round(100.0*classes[l]/np.sum(classes),2)}%)"

        rule += f" | based on {path[-1][1]:,} samples"

        rules += [rule]

    return rules

rules = get_rules(clf, iris.feature_names, iris.target_names)

for r in rules:

    print(r)


(.env) boris@boris-All-Series:~/DecisionTree$ python3 ConvertionDTree.py

|--- petal length (cm) <= 2.45

|   |--- class: 0

|--- petal length (cm) >  2.45

|   |--- petal width (cm) <= 1.75

|   |   |--- petal length (cm) <= 4.95

|   |   |   |--- class: 1

|   |   |--- petal length (cm) >  4.95

|   |   |   |--- class: 2

|   |--- petal width (cm) >  1.75

|   |   |--- petal length (cm) <= 4.85

|   |   |   |--- class: 2

|   |   |--- petal length (cm) >  4.85

|   |   |   |--- class: 2

Decision Tree has been built

if (petal length (cm) <= 2.45) then class: setosa (proba: 100.0%) | based on 50 samples

if (petal length (cm) > 2.45) and (petal width (cm) <= 1.75) and (petal length (cm) <= 4.95) then class: versicolor (proba: 97.92%) | based on 48 samples

if (petal length (cm) > 2.45) and (petal width (cm) > 1.75) and (petal length (cm) > 4.85) then class: virginica (proba: 100.0%) | based on 43 samples

if (petal length (cm) > 2.45) and (petal width (cm) <= 1.75) and (petal length (cm) > 4.95) then class: virginica (proba: 66.67%) | based on 6 samples

if (petal length (cm) > 2.45) and (petal width (cm) > 1.75) and (petal length (cm) <= 4.85) then class: virginica (proba: 66.67%) | based on 3 samples






























No comments:

Post a Comment