Levi Gurgel de Lima, Yves Gabriel Q. de Sousa, Marco Aurélio C. Risardi
A Aerometrics desenvolveu um sistema preditivo para estimar o consumo de combustível a partir de dados históricos de operações aéreas.
Nesta apresentação serão mostrados:
library(tidyverse)
library(lubridate)
library(e1071)
library(neuralnet)
library(caret)
library(tree)
set.seed(123)
load("data_project_train.Rda")
load("data_project_test.Rda")## # A tibble: 6 × 13
## flight_id orig dest dep_time arr_time airline
## <dbl> <fct> <fct> <dttm> <dttm> <fct>
## 1 816911099 SBSP SBNF 2023-06-12 22:25:43 2023-06-12 23:08:13 TAM
## 2 848573075 SBPA SBSP 2023-10-25 15:01:19 2023-10-25 16:22:48 TAM
## 3 822515328 SBVT SBGR 2023-07-06 23:02:27 2023-07-07 00:31:17 TAM
## 4 853338898 SBRJ SBPA 2023-11-17 00:49:03 2023-11-17 02:29:31 TAM
## 5 848627219 SBSP SBLO 2023-10-25 19:51:39 2023-10-25 20:39:28 TAM
## 6 797381975 SBSP SBBR 2023-03-15 09:11:29 2023-03-15 10:27:30 TAM
## # ℹ 7 more variables: aircraft_type <fct>, flown_distance_enr <dbl>,
## # flight_duration <dbl>, kpi_inefficiency_dep <dbl>,
## # kpi_inefficiency_enr <dbl>, kpi_inefficiency_arr <dbl>, fuel_burn <dbl>
Nesta etapa realizamos a criação de novas variáveis derivadas das
informações brutas do dataset.
A engenharia de atributos é fundamental para melhorar a representação
dos dados e aumentar o poder preditivo dos modelos.
As principais transformações incluem:
Esses atributos aprimoram a capacidade dos modelos em capturar padrões relevantes associados ao consumo de combustível.
df_train <- data_train %>%
mutate(
avg_speed = flown_distance_enr / (flight_duration / 60), # NM/h
fuel_per_nm = fuel_burn / flown_distance_enr,
fuel_per_min = fuel_burn / flight_duration,
total_ineff = kpi_inefficiency_dep + kpi_inefficiency_arr,
flight_range = case_when(
flown_distance_enr < 400 ~ "Curto",
flown_distance_enr < 800 ~ "Médio",
TRUE ~ "Longo"
),
flight_range = factor(flight_range, levels = c('Curto', 'Médio', 'Longo')),
dep_hour = hour(dep_time),
dep_period = case_when(
dep_hour >= 5 & dep_hour < 12 ~ "Manhã",
dep_hour >= 12 & dep_hour < 18 ~ "Tarde",
TRUE ~ "Noite"
),
dep_period = factor(dep_period, levels = c("Manhã", "Tarde", "Noite"))
)# Aplicar o mesmo processo à base de teste (sem fuel_burn)
df_test <- data_test %>%
mutate(
avg_speed = flown_distance_enr / (flight_duration / 60),
total_ineff = kpi_inefficiency_dep + kpi_inefficiency_arr,
flight_range = case_when(
flown_distance_enr < 400 ~ "Curto",
flown_distance_enr < 800 ~ "Médio",
TRUE ~ "Longo"
),
flight_range = factor(flight_range, levels = c('Curto', 'Médio', 'Longo')),
dep_hour = hour(dep_time),
dep_period = case_when(
dep_hour >= 5 & dep_hour < 12 ~ "Manhã",
dep_hour >= 12 & dep_hour < 18 ~ "Tarde",
TRUE ~ "Noite"
),
dep_period = factor(dep_period, levels = c("Manhã", "Tarde", "Noite"))
)A análise exploratória tem como finalidade compreender o comportamento dos dados de voo e identificar padrões que influenciam o consumo de combustível.
Principais objetivos:
Avaliar distribuições das variáveis operacionais.
Detectar outliers ou valores inconsistentes que possam afetar a modelagem.
Investigar relações entre variáveis que influenciam o fuel burn.
Identificar padrões operacionais úteis para o feature engineering.
Guiar a escolha dos modelos com base na estrutura e variabilidade dos dados.
A Aerometrics utilizou uma rede neural simples com função de ativação tanh para prever consumo de combustível em escala logaritmizada.
Os componentes principais (PCA) obtidos serviram como entrada para o modelo, reduzindo complexidade.
O desempenho foi avaliado via RMSE relativo.
data_train_pc <- data.frame(pca_out$x)
data_train_pc$fuel_burn <- data_train$fuel_burn %>% log1p() %>% scale()
nn_model <- neuralnet(fuel_burn ~ PC1 + PC2 + PC3, data=data_train_pc, hidden=c(3),
act.fct='tanh', linear.output=TRUE)## RMSE (Rede Neural) = 0.08932497
Também treinamos um modelo baseado em árvore de decisão, que permite interpretar a influência das variáveis de forma mais direta e intuitiva.
Esse método é útil para capturar relações não lineares e interações.
A validação cruzada foi utilizada para auxiliar na poda da árvore.
tree_model <- tree(
fuel_burn ~ airline + aircraft_type + flown_distance_enr +
flight_duration + total_ineff + flight_range + dep_hour,
df_train, mindev=0.001
)## [1] "RMSE (Árvore): 0.0690004290673126"
df_ensemble <- data.frame(fuel_burn = data_train$fuel_burn, nn = y_pred_nn, dt = y_pred_dt)
model_ensemble <- lm(fuel_burn ~ nn + dt, df_ensemble)
summary(model_ensemble)##
## Call:
## lm(formula = fuel_burn ~ nn + dt, data = df_ensemble)
##
## Residuals:
## Min 1Q Median 3Q Max
## -2030.0 -208.5 -11.7 176.4 10169.8
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -36.887662 10.461805 -3.526 0.000425 ***
## nn 0.150088 0.008179 18.351 < 2e-16 ***
## dt 0.859152 0.007923 108.434 < 2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 423.3 on 7276 degrees of freedom
## Multiple R-squared: 0.9726, Adjusted R-squared: 0.9726
## F-statistic: 1.294e+05 on 2 and 7276 DF, p-value: < 2.2e-16
Com o objetivo de melhorar a capacidade preditiva final, foi criado um modelo ensemble linear combinando:
As previsões da rede neural.
As previsões da árvore de decisão.
Os pesos foram estimados por regressão linear (LM), permitindo que o ensemble aprenda automaticamente qual modelo tem maior poder explicativo.
data_train$prediction_ensemble <- predict(model_ensemble, df_ensemble)
mean(abs(data_train$fuel_burn - data_train$prediction_ensemble) / data_train$fuel_burn)## [1] 0.06470415
Após treinar e calibrar, aplicamos o pipeline completo ao conjunto de teste:
Aplicação do mesmo feature engineering.
Projeção dos dados no espaço do PCA (usando o pca_out do treino).
Predição individual pelos modelos (NN e DT).
Combinação final pelo ensemble (usando os coef do treino).
mean_train <- mean(log1p(data_train$fuel_burn))
sd_train <- sd(log1p(data_train$fuel_burn))
x_test <- subset(data_test, select=c(8:12))
data_test_pc <- predict(pca_out, newdata=x_test) |> as.data.frame()
data_test_pc$fuel_burn <- (log1p(data_test$fuel_burn) - mean_train) / sd_train
y_test_scaled <- predict(nn_model, data_test_pc)
y_pred_nn <- expm1(y_test_scaled * sd_train + mean_train)
y_pred_dt <- predict(tree_model, df_test)
w <- coef(model_ensemble)
data_test$fuel_burn <- w["nn"] * y_pred_nn + w["dt"] * y_pred_dtO pipeline Aerometrics integra engenharia de atributos, PCA, rede neural e árvore de decisão.
O modelo ensemble mostrou melhor robustez geral.
A solução final está pronta para uso operacional.