Особая благодарность моим товарищам по команде Дони Коху, Дэниелу Симмондсу и Эзре Леру за их ценный вклад в завоевание 1-го места в конкурсе Analytics Edge Competition на Kaggle, крупнейшем в мире сообществе специалистов по данным и дочерней компании Google. Это наш самый первый конкурс Kaggle и скромное начало нашего пути к машинному обучению.
Нажмите на эту ссылку, чтобы просмотреть более подробный отчет:
The-Analytics-Edge-2023 Kaggle Report Subscription Team 13.pdf
Что такое предиктивная аналитика?
Предиктивная аналитика — это отрасль расширенной аналитики, которая использует исторические данные, статистические алгоритмы и методы машинного обучения для прогнозирования будущих результатов. Автомобильные компании используют прогностическую аналитику для адаптации своих предложений и маркетинговых стратегий с целью лучшего удовлетворения потребительских предпочтений. В этой статье мы познакомим вас с нашим рабочим процессом прогнозирования выбора комплекта безопасности автомобиля потребителями.
Предварительная обработка данных
Мы использовали 2 набора необработанных данных, предоставленных в этом соревновании — набор для обучения и набор для тестирования, каждый из которых содержит 113 столбцов:
При проверке данных было сделано несколько замечаний:
- Отсутствующие значения
- Некоторые переменные содержали интервальные записи, например. мили, ночь и доход
- Некоторые переменные являются категориальными (номинальными)
- Переменные, которые принимали дискретные числовые значения, имеют разные диапазоны значений.
Поэтому мы использовали методы разработки признаков в машинном обучении, включая вменение данных, горячее кодирование и масштабирование признаков. Эти методы имеют решающее значение для повышения прогностических способностей наших моделей машинного обучения в дальнейшем.
Теперь у нас есть 129 столбцов:
Разделение обучающих данных для обучения и тестирования
(для всех моделей, кроме XGBoost и Random Forest)
Поскольку данные тестирования не содержат записей для переменной «выбор», мы разделили обучающие данные на обучающий набор и проверочный набор в соотношении примерно 4:1. Учебный набор обучает наши модели, тогда как проверочный набор проверяет наши модели на предмет их производительности (оцениваемой с использованием Log Loss и Accuracy в нашем случае) после обучения.
# Read data from CSV file cars <- read.csv("Traintest_Processed.csv") # Distinguish original training and testing sets test <- subset(cars, choice==0) cars_19 <- subset(cars, choice!=0) # Split original training set into training set and validation set cars_train <- subset(cars_19, Task<=15) cars_test <- subset(cars_19, Task>15)
Метрики оценки
Функция потери журнала
Функция логарифмических (логарифмических) потерь используется в качестве метрики оценки для измерения производительности моделей с прогнозируемыми вероятностями в диапазоне от 0 до 1. Меньшее значение логарифмических потерь указывает на лучшую производительность модели, поскольку отражает, что прогнозируемые вероятности модели ближе к фактические метки классов.
R-код:
logloss_cal <- function(actual_labels, predicted_probs) { n <- length(actual_labels) # number of instances m <- ncol(predicted_probs) # number of classes logloss <- 0 # Initialize log loss variable # Loop over each instance for (i in 1:n) { # Loop over each class for (j in 1:m) { # Indicator function y_ij for actual class membership (1 if actual class matches j, 0 otherwise) y_ij <- ifelse(actual_labels[i] == j, 1, 0) # Predicted probability for class j for the i-th instance p_ij <- predicted_probs[i, j] # Calculate the log loss contribution for this class and instance logloss_ij <- y_ij * log(p_ij) # Accumulate the log loss logloss <- logloss + logloss_ij } } # Calculate the average log loss over all instances logloss <- -logloss / n # Return the final log loss value return(logloss) }
Вызовите функцию потери журнала
loglossval_m3 <- logloss_cal(cars_test$choice, pred_nnet_m3) loglossval_m3
Точность
Код R для создания матрицы путаницы и расчета точности модели:
actual_car_train_test <- subset(cars_test, Task>15)[,"choice"] Tabtrainmixed_pred_nn_m3 <- table(predicted_choice_nn_m3, actual_car_train_test) Tabtrainmixed_pred_nn_m3 sum(diag(Tabtrainmixed_pred_nn_m3)) / sum(Tabtrainmixed_pred_nn_m3)
Модели
В следующем разделе мы обсудим использование моделей полиномиальной логистической регрессии, случайного леса, XGBoost, наивного байесовского классификатора и регрессии Лассо, а также использование ансамблевых методов в комбинации этих моделей.
1. Модель мультиномиальной логистической регрессии (MLR)
Модель MLR, также известная как полиномиальная логит-модель, используется для моделирования взаимосвязи между переменными-предикторами (независимыми переменными) и вероятностями каждой категории в зависимой переменной. Он оценивает логарифмические шансы (логит) каждой категории относительно эталонной категории, которые затем преобразуются в вероятности для каждой категории.
Предположим, у нас есть K категорий для зависимой переменной. Для каждого наблюдения i у нас есть набор переменных-предикторов, обозначенных как X_i. Модель может быть представлена в виде:
logit(p_i_k) = β_{0k} + β_1 * X_i1 + β_2 * X_i2 + … + β_p * X_ip
где:
- p_i_k — вероятность того, что наблюдение i относится к категории k,
- β_{0k} – термин для категории k,
- β_1, β_2, …, β_p — коэффициенты для переменных-предикторов X_1, X_2, …, X_p соответственно.
В полиномиальной логистической регрессии модель оценивает K-1 наборов коэффициентов, по одному набору для каждой категории по сравнению с эталонной категорией. Эталонная категория обычно представляет базовую категорию или категорию по умолчанию, а другие коэффициенты показывают, насколько каждая категория отличается от эталонной категории.
R-код:
# Load package library(nnet) # Train model with validation set nnet_m <- multinom(choice ~ GN1+FA1+LD1+BZ1+FC1+FP1+RP1+PP1+KA1+SC1+TS1+NV1+MA1+AF1+HU1+Price1 +GN2+FA2+BZ2+FC2+FP2+RP2+PP2+KA2+SC2+TS2+NV2+LB2+AF2+HU2+Price2 +GN3+FA3+LD3+BZ3+FC3+RP3+PP3+KA3+SC3+TS3+NV3+AF3+HU3+Price3 +segmentind.1 +segmentind.2 +segmentind.3 +segmentind.4 +segmentind.5 +segmentind.6 +year.2000 +year.2001 +year.2002 +year.2003 +year.2004 +year.2005 +year.2006 +nightind.1 +nightind.2 +nightind.3 +nightind.4 +nightind.5 +nightind.6 +nightind.7 +nightind.8 +nightind.9 +nightind.10 +pparkind.1 +pparkind.2 +pparkind.3 +pparkind.4 +pparkind.5 +genderind.1 +genderind.2 +ageind +educind.1 +educind.2 +educind.3 +educind.4 +educind.5 +educind.6 +regionind.1 +regionind.2 +regionind.3 +regionind.4 +regionind.5 +Urbind.1 +Urbind.2 +Urbind.3 +incomea, data = cars_train) # Display a summary of the model's output, including coefficients, standard errors, z-values, and p-values. summary(nnet_m)
Сгенерируйте прогнозы проверочного набора для оценки с использованием обученной модели:
probabilities <- predict(<model>, newdata= cars_test, type = "probs") head(probabilities) # Assign integers 1-4 for "choice" variable, based on choice no. with highest predicted probabilities predicted_choice <- apply(probabilities, 1, which.max) head(predicted_choice)
2. Модель случайного леса
Случайный лес — это мощный метод ансамблевого обучения, который объединяет несколько деревьев решений для создания надежной и точной прогностической модели. Оценка Out-of-Bag (OOB) — это уникальная функция Random Forest, которая обычно недоступна в других отдельных моделях машинного обучения.
В отличие от других моделей, случайный лес использует начальную загрузку, при которой каждое дерево решений строится с использованием случайного подмножества обучающих данных, а оставшиеся данные (данные из пакета) используются для проверки. Это означает, что модель оценивается на невидимых данных без необходимости внешнего набора проверки или перекрестной проверки. Используя OOB-оценки производительности модели, Random Forest может оценить ее способность к обобщению и избежать переобучения, что приводит к более точным и надежным прогнозам.
R-код:
Создайте базовую модель со всеми обучающими данными
set.seed(1) # Load package library(ranger) # Use all training data to train model rangerpp<-ranger(as.factor(choice)~., data=cars_19,num.trees=500,mtry=15, importance='impurity', probability = TRUE)
Получите матрицу оценок OOB
# Values of ntree to be tested B <- seq(5,500,by=5) # Initialize a vector for the OOB value OOB <- vector(); OOB <- c(OOB, 1:length(B)) # For loop for (i in 1:length(B)){ # train a forest with B[i] trees set.seed(i) forest_temp <- ranger(as.factor(choice)~.,data=cars_train,num.trees=B[i]) # model performance OOB[i] <- forest_temp$prediction.error # remove the temporary variable rm(forest_temp) } plot(B,OOB) # Repeat the experiment, but changing `mtry` and fixing `ntree` at the same time. # Values of ntree to be tested B <- seq(500,500,by=5) # Values of mtry to be tested m <- seq(10,35,by=1) # Initialize a matrix for the OOB value OOB_matrix <- matrix(0,nrow=length(B),ncol=length(m)) k <- 0 # For loop for (i in 1:length(B)){ for (j in 1:length(m)){ # train a forest with B[i] trees k <- k+1 set.seed(k+1) forest_temp <- ranger(as.factor(choice)~.,data=cars_train,num.trees=B[i],mtry=m[j]) # model performance OOB_matrix[i,j] <- forest_temp$prediction.error # remove the temporary variable rm(forest_temp) } } summary(OOB_matrix)
Модель обучения с наилучшей оценкой OOB
# Extract best OOB estimate which(min(OOB_matrix) == OOB_matrix,arr.ind=TRUE) # Select mtry=15 as it is closer to sqrt(total predictor variables of 129) and 0.5178 not far off from 0.5175 set.seed(1) best_forest <- ranger(as.factor(choice)~.,data=cars_train,num.trees=500,mtry=15) set.seed(1) rangerpp2 <- ranger(as.factor(choice)~., data=cars_train,num.trees=500,mtry=15,probability = TRUE)
Примечание.
Хотя оценка OOB полезна для внутренней проверки в Random Forest, она имеет ограничения и может не гарантировать производительность модели на невидимых данных. Для обеспечения надежной оценки модели необходима внешняя проверка с помощью отдельного набора тестов или перекрестная проверка на полностью невидимых данных.
Сгенерируйте прогнозы проверочного набора для оценки с использованием обученной модели:
# best_forest probabilities <- predict(best_forest,data=cars_test) head(probabilities) # Assign integers 1-4 for "choice" variable, based on choice no. with highest predicted probabilities predicted_choice <- apply(probabilities, 1, which.max) head(predicted_choice)
3. Модель XGBoost
XGBoost — это оптимизированная реализация платформы повышения градиента, объединяющая деревья решений и повышение градиента для исключительной точности прогнозирования и вычислительной эффективности. Его универсальность делает его подходящим для систем классификации, регрессии, ранжирования и рекомендаций. Успех XGBoost объясняется методами регуляризации, обработкой отсутствующих данных, оценкой важности функций и поддержкой параллельных и распределенных вычислений.
R-код:
Подготовить наборы данных
# Import libraries library(xgboost) library(caret) ### Loading Data sets / Date Processing ### cars2 <- read.csv("Traintest_Processed.csv") test <- subset(cars2, choice==0) cars2 <- subset(cars2, choice!=0) cars_train <- subset(cars2, Task<=13) # For the xgboost model since it takes label values starting from 0, not 1 y_numeric <- as.numeric(cars_train$choice) -1 cars_train_mtx <- as.matrix(subset(cars_train, select = -c(choice,Task))) # Validation set cars_vld <- subset(cars2, Task>13 & Task<=15) y_numeric_vld <- as.numeric(cars_vld$choice) -1 cars_vld_mtx <- as.matrix(subset(cars_vld, select = -c(choice,Task))) cars_test <- subset(cars2, Task>15) y_numeric_test <- as.numeric(cars_test$choice) -1 cars_test_mtx <- as.matrix(subset(cars_test, select = -c(choice,Task))) test_mtx <- as.matrix(subset(test, select = -c(choice,Task))) # Using Dmatrix format as recommended by the authors dtrain <- xgb.DMatrix(data = cars_train_mtx, label = y_numeric) dtest <- xgb.DMatrix(data = cars_test_mtx, label=y_numeric_test)
Постройте модель, используя настройку сетки
# Load library library(caret) # Grid tuning the hyperparameters saved model results mymodel <- readRDS("model.rds") mymodel mymodel$bestTune
Сгенерируйте прогнозы проверочного набора для оценки с использованием обученной модели:
probabilities <- predict(mymodel, newdata= test_mtx, type = "probs") head(probabilities) # Assign integers 1-4 for "choice" variable, based on choice no. with highest predicted probabilities predicted_choice <- apply(probabilities, 1, which.max) head(predicted_choice)
4. Наивная модель байесовского классификатора
Эта модель основана на теореме Байеса. «Наивный» возник из предположения, что среди признаков существует условная независимость. На этапе обучения модель изучает распределения вероятностей каждой функции с учетом меток классов. Затем он вычисляет априорную вероятность каждого класса, а также условную вероятность каждой функции с учетом метки класса. Затем, на этапе прогнозирования, модель вычисляет вероятность каждой метки класса с учетом особенностей экземпляра с использованием теоремы Байеса:
P(C | x_1, x_2, …, x_n) = P(C) * P(x_1 | C) * P(x_2 | C) * … * P(x_n | C)
Затем модель выбирает класс с наибольшей вероятностью в качестве прогнозируемого класса для экземпляра.
Примечание.
Нам нужно будет указать тип прогноза как «необработанный», что означает, что мы хотим получить необработанные вероятности каждого экземпляра, принадлежащего каждому классу.
Эта модель эффективна в вычислительном отношении, требует относительно небольшого количества обучающих данных и может обрабатывать большие наборы данных с многомерными пространствами признаков. Несмотря на наивное предположение, наивные байесовские классификаторы могут работать хорошо, особенно когда признаки не сильно коррелированы или когда набор данных не очень велик.
R-код:
# Load packages library(e1071) library(caTools) library(ggplot2) library(caret) # Train model with validation set bay_m4 <- naiveBayes(choice ~ Price1+ Price2+ Price3+ segmentind+ year+ milesa+ nightind+ ppark+ ageind+ educind+ regionind+ Urbind, data = cars_train)
Сгенерируйте прогнозы проверочного набора для оценки с использованием обученной (наилучшей) модели:
pred_bay_m4_probs <- predict(bay_m4, newdata = cars_test, type = "raw") head(pred_bay_m4_probs) # Assign integers 1-4 for "choice" variable, based on choice no. with highest predicted probabilities predicted_choice_bay_m4 <- apply(pred_bay_m4_probs, 1, which.max) head(predicted_choice_bay_m4)
5. Модель регрессии Лассо
Лассо расшифровывается как «оператор наименьшей абсолютной усадки и выбора». Лассо-регрессия по существу представляет собой линейную регрессию с добавлением штрафного члена к исходной функции стоимости линейной регрессии для получения:
Стоимость = сумма квадратов ошибок + λ * сумма абсолютных значений коэффициентов
Член регуляризации уменьшает некоторые коэффициенты до 0, тем самым выполняя выбор признаков, чтобы получить более интерпретируемую и компактную модель. Выбор значения лямбда (λ) здесь имеет решающее значение, так как большое значение приводит к более сильному выбору признаков (большее количество коэффициентов будет сведено к 0). По этой причине регрессионная модель Лассо может быть особенно полезна при работе с многомерными наборами данных (содержащими множество функций), поскольку такие наборы данных создают риск переобучения моделей машинного обучения.
R-код:
Найти лямбда (λ)
# Define response variable y <- cars_train$choice # Define matrix of predictor variables x <- data.matrix(cars_train[, !(colnames(cars_train) %in% 'choice')]) # Perform k-fold cross-validation to find optimal lambda value cv_model <- cv.glmnet(x, y, family = "multinomial", alpha = 1) # Find optimal lambda value that minimizes test MSE best_lambda <- cv_model$lambda.min best_lambda
Создайте модель, используя best_lambda
# Load package library(glmnet) # Find coefficients of best model best_model <- glmnet(x, y, alpha = 1, family = "multinomial", lambda = best_lambda) coef(best_model)
Сгенерируйте прогнозы проверочного набора для оценки с использованием обученной (наилучшей) модели:
# Use fitted best model to make predictions y_predicted <- predict(best_model, s = best_lambda, newx = x) # Assign integers 1-4 for "choice" variable, based on choice no. with highest predicted probabilities predicted_choice_glmnet_m1 <- apply(pred_glm_m1, 1, which.max) head(predicted_choice_glmnet_m1)
Дополнительные модели ансамбля: сила в синергии
Здесь мы исследовали потенциал объединения нескольких простых и продвинутых алгоритмов машинного обучения, описанных выше, для создания надежных ансамблевых моделей. Благодаря использованию разнообразия этих моделей их отдельные недостатки смягчаются, что приводит к улучшению обобщения и уменьшению переобучения.
Результаты оценки метрик для отдельных моделей:
Результаты оценки метрики некоторых комбинаций моделей:
Спасибо за чтение!