Как извлечь правила дерева решений sklearn для логических условий pandas?

Есть так много сообщений так о том, как извлечь правила дерева решений sklearn, но я не смог найти ничего об использовании pandas.

Возьмем, к примеру, эти данные и модель, как показано ниже.

# Create Decision Tree classifer object
clf = DecisionTreeClassifier(criterion = "entropy", max_depth=3)

# Train Decision Tree Classifer
clf = clf.fit(X_train,y_train)

Результат:

Как извлечь правила дерева решений sklearn для логических условий pandas?

Ожидал:

В этом примере есть 8 правил.

Слева направо обратите внимание, что фрейм данных df

r1 = (df['glucose']<=127.5) & (df['bmi']<=26.45) & (df['bmi']<=9.1)
……
r8 =  (df['glucose']>127.5) & (df['bmi']>28.15) & (df['glucose']>158.5)

Я не мастер извлечения правил дерева решений sklearn. Получение логических условий pandas поможет мне рассчитать выборки и другие показатели для каждого правила. Поэтому я хочу извлечь каждое правило из логического условия pandas.

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
19
0
6 329
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Прежде всего, давайте используем scikit документация в структуре дерева решений, чтобы получить информацию о построенном дереве:

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

Затем мы определяем две рекурсивные функции. Первый найдет путь от корня дерева до создания определенного узла (в нашем случае всех листьев). Второй запишет конкретные правила, используемые для создания узла, используя его путь создания:

def find_path(node_numb, path, x):
        path.append(node_numb)
        if node_numb == x:
            return True
        left = False
        right = False
        if (children_left[node_numb] !=-1):
            left = find_path(children_left[node_numb], path, x)
        if (children_right[node_numb] !=-1):
            right = find_path(children_right[node_numb], path, x)
        if left or right :
            return True
        path.remove(node_numb)
        return False


def get_rule(path, column_names):
    mask = ''
    for index, node in enumerate(path):
        #We check if we are not in the leaf
        if index!=len(path)-1:
            # Do we go under or over the threshold ?
            if (children_left[node] == path[index+1]):
                mask += "(df['{}']<= {}) \t ".format(column_names[feature[node]], threshold[node])
            else:
                mask += "(df['{}']> {}) \t ".format(column_names[feature[node]], threshold[node])
    # We insert the & at the right places
    mask = mask.replace("\t", "&", mask.count("\t") - 1)
    mask = mask.replace("\t", "")
    return mask

Наконец, мы используем эти две функции, чтобы сначала сохранить путь создания каждого листа. А затем сохранить правила, используемые для создания каждого листа:

# Leaves
leave_id = clf.apply(X_test)

paths  = {}
for leaf in np.unique(leave_id):
    path_leaf = []
    find_path(0, path_leaf, leaf)
    paths[leaf] = np.unique(np.sort(path_leaf))

rules = {}
for key in paths:
    rules[key] = get_rule(paths[key], pima.columns)

С данными, которые вы дали, вывод:

rules =
{3: "(df['insulin']<= 127.5) & (df['bp']<= 26.450000762939453) & (df['bp']<= 9.100000381469727)  ",
 4: "(df['insulin']<= 127.5) & (df['bp']<= 26.450000762939453) & (df['bp']> 9.100000381469727)  ",
 6: "(df['insulin']<= 127.5) & (df['bp']> 26.450000762939453) & (df['skin']<= 27.5)  ",
 7: "(df['insulin']<= 127.5) & (df['bp']> 26.450000762939453) & (df['skin']> 27.5)  ",
 10: "(df['insulin']> 127.5) & (df['bp']<= 28.149999618530273) & (df['insulin']<= 145.5)  ",
 11: "(df['insulin']> 127.5) & (df['bp']<= 28.149999618530273) & (df['insulin']> 145.5)  ",
 13: "(df['insulin']> 127.5) & (df['bp']> 28.149999618530273) & (df['insulin']<= 158.5)  ",
 14: "(df['insulin']> 127.5) & (df['bp']> 28.149999618530273) & (df['insulin']> 158.5)  "}

Поскольку правила являются строками, вы не можете напрямую вызывать их с помощью df[rules[3]], вы должны использовать функцию eval вот так df[eval(rules[3])]

отлично, но я хочу использовать имена столбцов. Не могли бы вы ответить на него?

Jack 05.06.2019 04:31

Проблема anthor заключается в том, что при использовании выбора фрейма данных на основе логических условий, таких как df[rules[4]], возникает ошибка. как это решить

Jack 05.06.2019 04:35

@Jack Я изменил рекурсивную функцию get_rule для отображения столбцов. И я указал, почему вы получаете ошибку в конце ответа :)

vlemaistre 05.06.2019 11:01

Я нашел еще одно решение этой проблемы (вторая часть решения, опубликованного vlemaistre), которое позволяет пользователю запускать любой узел и подмножество данных на основе логического условия pandas.

node_id = 3

def datatree_path_summarystats(node_id):
    for k, v in paths.items():
        if node_id in v:
            d = k,v

    ruleskey = d[0]
    numberofsteps = sum(map(lambda x : x<node_id, d[1]))

    for k, v in rules.items():
        if k == ruleskey:
            b = k,v

    stringsubset = b[1]

    datasubset = "&".join(stringsubset.split('&')[:numberofsteps])
    return datasubset

datasubset = datatree_path_summarystats(node_id)

df[eval(datasubset)]

Эта функция проходит по путям, которые содержат идентификатор узла, который вы ищете. Затем он разделит правило на основе этого количества узлов, создав логику для подмножества фрейма данных на основе этого конкретного узла.

Теперь вы можете использовать export_text.

from sklearn.tree import export_text

r = export_text(loan_tree, feature_names=(list(X_train.columns)))
print(r)

Полный пример из склерн

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree import export_text
iris = load_iris()
X = iris['data']
y = iris['target']
decision_tree = DecisionTreeClassifier(random_state=0, max_depth=2)
decision_tree = decision_tree.fit(X, y)
r = export_text(decision_tree, feature_names=iris['feature_names'])
print(r)

Другие вопросы по теме