🌳 Настраиваемая и интерактивная структура дерева решений, написанная на чистом Python 🌳

Быстрый трек

0. Что внутри истории?

В этой истории будет представлена ​​еще одна реализация деревьев решений, которую я написал в рамках своей диссертации. Работа будет разделена на три части следующим образом: Во-первых, я попытаюсь мотивировать, почему я решил не торопиться, чтобы придумать собственную реализацию деревьев решений; Я покажу некоторые из его функций, но также перечислю недостатки его текущей реализации (да, их будет много). Во-вторых, я расскажу вам об основных принципах использования HDTree, используя несколько фрагментов кода и по ходу объясняя некоторые детали. Недавно будет несколько советов о том, как настроить и расширить HDTree с помощью ваших собственных идей.

Однако эта статья не проведет вас через все основы деревьев решений. Ресурсов действительно много ² ³. Думаю, нет необходимости повторять все это еще раз. Другие сделали это. Я не смогу сделать это лучше. Однако вам не нужно быть экспертом по деревьям решений, чтобы понять эту статью. Базового уровня понимания должно быть достаточно, чтобы продолжить :)

1. Мотивация и предыстория

В своей работе я начал работать с деревьями решений. Моя настоящая цель - реализовать ориентированную на человека ML-модель, где HDTree (Human Decision Tree, если на то пошло) является дополнительным ингредиентом, который используется как часть реального пользовательского интерфейса для этой модели. Хотя эта история посвящена исключительно HDTree, я мог бы написать продолжение, подробно описав другие компоненты.

1.1 Особенности HDTree и сравнение с scikit learn Деревья решений

Естественно, я наткнулся на реализацию scikit-learn деревьев решений. Думаю, многие практикующие так делают. И давайте проясним кое-что с самого начала: в этом нет ничего плохого.

У реализации sckit-learn много плюсов:

  • это быстро и оптимизировано. Реализация написана на диалекте C ython ⁵. Cython компилируется в C-Code (который, в свою очередь, компилируется в собственный код), сохраняя при этом возможность взаимодействия с интерпретатором Python.
  • им легко пользоваться. Это удобно. Многие люди в области машинного обучения знают, как работать с моделями scikit-learn.
  • Вы легко найдете помощь везде благодаря его пользовательской базе.
  • это проверено в боях. Многие люди этим пользуются. Просто работает!
  • он поддерживает множество методов предварительной и последующей обрезки⁶ и предоставляет множество функций (например, обрезка с минимальными затратами³ или выборочные веса)
  • он поддерживает базовую визуализацию⁷

Тем не менее, у него, безусловно, есть некоторые недостатки:

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

Возможности HDTree
По сути, HDTree предложит решение для большинства недостатков из приведенного выше списка, при этом жертвуя многими преимуществами реализации scikit-learn. Мы вернемся к этим вопросам позже, поэтому не волнуйтесь, если вы еще не поняли все части следующего списка:

👍 взаимодействовать с обучающим поведением
👍 основные компоненты являются модульными и довольно легко расширяемыми (реализовать интерфейс)
👍 написаны исключительно на Python (делает его более доступным)
👍 богатая визуализация
👍 поддержка категориальных данных
👍 поддержка отсутствующих значений (частично атм.)
👍 поддержка многовариантных разделений
👍 простой интерфейс для навигации по древовидной структуре
👍 поддержка n -арное разбиение (›2 дочерних узла)
👍 текстовое представление путей решения
👍 объяснение функций
👍 способствует объяснению за счет печати понятного человеку текста
-
👎 очень медленно (что-то не исправимо, что-то может быть)
👎 не проверено в боевых условиях ( будет содержать ошибки)
👎 посредственное качество программного обеспечения. Это взрослый проект. Вещи развивались естественным образом.
👎 не так много параметров обрезки (хотя он поддерживает некоторые базовые параметры)

⚠️ Хотя недостатки кажутся не слишком многочисленными, они критичны. Давайте сразу же проясним это: не бросайте на это большие данные. Вы будете ждать вечно. Не используйте его в производстве. Он может неожиданно сломаться. Вы были предупреждены! ⚠️
-
Некоторые из этих проблем могут быть решены со временем. Однако скорость обучения, вероятно, останется низкой. Вам нужно будет придумать лучшее решение, чтобы исправить это. Приглашаем вас внести свой вклад 😃.

Тем не менее, каковы были бы возможные варианты использования?

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

1.2 Структура деревьев решений

Хотя в этой работе не будут подробно рассмотрены деревья решений, мы кратко перечислим их основные строительные блоки. Это обеспечит основу для понимания примеров позже, а также выделит некоторые особенности HDTrees. На следующем рисунке показан фактический результат работы HDTree (за исключением маркеров).

a (Узлы)
ai: текстовое описание правила проверки / разделения, которое использовалось на этом узле для разделения данных на его дети. Отображает соответствующий атрибут (-ы) и словесное описание операции. Эти тесты легко настраиваются и могут включать в себя любую логику разделения данных, которую вы можете придумать. Разработка собственных пользовательских правил поддерживается за счет реализации интерфейса. Подробнее об этом в разделе 3.

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

aiii: граница узла указывает, сколько точек данных проходит через этот узел. Чем толще граница, тем больше данных проходит через этот узел.

aiv: список целей / ярлыков (т. е. класс, который имеет точка данных), которые привязаны к точкам данных и их индивидуальному количеству. Самый распространенный класс отмечен ✔.

av: при желании визуализация может отмечать путь, по которому следуют отдельные точки данных. Это отмечено линией в углу дерева решений.

b (Ребра)
bi:
стрелка соединяет каждый возможный результат разбиения (ai) с его дочерними узлами. Чем больше данных (относительно родительского) «перетекает» по краю, тем толще они отображаются.

bii: каждое ребро имеет читаемое текстовое представление соответствующего результата разбиения.

1.3 Почему разные сплиты / тесты?

К этому моменту вы уже можете задаться вопросом, чем отличается HDTree от дерева scikit-learn (или любой другой реализации) и почему мы можем захотеть иметь разные виды разбиений? Попробуем прояснить это.

Возможно, у вас есть интуитивное понимание понятия пространства функций . Все данные, с которыми мы работаем, находятся в некотором многомерном пространстве, которое определяется количеством и типом атрибутов / характеристик ваших данных.

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

Вы видите очень простой набор данных, состоящий из двух измерений и двух классов. Точки данных были нормально распределены в центре. Улица, которая является просто линейной функцией f (x) = y, разделяет эти два класса на Класс 1 (Юго-восток) и Класс 2 (Северо-запад). Кроме того, без особой причины был добавлен какой-то случайный шум 😉.

Учитывая эти данные, решение о том, как данные будут разделены (классифицированы), кажется очень простым. Разумный человек сказал бы (подумайте сначала самостоятельно):

"Это класс 1, если x› y, иначе класс 2 "

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

На изображении показаны области, в которых классификатор классифицирует точку данных как класс 1 (оранжевый) или класс 2 (синий).

Обратите внимание, как линейная функция должна быть аппроксимирована деревом решений с помощью функции s tep .

Это связано с типом правила проверки / разделения, которое использует дерево решений. Все они относятся к схеме attributethreshold, что приведет к образованию параллельных осям гиперплоскостей. В 2D-пространстве это как «вырезание» блоков. В 3D-пространстве это были бы кубики… и так далее.

Кроме того, дерево решений начинает моделировать шум в данных, когда уже имеет 8 уровней, т. Е. Это переоснащение. При этом он никогда не находит хорошего приближения к реальной функции. Чтобы убедиться в этом, я использовал типичное разделение данных на поезда (2: 1) и оценил оценки деревьев, которые составили
93,84%, 93,03%, 90,81% для тестового набора t и 94,54%, 96,57%, 98,81% для обучающего набора (глубина в порядке 4, 8 , 16). По мере того как точность теста снижается, точность обучения увеличивается, что является признаком переобучения.

Дерево решений также довольно сложно для такой простой функции. Самый простой из них (глубина 4) выглядит уже так:

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

2. Использование пакета HDTree 🌲

В этом разделе вы познакомитесь с основами HDTree. Я попробую прикоснуться к некоторым частям его API. Пожалуйста, не стесняйтесь спрашивать в разделе комментариев или свяжитесь со мной, если у вас есть какие-либо вопросы по этому поводу. С радостью отвечу и при необходимости дополню статью.

2.1. Установка HDTree 💻

Это немного сложнее, чем pip install hdtree. Извини.

  1. Создать пустой каталог
  2. Создайте внутри папку с именем «hdtree» (`your_folder / hdtree`)
  3. Загрузите или клонируйте репозиторий в этот каталог hdtree (не в подкаталог)
  4. Установите необходимые зависимости / пакеты (numpy, pandas, graphviz, sklearn, Python ≥ 3.5)
  5. Добавьте `your_folder` в свой путь поиска python , чтобы Python нашел его при импорте.

В качестве альтернативы вы можете добавить hdtree в папку site-packages вашей установки python. Я могу добавить установочный файл позже. На момент написания код недоступен в репозитории pip.

Все коды, которые генерируют графику / выходные данные ниже и полные фрагменты кода, находятся в репозитории или прямо здесь.

2.2 Решение линейной задачи с одноуровневым деревом решений 📈

Давайте сразу начнем с кода:

from hdtree import HDTreeClassifier, SmallerThanSplit, EntropyMeasure
hdtree_linear = HDTreeClassifier(allowed_splits=    [SmallerThanSplit.build()], information_measure=EntropyMeasure(), attribute_names=['x', 'y'])
hdtree_linear.fit(X_street_train, y_street_train)
hdtree_linear.generate_dot_graph()

Да, дерево всего на один уровень выше и имеет идеальное решение этой проблемы. По общему признанию, этот пример каким-то образом инсценирован, чтобы показать эффект.

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

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

Но давайте немного углубимся в сам код. При инициализации HDTreeClassifier самое важное, что вам нужно будет предоставить, - это allowed_splits. Здесь вы предоставляете список, содержащий возможные тесты / правила разделения, которые алгоритм пробует во время построения / обучения для каждого узла, чтобы найти хороший локальный раздел данных.

В этом случае мы предоставили только SmallerThanSplit. Это разделение делает именно то, что вы видите: оно принимает два атрибута (пробует любую комбинацию) и разделяет данные в схеме a_i ‹a_j. Что (не слишком случайно) подходит предоставленные данные настолько хороши, насколько это возможно.

Этот тип разделения обозначается как многовариантное разделение. Это означает, что разделение использует более одного атрибута для решения о разделении. Это отличается от одномерного разбиения, которые используются в большинстве других деревьев, таких как scikit-tree (подробности см. Выше), которые принимают ровно один атрибут в учетную запись. Конечно, HDTree также имеет параметры для достижения «нормального разделения», например, в деревьях scikit (QuantileSplit -Family). Мы узнаем больше о разделениях на нашем пути.

Еще одна незнакомая вещь, которую вы можете увидеть в коде, - это гиперпараметр модели information_measure. Здесь вы предоставляете модели измерение, которое используется для оценки значения отдельного узла или полного разбиения (родительский узел с его дочерними элементами). Выбранный здесь вариант основан на Entropy¹⁰. Возможно, вы также слышали о индексе Джини, который будет здесь еще одним подходящим вариантом. Конечно же, вы можете предоставить свои собственные информационные меры, просто реализовав соответствующий интерфейс. Если хотите: продолжайте и внедряйте индекс Джини, который вы можете добавить прямо в дерево без повторной реализации чего-либо еще. Подробности будут показаны позже.

2.3 Давайте копнем глубже - Титаник 🚢

Я как бы любитель учиться на собственном примере. Вот почему я думаю, что показываю вам еще некоторые особенности деревьев на конкретном примере, а не просто перечисляю функции без контекста.

Набор данных

Мы продолжим использовать знаменитый 101 набор данных машинного обучения: набор данных о титанической катастрофе. Делаем это для удобства. Это довольно простой набор данных, который не слишком велик, но содержит несколько разных типов данных и пропущенные значения, но при этом не является полностью тривиальным. Кроме того, это понятно, и многие люди уже работали с этим набором данных. Чтобы объединить нас всех на одной странице, данные выглядят следующим образом:

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

Когда вы просматриваете учебные пособия по машинному обучению с использованием этого набора данных, они будут выполнять всевозможные предварительные обработки, чтобы иметь возможность использовать его с общими моделями, например путем удаления значений NaN (путем Imputing¹² или удаления строк / столбцов), однократного горячего кодирования¹³ категориальных данных (например, Embarked и Sex) или значения биннинга, чтобы иметь действительный набор данных, который принимает ML-модель.

Для HDTree это технически не требуется. Вы можете вводить данные как есть, и он с радостью их примет. Изменяйте данные только в том случае, если вы занимаетесь реальной разработкой функций. Это реальное упрощение для начала.

Обучите первый HDTree на титанических данных

Мы просто возьмем данные как есть и скормим их модели. Базовый код аналогичен приведенному выше, однако в этом примере будет разрешено больше разделений.

hdtree_titanic = HDTreeClassifier(allowed_splits=[FixedValueSplit.build(), SingleCategorySplit.build(), TwentyQuantileRangeSplit.build(), TwentyQuantileSplit.build()], information_measure=EntropyMeasure(), attribute_names=col_names, max_levels=3)
hdtree_titanic.fit(X_titanic_train.values, y_titanic_train.values)
hdtree_titanic.generate_dot_graph()

Давайте немного углубимся в то, что мы видим. Мы создали дерево решений с тремя уровнями, в которых было выбрано 3 из 4 возможных SplitRules. Они помечены как S1, S2, S3 соответственно. Я кратко объясню, что они делают.

  • S1: FixedValueSplit. Это разделение работает с категориальными данными и выбирает одно из возможных значений. Затем данные разделяются на одну часть, для которой установлено это значение, и на одну часть, для которой это значение не установлено. например, PClass = 1 и Pclass ≠ 1.
  • S2: (Двадцать) QuantileRangeSplit. Они будут работать с числовыми данными. Они будут делить соответствующий диапазон значений оцениваемого атрибута на фиксированное количество квантилей ¹⁴ и охватывает интервалы, которые находятся в диапазоне последовательных подмножеств их (например, от квантиля 1 до квантиля 5). Каждый квантиль включает в себя одинаковое количество точек данных. Начальный квантиль и конечный квантиль (= размер интервала) ищутся для оптимизации информационной меры. Данные делятся на (i) имеющие значение в пределах этого интервала или (ii) вне его. Доступны разделения для различного количества квантилей.
  • S3: (Двадцать) QuantileSplit. Подобно разделению диапазона (S2), но разделяет данные по пороговому значению. Это в основном то, что делают обычные деревья решений, за исключением того, что они обычно пробуют все возможные пороги вместо их фиксированного числа.

Вы могли заметить, что SingleCategorySplit не использовался. Я все равно попытаюсь объяснить это, потому что оно появится позже:

  • S4: Разделение на одну категорию. Этот будет работать аналогично FixedValueSplit. Однако он создаст дочерний узел для каждого возможного значения, например: для атрибута PClass это будет 3 дочерних узла (каждый для Class 1, Class 2 и Class 3 ). Обратите внимание, что FixedValueSplit идентичен SingleValueSplit, если есть только две возможные категории.

Отдельные разделения умны в том, что касается типов / значений данных, которые они принимают. В некоторой степени они знают, при каких обстоятельствах они применяются, а при каких - нет.

Это HDTree также было обучено на обучающих данных с использованием разделения обучения / теста 2: 1. Производительность находится на уровне 80,37% точности теста и точности теста 81,69. Не плохо.

Ограничение разделения

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

- SNIP -
...allowed_splits=[FixedValueSplit.build_with_restrictions(min_level=1), SingleCategorySplit.build_with_restrictions(min_level=1),...],
- SNIP -

Я представлю получившееся HDTree целиком, так как мы также можем наблюдать недостающее разбиение (S4) внутри только что сгенерированного дерева.

Запрещая разделение на атрибут sex, появляющийся в корне (из-за параметра min_level = 1; подсказка: конечно же, вы также можете указать max_level ) мы полностью реструктурировали дерево. Его производительность сейчас составляет 80,37% и 81,69% (тренировочная / тестовая). Он вообще не изменился, даже если мы убрали предположительно лучшее расщепление в корневом узле.

Поскольку деревья решений строятся жадно , они найдут только локальное лучшее разбиение для каждого узла, что не обязательно глобально лучший вариант. На самом деле поиск идеального решения проблемы дерева решений уже давно оказался NP-Complete.

Итак, лучшее, что мы можем пожелать, - это эвристика. Вернемся к примеру: заметили, что мы уже получили представление о нетривиальных данных? Хотя тривиально сказать, что у мужчин будут лишь низкие шансы на выживание, меньше может быть обнаружение того факта, что принадлежность к первому или второму классу (PClass) происходит из Шербура (Embarked = C) может увеличить ваши шансы на выживание. Или что, даже если вы мужчина в PClass 3, но вам меньше 33 лет, ваши шансы также увеличиваются? Помните: это прежде всего женщины и дети. Хорошее упражнение - сделать эти выводы на вас, интерпретируя визуализацию. Эти выводы были возможны только из-за ограничения дерева. Кто знает, что еще можно раскрыть, применив другие ограничения? Попробуйте!

В качестве последнего примера такого рода я хочу показать вам, как ограничить разбиение до определенных атрибутов. Это можно использовать не только для предотвращения того, чтобы дерево узнало нежелательные корреляции или принудительного принятия альтернативных решений, но также для сужения область поиска. Это может резко сократить время выполнения, особенно при использовании многовариантного разбиения. Если вы вернетесь к предыдущему примеру, вы можете обнаружить узел, который проверяет атрибут PassengerId, который, возможно, мы не хотим моделировать, поскольку он, по крайней мере, должен Не вносите вклад в информацию, если пассажир выжил. Проверка может быть признаком переобучения снова. Давайте изменим это с помощью параметра blacklist_attribute_indices.

- SNIP -
...allowed_splits=[TwentyQuantileRangeSplit.build_with_restrictions(blacklist_attribute_indices=['PassengerId']), FixedValueSplit.build_with_restrictions(blacklist_attribute_indices=['Name Length']),...],
- SNIP -

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

Дополнительная подсказка: вы всегда можете добавить одно и то же SplitRule дважды. Если вы хотите внести атрибут в черный список только для определенного уровня (-ов) HDTree, просто добавьте такое же SplitRule без этого ограничения вокруг этого (-ых) уровня (-ов).

Прогнозирование точек данных

Как вы, возможно, уже заметили, вы можете использовать общий интерфейс scikit-learn для прогнозирования данных. Это метод .predict (), pred_proba (), а также .score (). Но можно пойти дальше. Существует дополнительный метод. manage_decision (), который может распечатать текстовое представление решения следующим образом (предполагается, что hdtree_titanic_3 является последним изменением, которое мы внесли в дерево):

print(hdtree_titanic_3.explain_decision(X_titanic_train[42]))

напечатает:

Query: 
 {'PassengerId': 273, 'Pclass': 2, 'Sex': 'female', 'Age': 41.0, 'SibSp': 0, 'Parch': 1, 'Fare': 19.5, 'Cabin': nan, 'Embarked': 'S', 'Name Length': 41}

Predicted sample as "Survived" because of: 
Explanation 1:
Step 1: Sex doesn't match value male
Step 2: Pclass doesn't match value 3
Step 3: Fare is OUTSIDE range [134.61, ..., 152.31[(19.50 is below range)
Step 4: Leaf. Vote for {'Survived'}
---------------------------------

Это работает даже для отсутствующих данных. Давайте установим индекс атрибута 2 (Пол) как отсутствующий (Нет)

passenger_42 = X_titanic_train[42].copy()
passenger_42[2] = None
print(hdtree_titanic_3.explain_decision(passenger_42))
Query: 
 {'PassengerId': 273, 'Pclass': 2, 'Sex': None, 'Age': 41.0, 'SibSp': 0, 'Parch': 1, 'Fare': 19.5, 'Cabin': nan, 'Embarked': 'S', 'Name Length': 41}

Predicted sample as "Death" because of: 
Explanation 1:
Step 1: Sex has no value available
Step 2: Age is OUTSIDE range [28.00, ..., 31.00[(41.00 is above range)
Step 3: Age is OUTSIDE range [18.00, ..., 25.00[(41.00 is above range)
Step 4: Leaf. Vote for {'Death'}
---------------------------------
Explanation 2:
Step 1: Sex has no value available
Step 2: Pclass doesn't match value 3
Step 3: Fare is OUTSIDE range [134.61, ..., 152.31[(19.50 is below range)
Step 4: Leaf. Vote for {'Survived'}
---------------------------------

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

другие (возможно) полезные дела

Вы можете продолжить и получить представление дерева в виде текста, просто распечатав его.

Level 0, ROOT: Node having 596 samples and 2 children with split rule "Split on Sex equals male" (Split Score: 0.251)
-Level 1, Child #1: Node having 390 samples and 2 children with split rule "Age is within range [28.00, ..., 31.00[" (Split Score: 0.342)
--Level 2, Child #1: Node having 117 samples and 2 children with split rule "Name Length is within range [18.80, ..., 20.00[" (Split Score: 0.543)
---Level 3, Child #1: Node having 14 samples and no children with 
- SNIP -

или получить доступ ко всем чистым узлам (с высоким баллом)

[str(node) for node in hdtree_titanic_3.get_clean_nodes(min_score=0.5)]
['Node having 117 samples and 2 children with split rule "Name Length is within range [18.80, ..., 20.00[" (Split Score: 0.543)',
 'Node having 14 samples and no children with split rule "no split rule" (Node Score: 1)',
 'Node having 15 samples and no children with split rule "no split rule" (Node Score: 0.647)',
 'Node having 107 samples and 2 children with split rule "Fare is within range [134.61, ..., 152.31[" (Split Score: 0.822)',
 'Node having 102 samples and no children with split rule "no split rule" (Node Score: 0.861)']

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

3. Расширение HDTree 🐍

Самое ценное, что вы, возможно, захотите добавить в систему, - это ваше настраиваемое SplitRule. Правило разделения действительно может делать все, что угодно, для разделения данных. Вы можете реализовать SplitRule, реализовав класс AbstractSplitRule, что довольно сложно, поскольку вам придется самостоятельно обрабатывать прием данных, оценку производительности и все остальное. По этим причинам в пакете есть миксины, которые вы можете добавить в реализацию в зависимости от типа разделения, которое вы хотите создать, которое делает большую часть трудной части за вас.

Поскольку статья уже довольно длинная, я предоставлю конкретное руководство в другой статье, которую, надеюсь, смогу написать в ближайшие недели. Лучшее на данный момент - это просто взять одно существующее правило разделения, скопировать его и адаптировать к своим требованиям. Если вы не слишком хорошо владеете Python или ООП¹¹, некоторый синтаксис может оказаться непосильным. В любом случае, вам не нужно понимать каждую мелочь, чтобы заставить его работать. Большинство вещей говорят сами за себя. Многие из функций предназначены только для отображения, чтобы создавать читабельные тексты.

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

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

Еще раз спасибо за уделенное время 👍 🎉🎉

[1] Статья в Википедии о деревьях решений
https://en.wikipedia.org/wiki/Decision_tree

[2] Статья Medium 101 о деревьях решений
https://medium.com/machine-learning-101/chapter-3-decision-tree-classifier-coding-ae7df4284e99

[3] Брейман, Лео, Джозеф Х. Фридман, Р. А. Олшен и К. Дж. Стоун. «Деревья классификации и регрессии». (1983).

[4] scikit-learn документация: Классификатор дерева решений
https://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html?highlight=decision%20tree#sklearn.tree. DecisionTreeClassifier

[5] Страница проекта Cython
https://cython.org

[6] Статья в Википедии об обрезке:
https://en.wikipedia.org/wiki/Decision_tree_pruning

[7] документация sklearn: построение дерева решений
https://scikit-learn.org/stable/modules/generated/sklearn.tree.plot_tree.html

[8] Статья в Википедии Машина опорных векторов
https://de.wikipedia.org/wiki/Support_Vector_Machine

[9] Библиотека Python MLExtend
http://rasbt.github.io/mlxtend/

[10] Энтропия статьи в Википедии в контексте деревьев решений
https://en.wikipedia.org/wiki/ID3_algorithm#Entropy

[11] Статья в Википедии об ООП
https://en.wikipedia.org/wiki/Object-oriated_programming

[12] Статья в Википедии о вменении
https://en.wikipedia.org/wiki/Imputation_(statistics)#:~:text=In%20statistics%2C%20imputation%20is%20the,known%20as% 20 'элемент% 20imputation

[13] Hackernoon статья о горячем кодировании
https://hackernoon.com/what-is-one-hot-encoding-why-and-when-do-you-have-to-use- it-e3c6186d008f

[14] Статья в Википедии о квантилях
https://en.wikipedia.org/wiki/Quantile

[15] Хяфил, Лоран; Ривест, Рональд Л.
«Построение оптимальных двоичных деревьев решений является NP-полным» (1976)