Несмотря на то, что линейная регрессия является одним из первых методов машинного обучения, она по-прежнему остается лучшим выбором среди специалистов по машинному обучению для решения задачи регрессии. За последние три года более 80% респондентов ежегодного опроса Kaggle о состоянии науки о данных и машинного обучения упомянули линейную регрессию как алгоритм машинного обучения, который они чаще всего используют. IBM Db2 предоставляет хранимую процедуру (SP) в базе данных для линейной регрессии как часть своей библиотеки ML, которая представляет собой набор из более чем 200 SP для выполнения различных задач ML в базе данных. Используя линейную регрессию SP и другие функции библиотеки машинного обучения DB2, специалисты по машинному обучению могут создавать и развертывать модели линейной регрессии в базе данных, если их набор данных машинного обучения доступен в базе данных Db2. В этом посте я покажу вам следующие этапы построения и использования конвейера линейной регрессии с использованием SQL с базой данных Db2:

Давай начнем.

Задача регрессии

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

Я хочу изучить функцию множественной линейной регрессии следующей формы уравнения, которая будет использовать в качестве входных данных первые четыре столбца — ВОЗРАСТ, СЕМЕЙНОЕ ПОЛОЖЕНИЕ и ПРОФЕССИЯ — и прогнозировать СУММУ ПОКУПОК.

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

Следуя этим шагам, я создал таблицу Db2 с именем GOSALES_FULL в схеме GOSALES и загрузил в нее набор данных.

Поезд / тестовый сплит

Во-первых, я разделю записи из таблицы GOSALES_FULL на два раздела: учебный раздел и тестовый раздел. Для создания этих разделов я буду вызывать хранимую процедуру (SP) SPLIT_DATA следующим образом.

CALL IDAX.SPLIT_DATA('intable=GOSALES.GOSALES_FULL, id=ID, traintable=GOSALES.GOSALES_TRAIN, testtable=GOSALES.GOSALES_TEST, fraction=0.8, seed=1')

Вот параметры, которые я передал этому SP: (1) intable: входная таблица, из которой я хочу создать разделы. Значение — GOSALES_FULL; (2) id: имя столбца id во входной таблице; (3) traintable: имя, которое я хочу дать таблице, в которой будут записи обучения; (4) testtable: имя выходной таблицы, в которой SP будет хранить тестовые записи; (5) дробь: часть записей, которые мне нужны в обучающем разделе; (6) семя: я могу установить значение воспроизводимости одних и тех же разделов.

SP случайным образом разделит записи из таблицы GOSALES_FULL на две выходные таблицы: GOSALES_TRAIN и GOSALES_TEST. Следующие два оператора SQL будут подсчитывать количество записей в этих двух таблицах.

SELECT count(*) FROM GOSALES.GOSALES_TRAIN

SELECT count(*) FROM GOSALES.GOSALES_TEST

Приведенные выше подсчеты подтверждают, что таблицы train и test содержат 80% и 20% записей соответственно от исходной таблицы с 60252 записями.

Исследование данных

Теперь я рассмотрю некоторые образцы записей из обучающего набора данных GOSALES_TRAIN.

SELECT * FROM GOSALES.GOSALES_TRAIN FETCH FIRST 5 ROWS ONLY

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

CALL IDAX.SUMMARY1000('intable=GOSALES.GOSALES_TRAIN, outtable=GOSALES.GOSALES_TRAIN_SUM1000, incolumn=GENDER;AGE;MARITAL_STATUS;PROFESSION')

В этом вызове SP параметр intable имеет имя обучающей таблицы, из которой я хотел собрать сводную статистику. параметр outtable имеет имя выходной таблицы, в которой я хочу, чтобы SP сохранял сводную статистику всей обучающей таблицы. В параметре incolumn я перечисляю столбцы, статистику которых хочу собрать.

Я вызываю эту SP со следующими параметрами: (1) intable: имя таблицы, для которой я хочу собрать сводную статистику, в данном случае обучающий раздел; (2) outtable: имя таблицы, в которой я хочу, чтобы SP хранил общую сводную статистику, (3) incolumn: список столбцов, чью статистику я хочу собрать.

SUMMARY1000 SP сохраняет собранную статистику из обучающей таблицы в трех выходных таблицах: (1) GOSALES_TRAIN_SUM1000: содержит сводную статистику всех столбцов, перечисленных в параметре incolumn; (2) GOSALES_TRAIN_SUM1000_NUM: имеет сводную статистику только числовых столбцов из параметра incolumn, (3) GOSALES_TRAIN_SUM1000_CHAR: имеет сводную статистику категориальных столбцов из параметра incolumn.

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

SELECT * FROM GOSALES.GOSALES_TRAIN_SUM1000_NUM

Набор данных имеет один столбец числовых признаков, ВОЗРАСТ. Эта сводная таблица содержит ряд статистических данных, таких как среднее значение, дисперсия, асимметрия. Кроме того, в таблице указано, что в столбце AGE отсутствует 1878 значений.

Точно так же я нахожу следующую сводную статистику из таблицы GOSALES.GOSALES_TRAIN_SUM1000_CHAR.

SELECT * FROM GOSALES.GOSALES_TRAIN_SUM1000_CHAR

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

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

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

Работа с отсутствующими значениями

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

Столбец AGEc: я заменю отсутствующие значения в столбце AGE средним значением возраста:

CALL IDAX.IMPUTE_DATA('intable=GOSALES.GOSALES_TRAIN, incolumn=AGE, method=mean')

В приведенном выше вызове SP я передал три параметра: (1) intable: имя входной таблицы, то есть GOSALES_TRAIN, (2) incolumn: имя столбца для подстановки отсутствующих значений. AGE — это имя столбца. (3) метод: поддерживаемая стратегия вменения. Я выбрал среднее).

Точно так же следующие вызовы SP заменят отсутствующие значения в столбцах GENDER, MARITAL_STATUS и PROFESSION наиболее частым значением каждого столбца. Я просмотрел наиболее часто встречающиеся значения каждого столбца в таблице GOSALES_TRAIN_SUM1000_CHAR, созданной на этапе исследования данных.

Подстановка отсутствующих значений в столбце GENDER:

CALL IDAX.IMPUTE_DATA('intable=GOSALES.GOSALES_TRAIN, method=replace, nominalValue=M, incolumn=GENDER')

Ввод отсутствующих значений в столбце MARITAL_STATUS:

CALL IDAX.IMPUTE_DATA('intable=GOSALES.GOSALES_TRAIN, method=replace, nominalValue=Married, incolumn=MARITAL_STATUS')

Подстановка отсутствующих значений в столбце ПРОФЕССИЯ:

CALL IDAX.IMPUTE_DATA('intable=GOSALES.GOSALES_TRAIN, method=replace, nominalValue=Other, incolumn=PROFESSION')

Выполнив следующую инструкцию SQL, я могу подтвердить, что столбец AGE в наборе обучающих данных теперь свободен от пропущенных значений:

SELECT count(*) FROM GOSALES.GOSALES_TRAIN WHERE AGE IS NULL

Точно так же следующие инструкции будут подсчитывать пропущенные значения в столбцах GENDER, MARITAL_STATUS и PROFESSION. Все они больше не имеют пропущенного значения.

Подсчитайте пропущенные значения в КОЛОННЕ ГЕНДЕР:

SELECT count(*) FROM GOSALES.GOSALES_TRAIN WHERE GENDER IS NULL

Подсчитайте пропущенные значения в столбце MARITAL_STATUS:

SELECT count(*) FROM GOSALES.GOSALES_TRAIN WHERE MARITAL_STATUS IS NULL

Подсчитайте пропущенные значения в столбце ПРОФЕССИЯ:

SELECT count(*) FROM GOSALES.GOSALES_TRAIN WHERE PROFESSION IS NULL

Работа с именными столбцами

Алгоритм линейной регрессии требует, чтобы все его входные столбцы были числовыми. Таким образом, прежде чем вызывать алгоритм линейной регрессии, специалисты по машинному обучению преобразуют любые нечисловые столбцы в числа в соответствии с некоторой схемой кодирования, например 1-горячее кодирование. SP линейной регрессии Db2 изначально может обрабатывать номинальные столбцы. Когда во входной таблице есть какой-либо номинальный столбец, SP внутренне преобразует его в набор числовых столбцов с использованием 1-горячего кодирования. Итак, я могу оставить три именных столбца — ПОЛ, СЕМЕЙНОЕ_СОСТОЯНИЕ и ПРОФЕССИЯ — как есть, и пусть SP позаботится о них.

Теперь набор данных GOSALES_TRAIN готов к обучению модели.

Обучение модели

Следующий вызов SP LINEAR_REGRESSION начнет обучение модели линейной регрессии с использованием обучающих примеров из таблицы GOSALES_TRAIN. SP будет использовать список столбцов, упомянутых в параметре incolum, в качестве входных признаков и столбец из параметра target в качестве выходного столбца. Поскольку для параметра перехвата установлено значение true, SP узнает значение перехвата.

CALL IDAX.LINEAR_REGRESSION('model=GOSALES.GOSALES_LINREG, intable=GOSALES.GOSALES_TRAIN, id=ID, target=PURCHASE_AMOUNT,incolumn=AGE;GENDER;MARITAL_STATUS;PROFESSION, intercept=true')

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

CALL IDAX.LIST_MODELS('format=short, all=true')

Кроме того, LINEAR_REGRESSION SP сохраняет изученные значения перехвата и коэффициентов вместе с несколькими другими значениями изученных параметров в таблице. Имя таблицы имеет следующую форму: MODELNAME_MODEL. Для модели GOSALES_LINREG имя ее таблицы метаданных — GOSALES_LINREG_MODEL.

Следующий SQL отобразит значения изученных параметров модели.

SELECT VAR_NAME, LEVEL_NAME, VALUE FROM GOSALES.GOSALES_LINREG_MODEL

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

Создание прогнозов с помощью модели

На этом этапе я буду использовать модель GOSALES_LINREG для прогнозирования суммы покупки клиентов в таблице GOSALE_TEST. Прежде чем генерировать прогнозы, я предварительно обработаю этот набор данных, используя шаги предварительной обработки, которые я использовал с набором обучающих данных, которые вводили пропущенные значения. Я буду использовать следующие операторы SQL для заполнения отсутствующих значений в столбцах AGE, GENDER, MARITAL_STATUS и PROFESSION тестового набора данных.

Подстановка отсутствующих значений в столбце ВОЗРАСТ:

CALL IDAX.IMPUTE_DATA('intable=GOSALES.GOSALES_TEST, method=mean, incolumn=AGE')

Подстановка отсутствующих значений в столбце ПОЛ:

CALL IDAX.IMPUTE_DATA('intable=GOSALES.GOSALES_TEST, method=replace, nominalValue=M, incolumn=GENDER')

Подстановка отсутствующих значений в столбце MARITAL_STATUS:

CALL IDAX.IMPUTE_DATA('intable=GOSALES.GOSALES_TEST, method=replace, nominalValue=Married, incolumn=MARITAL_STATUS')

Подстановка пропущенных значений в столбце ПРОФЕССИЯ:

CALL IDAX.IMPUTE_DATA('intable=GOSALES.GOSALES_TEST, method=replace, nominalValue=Other, incolumn=PROFESSION')

Теперь набор тестовых данных готов к передаче в качестве входных данных для модели.

PREDICT_LINEAR_REGRESSION SP будет использовать модель GOSALES_LINREG для генерации прогнозов для записей в таблице GOSALES_TEST. SP сохранит прогнозы в таблице GOSALES_TEST_PREDICTIONS в соответствии с именем таблицы, указанным в параметре outtable.

CALL IDAX.PREDICT_LINEAR_REGRESSION('model=GOSALES.GOSALES_LINREG, intable=GOSALES.GOSALES_TEST, outtable=GOSALES.GOSALES_TEST_PREDICTIONS, id=ID')

Следующий SQL отображает примеры прогнозов из таблицы GOSALES_TEST_PREDICTIONS.

SELECT * FROM GOSALES.GOSALES_TEST_PREDICTIONS FETCH FIRST 5 ROWS ONLY

Оценка модели

Для тестовых записей клиентов фактическая цена покупки доступна в таблице GOSALES_TEST, а прогнозируемая цена покупки — в таблице GOSALES_TEST_PREDICTIONS. Основываясь на этих фактических и прогнозируемых суммах покупки, я теперь могу вычислить среднеквадратичную ошибку (MSE), среднюю абсолютную ошибку (MAE) и среднюю абсолютную процентную ошибку (MAPE) с помощью SQL. Это поможет мне оценить прогностическую эффективность модели.

MSE:

Я буду использовать MSE SP для вычисления MSE:

CALL IDAX.MSE('intable=GOSALES.GOSALES_TEST, id=ID, target=PURCHASE_AMOUNT, resulttable=GOSALES.GOSALES_TEST_PREDICTIONS, resulttarget=PURCHASE_AMOUNT')

MAE:

Я буду использовать MAE SP для расчета MAE:

CALL IDAX.MAE('intable=GOSALES.GOSALES_TEST, id=ID, target=PURCHASE_AMOUNT, resulttable=GOSALES.GOSALES_TEST_PREDICTIONS, resulttarget=PURCHASE_AMOUNT')

MAPE:

Я написал следующий SQL для вычисления MAPE:

SELECT avg(abs(A.PURCHASE_AMOUNT - B.PURCHASE_AMOUNT) / A.PURCHASE_AMOUNT * 100) AS MAPE FROM GOSALES.GOSALES_TEST AS A, GOSALES.GOSALES_TEST_PREDICTIONS AS B WHERE A.ID = B.ID

Отказ от модели

Если я хочу сбросить эту модель, я могу использовать SP DROP_MODEL:

CALL IDAX.DROP_MODEL('model=GOSALES.GOSALES_LINREG')

Заключение

В этом упражнении я построил, оценил и развернул сквозной конвейер линейной регрессии, используя 29 простых SQL-запросов, 17 из которых — вызовы SP, предоставленные Db2, а остальные — операторы SELECT. В этом рабочем процессе машинного обучения мне не нужно было выносить какие-либо данные за пределы базы данных, а также мне не требовалась отдельная инфраструктура для разработки, обучения и обслуживания моделей машинного обучения. Для многих компаний машинное обучение в базе данных может быть экономичным и более быстрым способом внедрения ИИ.

Связанные ресурсы

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

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