Рынок подержанных автомобилей в Турции достаточно активен. Поэтому прогноз цен на автомобили сильно варьируется. В этой статье сравниваются модели машинного обучения и выбирается лучшая модель для прогнозирования цен.
Модель обучения была выполнена путем разделения моделей по маркам автомобилей вместо обучения одной большой модели как для эффективных процессов оптимизации, так и для более эффективного использования мощности и времени компьютера. При обучении использовалось около 100 000 данных с 12 функциями. Сравниваются модели машинного обучения:
- Линейная регрессия
- Хребет
- Лассо
- Эластичная сетка
- K-Ближайшие соседи
- Случайный лес
- XGBOOST
- Машина для повышения градиента
Прежде всего, модели были обучены с параметрами по умолчанию. Затем к этим моделям была применена гиперпараметрическая оптимизация. Значения и оценки параметров в обоих случаях были записаны для последующего просмотра.
Предварительная обработка данных
Данные, полученные с помощью методов веб-парсинга (возможно, это можно будет подробно обсудить в другой статье), загружаются из базы данных. Когда первые библиотеки процессов импортируются, наши данные конвертируются в DataFrame, а затем проверяются на отсутствие данных.
from pymongo import MongoClient import pandas as pd import numpy as np import matplotlib.pyplot as plt import re from sklearn.model_selection import train_test_split, GridSearchCV,ShuffleSplit, cross_val_score from sklearn import model_selection from sklearn.neighbors import KNeighborsRegressor import statsmodels.api as sm from sklearn.linear_model import LinearRegression, Ridge, Lasso, LassoCV, ElasticNet from sklearn.metrics import mean_squared_error, mean_absolute_error import numpy as np from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.ensemble import RandomForestRegressor, GradientBoostingRegressor import xgboost as xgb from xgboost import XGBRegressor import config import pickle from collections import defaultdict from operator import itemgetter import random import lightgbm as lgb from lightgbm import LGBMRegressor
Поскольку количество недостающих данных очень мало, мы можем их удалить. Некоторые данные, представляющие собой строку типа данных, преобразуются в целые числа, например год («1999», «2018»). Кроме того, данные подготавливаются путем удаления точечных выражений в значениях цены и пробега.
"""Preprocessing of Price""" df["Fiyat"] = df["Fiyat"].str.replace(".","") df["Fiyat"] = [re.findall(r"(\d+)", str(x)) for x in df["Fiyat"]] df["Fiyat"] = df["Fiyat"].str[0] df["Fiyat"] = df["Fiyat"].astype(int) """Preprocessing of Km and year""" df["Km"] = df["Km"].str.replace(".","") df["Km"] = df["Km"].astype(int) df["Yıl"] = df["Yıl"].astype(int)
Исключительные обнаружения идентифицируются после подготовки вышеуказанных данных. Обнаружение выбросов в этом проекте в основном происходит из-за того, что поставщики вводят неверную информацию.
Выше показана неверная информация о пробеге (км). Эти значения пробега неверны, особенно по сравнению с информацией о году (Yıl) и цене (Fiyat). Эти данные можно удалить, поскольку количество обнаруженных выбросов невелико. Однако в случаях, когда количество имеющихся у нас данных невелико, мы можем не захотеть их удалять. В таких случаях среднее значение или медианное значение может быть присвоено столбцам выбросов (в данном случае столбцу пробега). В качестве примера мы рассматривали только Audi, но эти процедуры применялись для каждой марки автомобиля.
Кратко рассмотрим модели машинного обучения, использованные в проекте:
- Линейная регрессия:
Линейная регрессия используется для определения степени, в которой существует линейная связь между зависимой переменной и одной или несколькими независимыми переменными. Существует два типа линейной регрессии: простая линейная регрессия и множественная линейная регрессия. Поскольку в этом проекте используется более одной независимой переменной, «была использована модель множественной линейной регрессии.
def linear_regression(self): self.lr_model = LinearRegression() self.lr_model.fit(self.X_train, self.y_train) y_pred = self.lr_model.predict(self.X_test) lr_rmse = np.sqrt(mean_squared_error(self.y_test,y_pred)) self.lr_rmse_per =np.sqrt(np.mean(np.square(((self.y_test - y_pred) / self.y_test))))*100 self.lr_mae = mean_absolute_error(self.y_test, y_pred) self.lr_mape = np.abs((self.y_test - y_pred) / self.y_test).mean(axis=0) * 100 return lr_rmse
- K-ближайшие соседи:
Хотя алгоритм K-ближайших соседей (KNN) обычно используется в задачах классификации, он также дает очень хорошие результаты в задачах регрессии. Принцип работы алгоритма KNN - кластеризация объектов в соответствии с их отношениями близости. Пример классифицируется большинством голосов его соседей; эта выборка отнесена к самому близкому классу среди ее ближайших соседей, что измеряется функцией расстояния.
Следует также отметить, что все три расстояния применимы только к непрерывным переменным. В случае категориальных переменных следует использовать расстояние Хэмминга. Также следует обратить внимание на стандартизацию числовых переменных, когда в наборе данных есть смесь числовых и категориальных переменных.
Хотя алгоритм KNN создает эффективную модель машинного обучения, особенно в отношении шума, содержащего данные, к большим данным необходимо подходить осторожно.
Код проекта:
def knn(self): knn_model = KNeighborsRegressor().fit(self.X_train, self.y_train) y_pred = knn_model.predict(self.X_test) self.knn_rmse = np.sqrt(mean_squared_error(self.y_test,y_pred)) #Model tuning #============================================================================= knn_params = {"n_neighbors": [2,5,10,20,30,40], "leaf_size": [15,30,60]} n_neighbors_list = knn_params["n_neighbors"] leaf_size_list = knn_params["leaf_size"] self.knn_result_list = [] for i in range(len(n_neighbors_list)): for j in range(len(leaf_size_list)): temp_list = [] knn_model = KNeighborsRegressor(n_neighbors = n_neighbors_list[i], leaf_size = leaf_size_list[j]) knn_model.fit(self.X_train, self.y_train) y_pred = knn_model.predict(self.X_test) knn_rmse = np.sqrt(mean_squared_error(self.y_test, y_pred)) temp_list.extend((knn_rmse, n_neighbors_list[i], leaf_size_list[j])) self.knn_result_list.append(temp_list) self.knn_result_list.sort() self.knn_tuned = KNeighborsRegressor(n_neighbors = self.knn_result_list[0][1], leaf_size = self.knn_result_list[0][2]) self.knn_tuned.fit(self.X_train, self.y_train) y_pred = self.knn_tuned.predict(self.X_test) knn_tuned_rmse = np.sqrt(mean_squared_error(self.y_test,y_pred)) self.knn_tuned_rmse_per =np.sqrt(np.mean(np.square(((self.y_test - y_pred) / self.y_test))))*100 self.knn_mae = mean_absolute_error(self.y_test, y_pred) self.knn_mape = np.abs((self.y_test - y_pred) / self.y_test).mean(axis=0) * 100 return knn_tuned_rmse
- Случайный лес:
Модель случайного леса, которая используется для задач регрессии и классификации и основана на модели дерева решений.
Одна из самых больших проблем деревьев решений, которые являются одним из традиционных методов, - это переоснащение в образовании. Модель случайного леса была разработана для решения этой проблемы. Эта модель делает случайный выбор как из набора данных, так и из набора атрибутов. Как видно выше, каждое дерево решений делает индивидуальные прогнозы, используя свое собственное подмножество. На последнем этапе мы достигаем окончательного значения прогноза нашей модели случайного леса, беря среднее значение полученных прогнозов.
В нашем проекте гиперпараметры «max_depth», «n_estimators» и «max_features» использовались для применения операций настройки к нашей модели случайного леса.
def random_forest(self): rf_model = RandomForestRegressor(random_state = 10).fit(self.X_train, self.y_train) y_pred = rf_model.predict(self.X_test) self.rf_rmse = np.sqrt(mean_squared_error(self.y_test, y_pred)) #Random Forest Tuning Model rf_params = {"max_depth": [None, 2,5,9], "n_estimators": [10,100,500,1000], "max_features": ["auto",3,5]} self.rf_result_list = [] max_depth_list = rf_params["max_depth"] n_estimators_list = rf_params["n_estimators"] max_features_list = rf_params["max_features"] for i in range(len(max_depth_list)): for j in range(len(n_estimators_list)): for k in range(len(max_features_list)): temp_list = [] rf_model = RandomForestRegressor(random_state = 10, max_depth = max_depth_list[i], n_estimators = n_estimators_list[j], max_features = max_features_list[k]) rf_model.fit(self.X_train, self.y_train) y_pred = rf_model.predict(self.X_test) knn_rmse = np.sqrt(mean_squared_error(self.y_test, y_pred)) temp_list.extend((knn_rmse, max_depth_list[i], n_estimators_list[j], max_features_list[k])) self.rf_result_list.append(temp_list) self.rf_result_list.sort() self.rf_tuned = RandomForestRegressor(random_state = 10, max_depth = self.rf_result_list[0][1], n_estimators = self.rf_result_list[0][2], max_features = self.rf_result_list[0][3]) self.rf_tuned.fit(self.X_train, self.y_train) y_pred = self.rf_tuned.predict(self.X_test) rf_tuned_rmse = np.sqrt(mean_squared_error(self.y_test,y_pred)) self.rf_tuned_rmse_per =np.sqrt(np.mean(np.square(((self.y_test - y_pred) / self.y_test))))*100 self.rf_mae = mean_absolute_error(self.y_test, y_pred) self.rf_mape = np.abs((self.y_test - y_pred) / self.y_test).mean(axis=0) * 100 return rf_tuned_rmse
- Машина для повышения градиента:
Повышение - это итеративный метод, в котором предикторы создаются не независимо, а последовательно. Следовательно, вероятность наблюдений в последующих моделях неодинакова, и наиболее вероятны те, которые имеют наибольшую ошибку. Предикторы могут быть выбраны из ряда моделей, таких как деревья решений, регрессоры, классификаторы и т. Д. Поскольку новые предикторы учатся на ошибках, совершенных предыдущими предикторами, требуется меньше времени / итераций, чтобы приблизиться к фактическим прогнозам. Но мы должны тщательно выбирать критерии остановки, иначе это может привести к переобучению обучающих данных. Итак, пример алгоритма повышения градиента.
Скажем, у нас есть среднеквадратичная ошибка (MSE) как потеря, определяемая как:
Используя градиентный спуск и обновляя наши прогнозы на основе скорости обучения, мы можем найти значения, при которых MSE минимальна.
def gbm(self): gbm_model = GradientBoostingRegressor().fit(self.X_train, self.y_train) y_pred = gbm_model.predict(self.X_test) self.gbm_rmse = np.sqrt(mean_squared_error(self.y_test,y_pred)) gbm_params = {"learning_rate" : [0.001, 0.01, 0.1], "max_depth": [3,5,8,50,100], "n_estimators" : [10,100,500,1000], "subsample" : [1,0.5,0.75]} learning_rate_list = gbm_params["learning_rate"] max_depth_list = gbm_params["max_depth"] n_estimators_list = gbm_params["n_estimators"] subsample_list = gbm_params["subsample"] self.gbm_result_list = [] for i in range(len(learning_rate_list)): for j in range(len(max_depth_list)): for k in range(len(n_estimators_list)): for l in range(len(subsample_list)): temp_list = [] gbm_model = GradientBoostingRegressor(learning_rate = learning_rate_list[i], max_depth = max_depth_list[j], n_estimators = n_estimators_list[k], subsample = subsample_list[l]) gbm_model.fit(self.X_train, self.y_train) y_pred = gbm_model.predict(self.X_test) gbm_rmse = np.sqrt(mean_squared_error(self.y_test, y_pred)) temp_list.extend((gbm_rmse, learning_rate_list[i], max_depth_list[j], n_estimators_list[k], subsample_list[l])) self.gbm_result_list.append(temp_list) self.gbm_result_list.sort() self.gbm_tuned = GradientBoostingRegressor(learning_rate = self.gbm_result_list[0][1], max_depth = self.gbm_result_list[0][2], n_estimators = self.gbm_result_list[0][3], subsample = self.gbm_result_list[0][4]) self.gbm_tuned.fit(self.X_train, self.y_train) y_pred = self.gbm_tuned.predict(self.X_test) gbm_tuned_rmse = np.sqrt(mean_squared_error(self.y_test, y_pred)) self.gbm_tuned_rmse_per =np.sqrt(np.mean(np.square(((self.y_test - y_pred) / self.y_test))))*100 self.gbm_mae = mean_absolute_error(self.y_test, y_pred) self.gbm_mape = np.abs((self.y_test - y_pred) / self.y_test).mean(axis=0) * 100 return gbm_tuned_rmse
- Экстремальное усиление градиента (XGBOOST):
Хотя XGBoost похож на Gradient Boosting Machine, он более эффективен. XGBoost обеспечивает распараллеливание при создании деревьев решений, что позволяет создавать их намного быстрее. Тот факт, что он может это сделать, - это базовые ученики, в то время как он может переключаться между внутренним и внешним петлителями. Обычно внешний цикл вычисляет атрибуты внутреннего цикла при формировании листьев дерева решений. XGBoost отдает приоритет глубине с max_depth, его сложность значительно увеличивает производительность вычислений. Внеядерные вычисления в XGBoost оптимизируют доступное дисковое пространство и максимизируют его использование при обработке огромных наборов данных, которые не помещаются в память. XGBoost может предотвратить переоснащение, используя регуляризацию как Лассо, так и Ридж. Для более быстрых вычислений XGBoost может использовать несколько ядер ЦП. Это возможно благодаря блочной структуре его системы. Данные сортируются и хранятся в единицах памяти, называемых блоками. В отличие от других алгоритмов, это позволяет повторно использовать макет данных в последующих итерациях вместо повторного вычисления. Одним из самых больших преимуществ XGBoost является то, что он использует точки наблюдения в наборе данных путем взвешивания, чтобы отличить его от правильной точки при разделении на деревья.
В нашем проекте гиперпараметры «max_depth», «n_estimators», «colsample_bytree» и «скорость обучения» использовались для применения операций настройки к нашей модели случайного леса.
def xgboost(self): X_train_v = self.X_train.values X_test_v = self.X_test.values xgb_model = XGBRegressor().fit(X_train_v, self.y_train) y_pred = xgb_model.predict(X_test_v) self.xgboost_rmse = np.sqrt(mean_squared_error(self.y_test, y_pred)) #Model Tuning xgb_params ={"colsample_bytree": [0.6,0.9,1], "n_estimators" : [100,200,500,1000], "max_depth" : [4,5,6], "learning_rate": [0.1,0.3,0.5]} self.xgb_result_list = [] colsample_bytree_list = xgb_params["colsample_bytree"] n_estimators_list = xgb_params["n_estimators"] max_depth_list = xgb_params["max_depth"] learning_rate_list = xgb_params["learning_rate"] for i in range(len(colsample_bytree_list)): for j in range(len(n_estimators_list)): for k in range(len(max_depth_list)): for l in range(len(learning_rate_list)): temp_list = [] xgb_model = XGBRegressor(colsample_bytree = colsample_bytree_list[i], n_estimators = n_estimators_list[j], max_depth = max_depth_list[k], learning_rate = learning_rate_list[l]) xgb_model.fit(X_train_v, self.y_train) y_pred = xgb_model.predict(X_test_v) xgb_rmse = np.sqrt(mean_squared_error(self.y_test, y_pred)) temp_list.extend((xgb_rmse, colsample_bytree_list[i], n_estimators_list[j], max_depth_list[k], learning_rate_list[l])) self.xgb_result_list.append(temp_list) self.xgb_result_list.sort() self.xgb_tuned = XGBRegressor(colsample_by_tree = self.xgb_result_list[0][1], n_estimators =self.xgb_result_list[0][2], max_depth = self.xgb_result_list[0][3], learning_rate = self.xgb_result_list[0][4]) self.xgb_tuned.fit(X_train_v, self.y_train) y_pred = self.xgb_tuned.predict(X_test_v) xgb_tuned_rmse = np.sqrt(mean_squared_error(self.y_test,y_pred)) self.xgb_tuned_rmse_per =np.sqrt(np.mean(np.square(((self.y_test - y_pred) / self.y_test))))*100 self.xgb_mae = mean_absolute_error(self.y_test, y_pred) self.xgb_mape = np.abs((self.y_test - y_pred) / self.y_test).mean(axis=0) * 100 return xgb_tuned_rmse
Среднеквадратичная ошибка представляет собой разницу для каждого наблюдаемого и прогнозируемого значения. Вы можете поменять местами порядок вычитания, потому что следующим шагом будет вычисление квадрата разницы. Это потому, что квадрат отрицательного значения всегда будет положительным значением. Но просто убедитесь, что вы соблюдаете тот же порядок во всем.
После этого разделите сумму всех значений на количество наблюдений. Наконец, мы получаем значение RMSE.
Другим методом сравнения полученных оценок может быть средняя абсолютная ошибка (MAE). Это особенно предпочтительно, когда в данных есть экстремальные наблюдения. Однако, если мы хотим сильнее отразить влияние наблюдений за выбросами на систему, было бы правильнее выбрать значение RMSE. Оба значения были найдены и сопоставлены в проекте.
Заключение
Для сравнения моделей используется значение rmse. В качестве валюты использовалась турецкая лира. Все сравниваемые модели для каждой марки автомобилей проходят обучение, и определяется лучшая модель. Таким образом определялась лучшая модель для каждой марки автомобиля.
Значения среднеквадратичного отклонения всех моделей можно увидеть в приведенных выше таблицах. Кроме того, в столбце таблиц с названием «выбранная модель mae» лучшая выбранная модель имеет значение mae.
В результате сравнения моделей (количество лучших моделей):
- Машина для повышения градиента (GBM): 19
- Экстремальное усиление градиента (XGBoost): 11
- Случайный лес: 7
- Конек: 5
- Лассо: 2
- Эластичная сетка: 1
Глядя на сортировку, мы видим, что модель GBM выбирается больше всего. Особенно у моделей XGBoost и GBM есть преимущества перед другими моделями.
Однако с такими результатами нельзя делать вывод о том, что модель GBM является лучшей. Не следует забывать, что каждая модель может быть эффективной для разных типов и размеров данных.
Наконец, как среднеквадратичные значения параметров по умолчанию, так и среднеквадратичные значения настроенных параметров моделей GBM можно увидеть в таблице выше. Если в именах столбцов есть «def» (gbm def max_depth), это параметр по умолчанию, в противном случае («cho») - настроенный параметр. Итак, мы увидели, как модель может развиваться в результате оптимизации гиперпараметров.
Github: https://github.com/ademakdogan
Linkedin: https://www.linkedin.com/in/adem-akdo%C4%9Fan-948334177/
Ссылка
- Достижения в области науки о данных, кибербезопасности и ИТ-приложений
- Https://www.statisticallysignificantconsulting.com/RegressionAnalysis.htm
- Https://www.analyticsvidhya.com/blog/2018/09/an-end-to-end-guide-to-understand-the-math-behind-xgboost/