Предсказываем с моделями машинного обучения
Продемонстрируем мощь алгоритмов машинного обучения для предсказания некой целевой переменной. В демонстрационных целях будем использовать программно сгенерированный набор о доходах и расходах людей (код представлен в конце статьи).Набор помимо перечисленной информации также включает ФИО человека, индекс города проживания и сумму дотаций из регионального бюджета:
Нашей целью будет являться предсказание расходов человека по доходу и сумме помощи. При этом намеренно установлена следующая зависимость:
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['сумма_помощи']