PRISM — алгоритм, реализованный мной на языке Python. Хотя идея, лежащая в его основе, не нова, в процессе многократных экспериментов я обнаружил конкурентоспособность PRISM по отношению к большинству других интерпретирующих моделей классификации.

PRISM — относительно простой алгоритм, но в машинном обучении не всегда лучшими оказываются самые сложные решения. Иногда самые простые модели показывают оптимальные результаты. Более того, простота имеет большое значение для эффективности интерпретирующих моделей.

PRISM — инструмент вывода правил методом индукции. Иными словами, он создает набор правил для предсказания целевого признака на основе других признаков.

Правила имеют несколько важнейших назначений в машинном обучении. Одно из них — предсказание. Подобно небольшому количеству инструментов (включая стандартные и аддитивные деревья решений, линейную регрессию, GAM, ikNN, таблицы решений), правила PRISM обеспечивают работу интерпретирующих моделей классификации.

Кроме того, PRISM можно использовать как технологию для понимания данных, причем даже без меток в неконтролируемом режиме. В результате вы получаете набор правил для предсказания каждого признака на основе других признаков (рассматривая каждый признак в таблице по очереди как целевой столбец), что позволяет выявить существенные закономерности в данных.

Существуют и другие инструменты для создания правил на Python, в том числе мощная библиотека imodels. Однако создать набор правил, которые были бы одновременно точными и понятными, непросто. Часто системы вывода правил методом индукции не могут создать достаточно точные модели. А если и могут, то только путем вывода слишком большого количества правил и/или использования в них слишком большого количества условий. Вот как могут выглядеть подобные правила:

IF color (ЕСЛИ цвет) =’blue’ (синий) AND height (И высота) < 3.4 AND width (И ширина) > 3.2 AND length (И длина) > 33.21 AND temperature (И температура) > 33.2 AND temperature (И температура) < 44.2 AND width (И ширина) < 5.1 AND weight (И вес) > 554.0 AND… THEN (ТО)…

Правила, в которых больше 5-10 условий, оказываются трудно выполнимыми. При слишком большом количестве условий они могут стать фактически неинтерпретируемыми. Сложным для выполнения является и набор с превышением допустимого количества правил (особенно если каждое правило содержит множество условий).

Правила PRISM

PRISM — это система вывода правил методом индукции, впервые предложенная Чендровской и описанная в Principles of Data Mining (Принципы интеллектуального анализа данных).

Не найдя реализацию PRISM на Python, я создал ее сам. Вот главная страница правил PRISM.

PRISM поддерживает генерацию правил, выступая одновременно в качестве описательной и прогностической модели. Как описательная модель, PRISM описывает выявленные закономерности в таблице (в виде ассоциаций между признаками), на основе которой создает очень лаконичный, чистый набор правил интерпретации.

Как прогностическая модель, PRISM дает так называемые глобальные и локальные объяснения (понятия, используемые в XAI (Explainable AI — объяснимый ИИ)). То есть это полностью интерпретирующая система, что позволяет понять как модель в целом, так и отдельные предсказания.

Тестируя множество систем вывода правил, я часто обнаруживаю, что PRISM выводит самый чистый набор правил. Однако ни одна система не работает постоянно лучше других, поэтому часто приходится использовать несколько инструментов вывода правил методом индукции.

Создаваемые правила имеют дизъюнктивную нормальную форму (OR из ANDs). Каждое отдельное правило представляет собой AND из одного или нескольких условий. Каждое условие имеет вид “признак = значение” (для определенного значения в пределах набора значений данного признака). 

Вот как выглядят правила, созданные для целевого значения “blue” (“синий”):

  • IF feat_A = “hot” AND feat_C = “round” THEN “blue” (ЕСЛИ признак A = “горячий” И признак C = “круглый” ТО целевое значение = “синий”);
  • IF feat_A = “warm” AND feat_C = “square” THEN “blue” (ЕСЛИ признак A = “теплый” И признак C = “квадратный” ТО целевое значение = “синий”).

А вот правила для целевого значения “red” (“красный”):

  • IF feat_A = “cold” AND feat_C = “triangular” THEN “red” (ЕСЛИ признак A = “холодный” И признак C = “треугольный” ТО целевое значение = “красный”);
  • IF feat_A = “cool” AND feat_C = “triangular” THEN “red” (ЕСЛИ признак A = “прохладный” И признак C = “треугольный” ТО целевое значение = “красный”).

Алгоритм работает строго с категориальными признаками, как в столбце X, так и в столбце Y. Поэтому данная реализация автоматически бинирует все числовые столбцы для поддержки алгоритма. По умолчанию используются три одинаковых бина (представляющие низкие, средние и высокие значения признака), но их можно настроить с помощью параметра nbins (чтобы использовать больше или меньше бинов).

Алгоритм PRISM

В этом разделе рассмотрим PRISM в качестве прогностической модели, а именно в качестве классификатора.

Алгоритм работает путем создания набора правил для каждого класса в целевом столбце. Например, при работе с набором данных Iris (ирис), где в целевом столбце есть три значения — Setosa (щетинистый), Versicolour (многоцветный) и Virginica (виргинский), — будет создан набор правил, относящихся к каждому из этих трех значений

Сгенерированные правила должны читаться по принципу “от первого правила к последнему”, поэтому все правила сгенерированы и представлены в разумном порядке (от наиболее до наименее релевантных для каждого целевого класса). Например, рассматривая набор правил, относящихся к Setosa, получим набор правил, предсказывающих, когда Iris является Setosa, и они будут упорядочены от наиболее до наименее предсказуемых. Аналогично выполняется генерация наборов правил для двух других классов.

Генерация правил

Теперь посмотрим, как работает алгоритм, с помощью которого PRISM генерирует набор правил для одного класса. Предположим, что нужно сгенерировать правила для класса Setosa из набора данных Iris.

Для начала PRISM находит лучшее из имеющихся правил для предсказания данного целевого значения. Это первое правило для Setosa должно предсказать как можно больше зарегистрированных данных (записей) о Setosa. То есть мы находим уникальный набор значений в неком подмножестве других признаков, который лучше всего предсказывает, когда запись станет Setosa. Это и есть первое правило для Setosa.

Однако первое правило не охватывает все Setosa-записи, поэтому создаем дополнительные правила, чтобы охватить оставшиеся строки Setosa (или столько, сколько сможем).

По мере обнаружения каждого правила строки, соответствующие этому правилу, удаляются, и находится следующее правило, которое наилучшим образом описывает оставшиеся строки для данного целевого значения.

Каждое правило может содержать любое количество условий.

Для каждого другого значения в целевом столбце начинаем работу с полным набором данных, удаляя строки по мере обнаружения правил и генерируя дополнительные правила, чтобы объяснить оставшиеся строки для этого значения целевого класса. Так, найдя правила для Setosa, PRISM сгенерирует правила для Versicolour, а затем для Virginica.

Охват и поддержка

Данная реализация расширяет возможности алгоритма, описанного в Principles of Data Mining, выводя статистику по каждому правилу, поскольку многие индуцированные правила могут быть гораздо более значимыми или, наоборот, значительно менее значимыми, чем другие индуцированные правила.

Кроме того, отслеживание простой статистики о каждом правиле позволяет задать параметры, определяющие:

  • минимальный охват каждого правила (минимальное количество строк в обучающих данных, для которых оно применимо);
  • минимальную поддержку (минимальную вероятность того, что целевой класс совпадет с желаемым значением для строк, соответствующих правилу). 

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

Сравнение PRISM с деревьями решений

Деревья решений — одна из самых распространенных интерпретируемых моделей, а возможно, и самая распространенная. При достаточно малых размерах она может быть достаточно интерпретируемой (пожалуй, в той же мере, что и любой другой тип модели), и достаточно точной для решения многих проблем (хотя, конечно, не для всех). Тем не менее у нее, как у интерпретируемой модели, есть свои ограничения, которые PRISM был призван устранить.

Деревья решений специально не разрабатывались как интерпретируемые модели. Способность к интерпретации — дополнительное свойство, повышающее удобство использования деревьев решений. И все же они не являются интерпретируемыми в полной мере. Например, они часто вырастают гораздо больше, чем можно понять, часто с повторяющимися поддеревьями, поскольку для правильного отображения отношений к признакам необходимо многократно повторять их в деревьях.

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

В работе Чендровской приводятся примеры простых наборов правил, которые не могут быть легко представлены в виде деревьев. Например:

  • Правило 1: IF a = 1 AND b = 1 THEN class = 1 (ЕСЛИ a = 1 И b = 1 ТО класс = 1).
  • Правило 2: IF c = 1 AND d = 1 THEN class = 1 (ЕСЛИ c = 1 И d = 1 ТО класс = 1).

Такие простые правила можно представить удивительно сложными деревьями. Подобная закономерность часто наблюдается, когда есть два (базовых) правила, не имеющих общего атрибута.

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

Установка

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

from prism_rules import PrismRules

Пример использования набора данных Wine из sklearn

На странице Github представлены два ноутбука с простыми, но подробными примерами использования инструмента. Инструмент довольно прост в использовании. Чтобы выполнить с его помощью генерацию правил, просто создайте объект PrismRules и вызовите get_prism_rules() с набором данных, указав целевой столбец:

import pandas as pd
from sklearn.datasets import load_wine

data = datasets.load_wine()
df = pd.DataFrame(data.data, columns=data.feature_names)
df['Y'] = data['target']
display(df.head())

prism = PrismRules()
_ = prism.get_prism_rules(df, 'Y')

Результаты

Этот набор данных имеет три значения в целевом столбце, поэтому будет сгенерировано три набора правил:

................................................................
Target: 0
................................................................

proline = High AND alcohol = High
Support: the target has value: '0' for 100.000% of the 39 rows matching the rule
Coverage: the rule matches: 39 out of 59 rows for target value: 0. This is:
66.102% of total rows for target value: 0
21.910% of total rows in data

proline = High AND alcalinity_of_ash = Low
Support: The target has value: '0' for 100.000% of the 10 remaining rows matching the rule
Coverage: The rule matches: 10 out of 20 rows remaining for target value: '0'. This is:
50.000% of remaining rows for target value: '0'
16.949% of total rows for target value: 0
5.618% of total rows in data0


................................................................
Target: 1
................................................................
color_intensity = Low AND alcohol = Low
Support: the target has value: '1' for 100.000% of the 46 rows matching the rule
Coverage: the rule matches: 46 out of 71 rows for target value: 1. This is:
64.789% of total rows for target value: 1
25.843% of total rows in data

color_intensity = Low
Support: The target has value: '1' for 78.571% of the 11 remaining rows matching the rule
Coverage: The rule matches: 11 out of 25 rows remaining for target value: '1'. This is:
44.000% of remaining rows for target value: '1'
15.493% of total rows for target value: 1
6.180% of total rows in data

................................................................
Target: 2
................................................................
flavanoids = Low AND color_intensity = Med
Support: the target has value: '2' for 100.000% of the 16 rows matching the rule
Coverage: the rule matches: 16 out of 48 rows for target value: 2. This is:
33.333% of total rows for target value: 2
8.989% of total rows in data

flavanoids = Low AND alcohol = High
Support: The target has value: '2' for 100.000% of the 10 remaining rows matching the rule
Coverage: The rule matches: 10 out of 32 rows remaining for target value: '2'. This is:
31.250% of remaining rows for target value: '2'
20.833% of total rows for target value: 2
5.618% of total rows in data

flavanoids = Low AND color_intensity = High AND hue = Low
Support: The target has value: '2' for 100.000% of the 21 remaining rows matching the rule
Coverage: The rule matches: 21 out of 22 rows remaining for target value: '2'. This is:
95.455% of remaining rows for target value: '2'
43.750% of total rows for target value: 2
11.798% of total rows in data

Для каждого правила видим как поддержку, так и охват.

Поддержка показывает, сколько строк поддерживают правило, то есть в скольких строках, где правило может быть применено, оно верно. Первое правило здесь следующее:

proline = High AND alcohol = High
Support: the target has value: '0' for 100.000% of the 39 rows matching the rule

Это означает, что для 100 % из 39 строк, где proline = High (пролин = высокий) (признак “пролин” имеет высокое числовое значение) и alcohol = High (алкоголь = высокий) (признак “алкоголь” имеет высокое числовое значение), целевое значение определяется как 0.

Охват показывает, сколько строк охватывает правило. Для первого правила ситуация следующая:

Coverage: the rule matches: 39 out of 59 rows for target value: 0. This is:
66.102% of total rows for target value: 0
21.910% of total rows in data

Здесь указан охват как с точки зрения количества строк, так и в процентах от числа строк в данных.

Пример генерации предсказаний

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

y_pred = prism.predict(df.drop(columns=['Y']))

Таким образом, правила PRISM эквиваленты в использовании любой другой прогностической модели, такой как Decision Trees, Random Forests, XGBoost и др.

Однако при генерации прогнозов некоторые строки могут не соответствовать никаким правилам. В этом случае по умолчанию будет использоваться наиболее часто встречающееся значение в целевом столбце во время обучения (которое можно увидеть здесь: prism.default_target). Метод predict() также поддерживает параметр leave_unknown. Если он имеет значение True, то для всех записей, не соответствующих каким-либо правилам, будет установлено значение «NO PREDICTION». В этом случае прогнозы будут возвращены в виде строкового типа, даже если исходный целевой столбец был числовым.

Другие примеры приведены в примерах ноутбуков.

Пример с числовыми данными

В этом примере используем метод sklearn make_classification() для создания числовых данных (кроме целевого столбца), которые затем разбиваются на бины. По умолчанию используется три бина на числовой признак.

x, y = make_classification(
n_samples=1000,
n_features=20,
n_informative=2,
n_redundant=2,
n_repeated=0,
n_classes=2,
n_clusters_per_class=1,
class_sep=2,
flip_y=0,
random_state=0
)

df = pd.DataFrame(x)
df['Y'] = y
prism = PrismRules()
_ = prism.get_prism_rules(df, 'Y')

Результаты

Данные разбиты на низкие, средние и высокие значения для каждого столбца. Результатом является набор правил для каждого целевого класса.

Target: 0
1 = High
Support: the target has value: '0' for 100.000% of the 333 rows matching the rule
Coverage: the rule matches: 333 out of 500 rows for target value: 0. This is:
66.600% of total rows for target value: 0
33.300% of total rows in data

15 = Low AND 4 = Med
Support: The target has value: '0' for 100.000% of the 63 remaining rows matching the rule
Coverage: The rule matches: 63 out of 167 rows remaining for target value: '0'. This is:
37.725% of remaining rows for target value: '0'
12.600% of total rows for target value: 0
6.300% of total rows in data

4 = High AND 1 = Med
Support: The target has value: '0' for 100.000% of the 47 remaining rows matching the rule
Coverage: The rule matches: 47 out of 104 rows remaining for target value: '0'. This is:
45.192% of remaining rows for target value: '0'
9.400% of total rows for target value: 0
4.700% of total rows in data

Пример из Principles of Data Mining

Этот пример приведен в одном из примеров в ноутбуках на странице Github.

PRISM сгенерировал три правила:

  • IF tears = 1 THEN Target = 3 (ЕСЛИ слезоотделение = 1 ТО Целевое значение =3);
  • IF astig = 1 AND tears = 2  AND specRX = 2 THEN Target=2 (ЕСЛИ астигматизм = 1 И слезоотделение = 2 И рецепт очков = 2 ТО Целевое значение =2);
  • IF astig = 2 AND tears = 2 AND specRX =1 THEN Target =1 (ЕСЛИ астигматизм = 2  И слезоотделение = 2 И рецепт очков =1 ТО Целевое значение =1).

Время выполнения

Алгоритм обычно способен создавать набор правил за несколько секунд или минут. Если необходимо сократить время выполнения алгоритма, вместо полного набора данных можно использовать выборку данных. Алгоритм обычно хорошо работает на выборках данных, поскольку модель ищет общие закономерности, а не исключения, а закономерности присущи любой достаточно большой выборке.

Дополнительные указания по настройке модели приведены на странице Github.

Выводы

К сожалению, на сегодняшний день создано относительно немного вариантов интерпретируемых прогностических моделей. К тому же, ни одна из них не будет достаточно точной или достаточно интерпретируемой для всех наборов данных. Следовательно, там, где важна интерпретируемость, стоит, помимо правил PRISM, протестировать несколько других интерпретируемых моделей, включая деревья решений (стандартные и аддитивные), GAM, ikNN.

PRISM обычно генерирует чистые правила интерпретации и отличается высоким уровнем точности, хотя многое зависит от проекта. Поэтому правилам PRISM, впрочем, как и другим прогностическим моделям, необходима определенная настройка.

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи W Brett Kennedy: PRISM-Rules in Python. A simple python rules-induction system

Предыдущая статьяКак прошло мое собеседование в Uber на должность старшего инженера-разработчика
Следующая статья10 рекомендаций по повышению производительности от экспертов JS React