Предсказываем с моделями машинного обучения
Продемонстрируем мощь алгоритмов машинного обучения для предсказания некой целевой переменной. В демонстрационных целях будем использовать программно сгенерированный набор о доходах и расходах людей (код представлен в конце статьи).Набор помимо перечисленной информации также включает ФИО человека, индекс города проживания и сумму дотаций из регионального бюджета:
Нашей целью будет являться предсказание расходов человека по доходу и сумме помощи. При этом намеренно установлена следующая зависимость:
data_m['расходы'] = 2*np.sqrt(data_m['зарплата'])+0.5*data_m['сумма_помощи']
Для предсказания будем использовать популярную реализацию алгоритма градиентного бустинга LightGBM.
Рассмотрим минимальные шаги, необходимые для получения модели (без ее настройки, о которой пойдет речь в последующих статьях). В частности, отделим тренировочные данные (для обучения) и тестовые (для проверки качества), инициируем процесс обучения и сравним предсказанные и тестовые данные.
Сначала реализуем этап обучения:
X_tr, X_ts, y_tr, y_ts = train_test_split(data_m[['зарплата', 'сумма_помощи']], data_m['расходы'], test_size=0.2)
train_data = lgb.Dataset(X_tr, label=y_tr)
test_data = lgb.Dataset(X_ts, label=y_ts)
params = {"objective": "regression"}
bst = lgb.train(params, train_set = train_data, valid_sets=[test_data])С помощью train_test_split мы разделили данные на обучающую и тестовую выборки, затем заполнили внутренний тип библиотеки lightgbm - Dataset данными для обучения и тренировки, задали параметры модели в словаре params (пока достаточно лишь задания типа задачи - классификация/регрессия).
После завершения обучения train вернет экземпляр объекта Booster, который будет использован для будущих предсказаний.
y_pr = bst.predict(X_ts, num_iteration=bst.best_iteration)
Как можно заметить, алгоритм смог даже с настройками по умолчанию уловить закономерности в формировании расходов и достаточно точно предсказать данные.
Ниже привожу код для генерации исследованного набора данных:
import pandas as pd
import numpy as np
import string
import lightgbm as lgb
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_absolute_error, mean_absolute_percentage_error
np.random.seed(0)
letters = np.array(list(string.ascii_uppercase))
digits = np.arange(0,10)
people_num = 10000
towns_num = 200 # количество городов, нацело делит people_num для удобства
# людям соответствуют по три случайные буквы алфавита (имя, фамилия)
names = np.random.choice(letters, size=(people_num,3))
# зарплата от 20 до 50 тыс. рублей, случайное равномерное распределение
salary = np.random.uniform(20,500, size=people_num)
# индекс города - по семь цифр из алфавита, их меньше чем людей,
# так как предполагаем одинаковые города для разных людей
loc_ind_p = np.random.choice(digits, size=(towns_num,7))
loc_ind = np.tile(loc_ind_p, (people_num//towns_num,1))
# склеим буквы имен и фамилий, а также
# индексы городов
names = pd.DataFrame(names, dtype='str').apply(lambda x:' '.join(x),axis=1)
loc_ind = pd.DataFrame(loc_ind, dtype='str').apply(lambda x:''.join(x),axis=1)
data = pd.DataFrame({'ФИО':names, 'индекс_города':loc_ind,
'зарплата':salary})
data['зарплата'] = np.round(data['зарплата'],2)
helps = np.random.uniform(5,10, size = towns_num)
town_help = pd.DataFrame({'индекс_города':pd.DataFrame(loc_ind_p, dtype='str')
.apply(lambda x:''.join(x), axis=1),
'сумма_помощи':helps})
town_help['сумма_помощи'] = np.round(town_help['сумма_помощи'],2)
data_m = pd.merge(data, town_help, left_on = 'индекс_города',
right_on='индекс_города')
# перемешиваем данные
data_m = data_m.sample(frac=1).reset_index(drop=True)
data_m['расходы'] = 2*np.sqrt(data_m['зарплата'])+\
0.5*data_m['сумма_помощи']