Мастерство Data Science: Автоматизированное конструирование признаков на Python

Автор оригинала: Will Koehrsen
  • Перевод
image

Машинное обучение все больше переходит от моделей, разработанных вручную, к автоматически оптимизированным пайплайнам с использованием таких инструментов, как H20, TPOT и auto-sklearn. Эти библиотеки, наряду с такими методами, как случайный поиск, стремятся упростить выбор модели и настройку частей машинного обучения, находя лучшую модель для набора данных без какого-либо ручного вмешательства. Однако разработка объектов, возможно, более ценный аспект пайплайнов машинного обучения, остается почти полностью человеческим трудом.

Конструирование признаков (Feature engineering), также известная как создание признаков (feature creation), представляет собой процесс создания новых признаков из существующих данных для обучения модели машинного обучения. Этот шаг может быть более важным, чем фактическая используемая модель, потому что алгоритм машинного обучения извлекает уроки только из тех данных, которые мы ему предоставляем, и создание признаков, которые имеют отношение к задаче, абсолютно необходимо (см. Превосходную статью «Несколько полезных вещей, которые необходимо знать о Машинное обучение").

Как правило, разработка признаков — это длительный ручной процесс, основанный на знании предметной области, интуиции и манипулировании данными. Этот процесс может быть чрезвычайно утомительным, и конечные характеристики будут ограничены как субъективностью человека, так и временем. Автоматизированное проектирование признаков направлено на то, чтобы помочь специалисту по науке о данных, автоматически создавать множество объектов-кандидатов из набора данных, из которого можно выбрать лучшие и использовать для обучения.
В этой статье мы рассмотрим пример использования автоматической разработки признаков с библиотекой featuretools для Python. Мы будем использовать примерный набор данных, чтобы показать основы (следите за будущими публикациями с использованием реальных данных). Полный код из этой статьи доступен на GitHub.

Основы разработки признаков


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

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

Преобразование действует на одну таблицу (в терминах Python, таблица представляет собой просто Pandas DataFrame), создавая новые признаки из одного или нескольких существующих столбцов. Например, если у нас есть таблица клиентов ниже,

image

мы можем создать признаки, найдя месяц из столбца joined или взяв натуральный логарифм из столбца income. Это оба преобразования, потому что они используют информацию только из одной таблицы.

image

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

Этот процесс включает в себя группирование таблицы loans по клиенту, вычисление агрегации и последующее объединение полученных данных с данными клиента. Вот как мы могли бы сделать это в Python, используя язык Pandas.

import pandas as pd

# Group loans by client id and calculate mean, max, min of loans
stats = loans.groupby('client_id')['loan_amount'].agg(['mean', 'max', 'min'])
stats.columns = ['mean_loan_amount', 'max_loan_amount', 'min_loan_amount']

# Merge with the clients dataframe
stats = clients.merge(stats, left_on = 'client_id', right_index=True, how = 'left')

stats.head(10)

image

Эти операции сами по себе не сложны, но если у нас есть сотни переменных, разбросанных по десяткам таблиц, этот процесс невозможно осуществить вручную. В идеале нам нужно решение, которое может автоматически выполнять преобразования и агрегации для нескольких таблиц и объединять полученные данные в одну таблицу. Несмотря на то, что Pandas — отличный ресурс, есть еще много манипуляций с данными, которые мы хотим сделать вручную! (Подробнее о ручном проектировании признаков можно найти в превосходном справочнике Python Data Science Handbook).

Featuretools


К счастью, featuretools — это именно то решение, которое мы ищем. Эта библиотека для Python с открытым исходным кодом автоматически создает множество признаков из набора связанных таблиц. Featuretools основан на методе, известном как «Deep Feature Synthesis», который звучит гораздо более впечатляюще, чем на самом деле (название происходит от объединения нескольких признаков, а не потому, что он использует глубокое обучение!).

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

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

  • clients: базовая информация о клиентах в кредитном объединении. Каждый клиент имеет только одну строку в этом фрейме данных

    image

  • loans: кредиты, предоставленные клиентам. Каждый кредит имеет только собственную строку в этом фрейме данных, но клиенты могут иметь несколько кредитов.
    image

  • payments: платежи по кредитам. Каждый платеж имеет только одну строку, но каждый заем будет иметь несколько платежей.

    image

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

Entities и EntitySets (сущности и наборы сущностей)


Первые две концепции featuretools — это entities и entitysets. Entity — это просто таблица (или DataFrame, если вы думаете в Pandas). EntitySet — это набор таблиц и взаимосвязей между ними. Представьте, что entityset — это просто еще одна структура данных Python со своими собственными методами и атрибутами.

Мы можем создать пустой набор сущностей в featuretools, используя следующее:

import featuretools as ft
# Create new entityset
es = ft.EntitySet(id = 'clients')

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

# Create an entity from the client dataframe
# This dataframe already has an index and a time index
es = es.entity_from_dataframe(entity_id = 'clients', dataframe = clients, 
                              index = 'client_id', time_index = 'joined')

Фрейм данных loans также имеет уникальный индекс loan_id, и синтаксис для добавления его к набору сущностей такой же, как и для clients. Однако для фрейма данных платежей нет уникального индекса. Когда мы добавляем эту сущность в набор сущностей, нам нужно передать параметр make_index = True и указать имя индекса. Кроме того, хотя featuretools будет автоматически выводить тип данных каждого столбца в сущносте, мы можем переопределить это, передав словарь типов столбцов параметру variable_types.

# Create an entity from the payments dataframe
# This does not yet have a unique index
es = es.entity_from_dataframe(entity_id = 'payments', 
                              dataframe = payments,
                              variable_types = {'missed': ft.variable_types.Categorical},
                              make_index = True,
                              index = 'payment_id',
                              time_index = 'payment_date')

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

image

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

Связи между таблицами


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

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

Чтобы формализовать отношения в featuretools, нам нужно только указать переменную, которая связывает две таблицы вместе. clients и таблица loans связаны с помощью переменной client_id, а loans и payments — с помощью loan_id. Синтаксис для создания отношения и добавления его в набор сущностей показан ниже:

# Relationship between clients and previous loans
r_client_previous = ft.Relationship(es['clients']['client_id'],
                                    es['loans']['client_id'])

# Add the relationship to the entity set
es = es.add_relationship(r_client_previous)

# Relationship between previous loans and previous payments
r_payments = ft.Relationship(es['loans']['loan_id'],
                                      es['payments']['loan_id'])

# Add the relationship to the entity set
es = es.add_relationship(r_payments)

es

image

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

Примитивы признаков


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

  • Агрегации: операции, выполненные в отношении «родитель-ребенок» (один-ко-многим), которые группируются по родителям и рассчитывают статистику по детям. Примером является группировка таблицы loans по client_id и определение максимальной суммы кредита для каждого клиента.
  • Преобразования: операции, выполняемые с одной таблицы в один или несколько столбцов. В качестве примера берется разница между двумя столбцами в одной таблице или абсолютное значение столбца.

Новые признаки создаются в featuretools, используя эти примитивы, либо сами по себе, либо в виде нескольких примитивов. Ниже приведен список некоторых примитивов в featuretools (мы также можем определить кастомные примитивы):

image

Эти примитивы могут быть использованы сами по себе или объединены для создания признаков. Для создания признаков с указанными примитивами мы используем функцию ft.dfs (расшифровывается как глубокий синтез признаков). Мы передаем набор сущностей target_entity, который представляет собой таблицу, в которую мы хотим добавить признаки, выбранные trans_primitives (преобразования) и agg_primitives (агрегаты):

# Create new features using specified primitives
features, feature_names = ft.dfs(entityset = es, target_entity = 'clients', 
                                 agg_primitives = ['mean', 'max', 'percent_true', 'last'],
                                 trans_primitives = ['years', 'month', 'subtract', 'divide'])

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

image

У нас также есть ряд примитивов агрегации, таких как средние суммы платежей для каждого клиента:

image

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

image

Полный фрейм данных содержит 793 столбца новых признаков!

Глубокий Синтез Признаков


Теперь у нас есть все для понимания глубокого синтеза признаков (dfs). Фактически, мы уже выполняли dfs в предыдущем вызове функции! Глубокий признак — это просто признак, состоящий из объединения нескольких примитивов, а dfs — это имя процесса, который создает эти признаки. Глубина глубокого признака — это количество примитивов, необходимых для создания признака.

Например, столбец MEAN (payment.payment_amount) представляет собой глубокий признак с глубиной 1, поскольку он был создан с использованием одной агрегации. Элемент с глубиной два — это LAST(loans(MEAN(payment.payment_amount)). Это делается путем объединения двух агрегаций: LAST (самая последняя) поверх MEAN. Это представляет средний размер платежа по самому последнему кредиту для каждого клиента.

image

Мы можем составлять признаки на любую глубину, какую захотим, но на практике я никогда не выходил за пределы глубины 2. После этого момента признаки трудно интерпретировать, но я призываю всех, кто заинтересован, попробовать «углубиться».

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

# Perform deep feature synthesis without specifying primitives
features, feature_names = ft.dfs(entityset=es, target_entity='clients', 
                                 max_depth = 2)

features.head()

image

Featuretools создал много новых признаков для нас. Хотя этот процесс автоматически создает новые признаки, он не заменит специалиста по Data Science, потому что нам еще предстоит выяснить, что делать со всеми этими признаками. Например, если наша цель состоит в том, чтобы предсказать, будет ли клиент погашать кредит, мы могли бы искать признаки, наиболее соответствующие конкретному результату. Более того, если у нас есть знание предметной области, мы можем использовать его для выбора конкретных примитивов признаков или для глубокого синтеза признаков-кандидатов.

Следующие шаги


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

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

Проклятие размерности сочетается с сокращением признаков (также известным как выбор признаков): процессом удаления ненужных признаков. Это может принимать различные формы: Principal Component Analysis (PCA), SelectKBest, использование значений признаков из модели или автоматическое кодирование с использованием глубоких нейронных сетей. Однако сокращение признаков — это отдельная тема для другой статьи. На данный момент мы знаем, что мы можем использовать featuretools для создания множества признаков из множества таблиц с минимальными усилиями!

Вывод


Как и многие темы в машинном обучении, автоматизированное проектирование признаков с помощью featuretools — сложная концепция, основанная на простых идеях. Используя понятия наборов сущностей, сущностей и отношений, featuretools может выполнять глубокий синтез признаков для создания новых признаков. Глубокий синтез признаков, в свою очередь, объединяет примитивы — агрегаты, которые действуют через отношения «один ко многим» между таблицами, и преобразования, функции, применяемые к одному или нескольким столбцам в одной таблице, — для создания новых признаков из нескольких таблиц.

image

Узнайте подробности, как получить востребованную профессию с нуля или Level Up по навыкам и зарплате, пройдя платные онлайн-курсы SkillFactory:



Читать еще


SkillFactory
Школа Computer Science. Скидка 10% по коду HABR

Комментарии 1

    0

    Получается, это просто высокоуровневый интерфейс регенерации всевозможных комбинаций признаков. В современном глубоком обучение действительно признаки делаются не вручную ( я имею в виду выбор признаков конечно а не прописывание формул)?
    Просто какая же должна быть зарплата у специалистов чтобы удорожание и так недешевых вычислительных мощностей оказалось выгоднее ручного конструирования признаков? Ведь при таком росте количества признаков сложность вычисления возрастет как минимум линейно, а на самом деле сильнее.
    Практический вопрос — автоскейлинг то оно умеет?
    P. S. Только сейчас заметил что статья о Data Sines а не о машинном обучении как таковом

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

    Самое читаемое