Любой, кто участвовал в хакатонах и соревнованиях по машинному обучению, может подтвердить, насколько важной может быть разработка функций. Часто это разница между попаданием в топ-10 таблицы лидеров и выходом за пределы топ-50!

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

Для этого мы будем использовать библиотеку разработки функций Python под названием Featuretools. Но прежде чем мы перейдем к этому, мы сначала рассмотрим основные строительные блоки FE, разберемся с ними с помощью интуитивно понятных примеров, а затем, наконец, погрузимся в удивительный мир автоматизированной разработки функций с использованием набора данных BigMart Sales.

Оглавление

  1. Что есть особенность?
  2. Что такое Feature Engineering?
  3. Почему требуется разработка функций?
  4. Автоматизация проектирования функций
  5. Введение в Featuretools
  6. Реализация Featuretools
  7. Featuretools Интерпретируемость

1. Что такое особенность?

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

Например, предположим, что у вас есть список студентов. Этот список содержит имя каждого студента, количество часов, которые они изучили, их IQ и их общие оценки на предыдущих экзаменах. Теперь вам предоставляется информация о новом ученике - количество часов, которые он / она учил, и его IQ, но его / ее оценки отсутствуют. Вы должны оценить его / ее вероятные оценки.

Здесь вы использовали бы IQ и study_hours, чтобы построить прогностическую модель для оценки этих недостающих оценок. Итак, IQ и study_hours называются функциями этой модели.

2. Что такое разработка функций?

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

Теперь, чтобы создать новую функцию, мы можем использовать Item_Weight и Item_Price. Итак, давайте создадим функцию под названием Price_per_Weight. Это не что иное, как цена предмета, деленная на вес предмета. Этот процесс называется функциональной инженерией.

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

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

  • Монтвила, преподобный Юозас
  • Грэм, мисс Маргарет Эдит
  • Джонстон, мисс Кэтрин Хелен «Кэрри»
  • Бер, г-н Карл Хауэлл
  • Дули, мистер Патрик

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

Оказывается, такие титулы, как «Дона», «Леди», «Графиня», «Капитан», «Кол», «Дон», «Доктор», «Майор», «Преподобный», «Сэр» и «Джонхир». 'довольно редки и могут быть помещены под одним ярлыком. Назовем это раритетное_заголовок. Помимо этого, титулы «Mlle» и «Ms» можно помещать в «Miss», а «Mme» можно заменять на «Mrs».

Следовательно, новая функция заголовка будет иметь только 5 уникальных значений, как показано ниже:

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

3. Почему требуется разработка функций?

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

В одном из самых популярных соревнований Kaggle, «Прогнозирование спроса на совместное использование велосипедов», участников просят спрогнозировать спрос на аренду в Вашингтоне, округ Колумбия, на основе исторических моделей использования в зависимости от погоды, времени и других данных.

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

  1. Ячейки часов: новая функция была создана путем объединения функции часов с помощью дерева решений.
  2. Temp Bins. Аналогично, функция интервалов для переменной температуры.
  3. Подборки по годам: было создано 8 квартальных подборок сроком на 2 года.
  4. Тип дня: дни были разделены на "будние", "выходные" или "праздничные".

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

4. Автоматизация проектирования функций

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

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

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

5. Введение в Featuretools

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

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

  • Сущности
  • Глубокий синтез функций (DFS)
  • Примитивы функций

а) Сущность можно рассматривать как представление фрейма данных Pandas. Набор из нескольких сущностей называется набором сущностей.

б) Deep Feature Synthesis (DFS) не имеет ничего общего с глубоким обучением. Не волнуйся. На самом деле DFS - это метод разработки функций и основа Featuretools. Это позволяет создавать новые функции как из одного, так и из нескольких фреймов данных.

c) DFS создает функции, применяя примитивы функций к отношениям сущностей в EntitySet. Эти примитивы - часто используемые методы для создания функций вручную. Например, примитивное «среднее» найдет среднее значение переменной на агрегированном уровне.

Лучший способ понять и освоиться с Featuretools - это применить его к набору данных. Итак, мы будем использовать набор данных из нашей Задачи практики продаж BigMart в следующем разделе, чтобы укрепить наши концепции.

6. Реализация Featuretools

Задача BigMart Sales - построить прогностическую модель для оценки продаж каждого продукта в конкретном магазине. Это поможет лицам, принимающим решения в BigMart, узнать свойства любого продукта или магазина, которые играют ключевую роль в увеличении общих продаж. Обратите внимание, что в данном наборе данных есть 1559 продуктов в 10 магазинах.

В таблице ниже показаны функции, представленные в наших данных:

Вы можете скачать данные здесь.

6.1. Установка

Featuretools доступен для Python 2.7, 3.5 и 3.6. Вы можете легко установить Featuretools с помощью pip.

pip install featuretools

6.2. Загрузка необходимых библиотек и данных

import featuretools as ft 
import numpy as np 
import pandas as pd 
train = pd.read_csv("Train_UWu5bXk.csv") 
test = pd.read_csv("Test_u94Q5KV.csv")

6.3. Подготовка данных

Для начала мы просто сохраним целевой Item_Outlet_Sales в переменной, называемой переменными sales и id, в test_Item_Identifier и test_Outlet_Identifier.

# saving identifiers 
test_Item_Identifier = test['Item_Identifier'] test_Outlet_Identifier = test['Outlet_Identifier'] 
sales = train['Item_Outlet_Sales'] 
train.drop(['Item_Outlet_Sales'], axis=1, inplace=True)

Затем мы объединим поезд и набор тестов, так как это избавит нас от необходимости повторять один и тот же шаг (и) дважды.

combi = train.append(test, ignore_index=True)

Давайте проверим недостающие значения в наборе данных.

combi.isnull().sum()

Довольно много пропущенных значений в переменных Item_Weight и Outlet_size. Давайте быстро с ними разберемся:

# imputing missing data 
combi['Item_Weight'].fillna(combi['Item_Weight'].mean(), 
                            inplace = True) 
combi['Outlet_Size'].fillna("missing", inplace = True)

6.4. Предварительная обработка данных

Я не буду выполнять обширную операцию предварительной обработки, поскольку цель этой статьи - помочь вам начать работу с Featuretools.

combi['Item_Fat_Content'].value_counts()

Кажется, что Item_Fat_Content содержит только две категории, то есть «с низким содержанием жира» и «обычный» - остальные из них мы будем считать избыточными. Итак, давайте преобразуем его в двоичную переменную.

# dictionary to replace the categories 
fat_content_dict = {'Low Fat':0, 'Regular':1, 'LF':0, 'reg':1, 
                    'low fat':0} 
combi['Item_Fat_Content'] = combi['Item_Fat_Content'].replace(   
                            fat_content_dict, regex=True)

6.5. Разработка функций с использованием Featuretools

Теперь мы можем начать использовать Featuretools для автоматизированного проектирования функций! Необходимо, чтобы в наборе данных был уникальный идентификатор (в нашем наборе данных его сейчас нет). Итак, мы создадим один уникальный идентификатор для нашего объединенного набора данных. Если вы заметили, у нас есть два идентификатора в наших данных - один для товара, а другой для торговой точки. Итак, простое объединение обоих даст нам уникальный идентификатор.

combi['id'] = combi['Item_Identifier'] + combi['Outlet_Identifier'] 
combi.drop(['Item_Identifier'], axis=1, inplace=True)

Обратите внимание, что я отказался от функции Item_Identifier, поскольку она больше не требуется. Однако я сохранил функцию Outlet_Identifier, потому что планирую использовать ее позже.

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

# creating and entity set 'es' 
es = ft.EntitySet(id = 'sales') 
# adding a dataframe 
es.entity_from_dataframe(entity_id = 'bigmart', 
                         dataframe = combi, 
                         index = 'id')

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

es.normalize_entity(base_entity_id='bigmart', 
                    new_entity_id='outlet', 
                    index = 'Outlet_Identifier', 
                    additional_variables =   
                    ['Outlet_Establishment_Year', 'Outlet_Size',  
                     'Outlet_Location_Type', 'Outlet_Type'])

Давайте проверим сводку нашего EntitySet.

print(es)

Как видно выше, он состоит из двух сущностей - bigmart и outlet. Также существует связь между двумя таблицами, соединенными Outlet_Identifier. Эти отношения будут играть ключевую роль в создании новых функций.

Теперь мы будем использовать Deep Feature Synthesis для автоматического создания новых функций. Напомним, что DFS использует примитивы функций для создания функций с использованием нескольких таблиц, присутствующих в EntitySet.

feature_matrix, feature_names = ft.dfs(entityset=es, 
                                       target_entity = 'bigmart', 
                                       max_depth = 2, 
                                       verbose = 1, 
                                       n_jobs = 3)

target_entity - это не что иное, как идентификатор объекта, для которого мы хотим создать новые функции (в данном случае это объект bigmart). Параметр max_depth управляет сложностью функций, создаваемых путем наложения примитивов. Параметр n_jobs помогает при параллельном вычислении признаков с использованием нескольких ядер.

Это все, что вам нужно сделать с Featuretools. Он сам по себе создал кучу новых функций.

Давайте посмотрим на эти недавно созданные функции.

feature_matrix.columns

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

Давайте напечатаем первые несколько строк feature_matrix.

feature_matrix.head()

У этого фрейма данных есть одна проблема - он не отсортирован должным образом. Нам нужно будет отсортировать его на основе переменной id из фрейма данных combi.

feature_matrix = feature_matrix.reindex(index=combi['id']) feature_matrix = feature_matrix.reset_index()

Теперь feature_matrix фрейма данных находится в правильном порядке.

6.6. Построение модели

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

from catboost import CatBoostRegressor

CatBoost требует, чтобы все категориальные переменные были в строковом формате. Итак, мы сначала преобразуем категориальные переменные в наших данных в строку:

categorical_features = np.where(feature_matrix.dtypes =='object')[0] 
for i in categorical_features: 
    feature_matrix.iloc[:,i]=feature_matrix.iloc[:,i].astype('str')

Давайте снова разделим feature_matrix на обучающие и тестовые наборы.

feature_matrix.drop(['id'], axis=1, inplace=True) 
train = feature_matrix[:8523] 
test = feature_matrix[8523:]
# removing uneccesary variables 
train.drop(['Outlet_Identifier'], axis=1, inplace=True) test.drop(['Outlet_Identifier'], axis=1, inplace=True)
# identifying categorical features categorical_features = np.where(train.dtypes == 'object')[0]

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

from sklearn.model_selection import train_test_split 
# splitting train data into training and validation set 
xtrain, xvalid, ytrain, yvalid = train_test_split(train, sales, 
                                                  test_size=0.25, 
                                                  random_state=11)

Наконец, мы можем обучить нашу модель. Мы будем использовать метрику оценки - RMSE (среднеквадратичная ошибка).

model_cat = CatBoostRegressor(iterations=100, learning_rate=0.3, 
                              depth=6, eval_metric='RMSE',  
                              random_seed=7) 
# training model 
model_cat.fit(xtrain, ytrain, cat_features=categorical_features, 
              use_best_model=True)
# validation score 
model_cat.score(xvalid, yvalid)

1091.244

Оценка RMSE на проверочном наборе составляет ~ 1092,24.

Эта же модель получила 1155,12 балла в общедоступной таблице лидеров. Без какой-либо разработки функций оценки составили ~ 1103 и ~ 1183 в наборе для проверки и в общедоступной таблице лидеров соответственно. Следовательно, функции, созданные Featuretools, - это не просто случайные функции, они ценные и полезные. Что наиболее важно, это невероятно экономит время на разработку функций.

7. Интерпретируемость Featuretools

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

Например, функции outlet.SUM (bigmart.Item_Weight) и outlet.STD (bigmart.Item_MRP) означают сумму веса товаров на уровне торговой точки и стандартное отклонение стоимость предметов соответственно.

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

Конечные заметки

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

Попробуйте в следующий раз, когда будете работать с любым набором данных, и дайте мне знать, как это прошло, в разделе комментариев!

Первоначально опубликовано на www.analyticsvidhya.com 22 августа 2018 г.