Действительно важной частью любой модели машинного обучения являются данные, особенно используемые функции. В этой статье мы рассмотрим, где проектирование функций относится к конвейеру машинного обучения и как выполнить некоторую разработку функций для чисел с помощью биннинга, преобразований и нормализации. Настоящее преимущество проектирования функций - это возможность улучшить предсказание ваших моделей, не усложняя модели. В этой статье мы выполним практическое кодирование с данными, взятыми с Goodreads.com, которые я нашел на Kaggle.com [1].

Данные, использованные в этой статье, относятся к рейтингам книг, и их можно скачать здесь: https://www.kaggle.com/jealousleopard/goodreadsbooks

Общий обзор конвейера машинного обучения

Общий конвейер машинного обучения состоит из 5 шагов:

  1. Спросите - что хочет сделать компания или клиент (например, спрогнозировать продажи на следующий квартал, выявить рак и т. д.)
  2. Данные - часть реальности в цифровом виде. Например, количество продаж за квартал.
  3. Возможности - данные преобразованы в числа, чтобы модель могла их понять. Некоторые из вас могут сказать: «Эй, моя модель принимает красный или зеленый цвет в качестве элемента!» Что ж, под капотом вашей модели код фактически преобразует этот красный или зеленый в 0 или 1, что обычно выполняется с помощью одного горячего кодирования.
  4. Выбор модели. Модель - это инструмент, который вы используете, чтобы ликвидировать разрыв между данными и прогнозами. Для тех из вас, кто знаком с математикой, считайте ее функцией. Ваши данные - это вход, модель - это функция, а ваш прогноз - это выход.
  5. Прогнозы - ответ на запрос «спросить». Чтобы связать это с примерами из вопроса выше, в первом квартале (Q1) было продано 10 000 единиц или у пациента XYZ рак.

На рисунке ниже показан аналогичный процесс построения конвейера машинного обучения, взятый из Microsoft [2]:

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

Биннинг

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

#Load Packages
import numpy as npimport pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import linear_model 
from sklearn.model_selection import cross_val_score
import sklearn.preprocessing as pp
#load data into dataframe
books_file = pd.read_csv('books.csv', error_bad_lines=False)

Поместите код error_bad_lines в функцию pd.read_csv, так как есть несколько нечистых строк. В противном случае Python будет кричать на нас.

#Taking a look at the data
books_file.head()

Теперь приступим к построению гистограмм.

#Plotting a histogram - no feature engineering
sns.set_style('whitegrid') #Picking a background color
fig, ax =plt.subplots()
books_file['ratings_count'].hist(ax=ax, bins=10) #State how many bins you want
ax.tick_params(labelsize=10)
ax.set_xlabel('Ratings Count')
ax.set_ylabel('Event') #How many times the specific numbers of ratings count happened

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

Преобразование журнала

#Plotting a histogram - log scale
sns.set_style('whitegrid') #Picking a background color
fig, ax =plt.subplots()
books_file['ratings_count'].hist(ax=ax, bins=10) #State how many bins you want
ax.set_yscale('log') #Recaling to log, since large numbers can mess up the weightings for some models
ax.tick_params(labelsize=10)
ax.set_xlabel('Ratings Count')
ax.set_ylabel('Event') #How many times the specific numbers of ratings count happened

Теперь мы сделаем рейтинговые прогнозы на основе нормальных значений и преобразованных в журнал значений рейтинговых подсчетов.

Для приведенного ниже кода мы добавляем +1, поскольку журнал 0 не определен, что может привести к взрыву нашего компьютера (шучу, вроде).

books_file['log_ratings_count'] = np.log10(books_file['ratings_count']+1)
#Using ratings count to predict average rating.  Cross Validation (CV) is normally 5 or 10.
base_model = linear_model.LinearRegression()
base_scores = cross_val_score(base_model, books_file[['ratings_count']], 
                              books_file['average_rating'], cv=10)
log_model = linear_model.LinearRegression()
log_scores = cross_val_score(log_model, books_file[['log_ratings_count']], 
                              books_file['average_rating'], cv=10)
#Display the R^2 values.  STD*2 for 95% confidence level
print("R^2 of base data: %0.4f (+/- %0.4f)" % (base_scores.mean(), base_scores.std()*2))
print("R^2 of log data: %0.4f (+/- %0.4f)" % (log_scores.mean(), log_scores.std()*2))

R² базовых данных: -0,0024 (+/- 0,0125)

R² данных журнала: 0,0107 (+/- 0,0365)

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

Масштабирование функций

Мы рассмотрим три способа масштабирования функций: минимальное максимальное масштабирование, стандартизация и нормализация L2.

#Min-max scaling
books_file['minmax'] = pp.minmax_scale(books_file[['ratings_count']])
#Standarization
books_file['standardized'] = pp.StandardScaler().fit_transform(books_file[['ratings_count']])
#L2 Normalization
books_file['l2_normalization'] = pp.normalize(books_file[['ratings_count']], axis=0) #Needs axis=0 for graphing
#Plotting histograms of scaled features
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4,1, figsize=(8, 7))
fig.tight_layout(h_pad=2.0)
#Normal rating counts
books_file['ratings_count'].hist(ax=ax1, bins=100)
ax1.tick_params(labelsize=10)
ax1.set_xlabel('Review ratings count', fontsize=10)
#Min max scaling
books_file['minmax'].hist(ax=ax2, bins=100)
ax2.tick_params(labelsize=10)
ax2.set_xlabel('Min max scaled ratings count', fontsize=10)
#Standardization
books_file['standardized'].hist(ax=ax3, bins=100)
ax3.tick_params(labelsize=10)
ax3.set_xlabel('Standardized ratings_count count', fontsize=10)
#L2 Normalization
books_file['l2_normalization'].hist(ax=ax4, bins=100)
ax4.tick_params(labelsize=10)
ax4.set_xlabel('Normalized ratings count count', fontsize=10)

Теперь мы сделаем прогнозы на основе наших масштабированных данных по трем функциям.

#Using ratings count to predict average rating. Cross Validation (CV) is normally 5 or 10.
base_model = linear_model.LinearRegression()
base_scores = cross_val_score(base_model, books_file[['ratings_count']], 
books_file['average_rating'], cv=10)
minmax_model = linear_model.LinearRegression()
minmax_scores = cross_val_score(log_model, books_file[['minmax']], 
books_file['average_rating'], cv=10)
standardized_model = linear_model.LinearRegression()
standardized_scores = cross_val_score(base_model, books_file[['standardized']], 
books_file['average_rating'], cv=10)
l2_normalization_model = linear_model.LinearRegression()
l2_normalization_scores = cross_val_score(log_model, books_file[['l2_normalization']], 
books_file['average_rating'], cv=10)
#Display R^2 values. STD*2 for 95% confidence level
print("R^2 of base data: %0.4f (+/- %0.4f)" % (base_scores.mean(), base_scores.std()*2)) 
print("R^2 of minmax scaled data: %0.4f (+/- %0.4f)" % (minmax_scores.mean(), minmax_scores.std()*2))
print("R^2 of standardized data: %0.4f (+/- %0.4f)" % (standardized_scores.mean(), standardized_scores.std()*2)) 
print("R^2 of L2 normalized data: %0.4f (+/- %0.4f)" % (l2_normalization_scores.mean(), l2_normalization_scores.std()*2))

R² базовых данных: -0,0024 (+/- 0,0125)

R² масштабированных данных minmax: 0,0244 (+/- 0,0298)

R² стандартизованных данных: 0,0244 (+/- 0,0298)

R² нормализованных данных L2: 0,0244 (+/- 0,0298)

Небольшое улучшение по сравнению с преобразованиями журнала. Поскольку большинство типов масштабирования графически отображали одну и ту же форму, неудивительно, что они дали одинаковые значения для R в квадрате. Несколько замечаний по каждому методу масштабирования. Минимальное максимальное значение подходит для получения значений всех функций от 0 до 1. Стандартизация хороша для масштабирования дисперсии функций, поэтому среднее значение = 0, а дисперсия = 1 (также известный как стиль нормального распределения). Нормализация L2 работает, преобразовывая масштаб функций в евклидову плоскость или норму плоскости XY. Важное замечание: масштабирование функции не меняет форму вашей функции, так как внутри оно делится на константу.

Заключение

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

Лично я считаю, что min max хорошо работает при работе с распределениями вероятностей с большинством других функций в других наборах данных. Аналогичным образом, стандартизация и нормализация L2 работают для уменьшения числа действительно больших чисел до аналогичных функций относительно выбранного анализируемого набора данных.

Заявление об ограничении ответственности: все, что изложено в этой статье, принадлежит мне, а не работодателю.

[1] Kaggle, Goodreads-books (2019), https://www.kaggle.com/jealousleopard/goodreadsbooks
[2] Microsoft, Что такое конвейеры машинного обучения? (2019), https://docs.microsoft.com/en-us/azure/machine-learning/service/concept-ml-pipelines