Особая благодарность моим товарищам по команде Дони Коху, Дэниелу Симмондсу и Эзре Леру за их ценный вклад в завоевание 1-го места в конкурсе Analytics Edge Competition на Kaggle, крупнейшем в мире сообществе специалистов по данным и дочерней компании Google. Это наш самый первый конкурс Kaggle и скромное начало нашего пути к машинному обучению.

Нажмите на эту ссылку, чтобы просмотреть более подробный отчет:
The-Analytics-Edge-2023 Kaggle Report Subscription Team 13.pdf

Что такое предиктивная аналитика?

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

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

Мы использовали 2 набора необработанных данных, предоставленных в этом соревновании — набор для обучения и набор для тестирования, каждый из которых содержит 113 столбцов:

При проверке данных было сделано несколько замечаний:

  1. Отсутствующие значения
  2. Некоторые переменные содержали интервальные записи, например. мили, ночь и доход
  3. Некоторые переменные являются категориальными (номинальными)
  4. Переменные, которые принимали дискретные числовые значения, имеют разные диапазоны значений.

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

Теперь у нас есть 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)

Дополнительные модели ансамбля: сила в синергии

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

Результаты оценки метрик для отдельных моделей:

Результаты оценки метрики некоторых комбинаций моделей:

Спасибо за чтение!