Competição Kaggle: New York City Taxi Trip Duration
O objetivo deste desafio é prever a duração dos passeios de táxi em Nova York com base em recursos como coordenadas de viagem ou data e hora da partida.
Os dados vêm na forma de 1,5 milhão de observações de treinamento e 630k de observação de teste. O conjunto de dados é divulgado pela Comissão de Táxis e Limusines de Nova York, que inclui tempo de coleta, coordenadas geográficas, número de passageiros e várias outras variáveis. Cada linha contém uma viagem de táxi.
Primeiro serão estudados os dados originais, numa análise exploratória dos dados e os os potenciais outliers serão examinados.
Por fim, concluir este trabalho com um modelo linear generalizado e um modelo XGBoost simples que fornece uma previsão básica. A partir daí, julgar qual o melhor modelo a partir da medida RMSE, que será explanada no capítulo 3.1. deste trabalho.
Construir um modelo que prevê a duração total da viagem de táxi em Nova York.
Foi utlizada a linguagem funcional R.
RMSE significa Root-mean-square deviation (Raiz quadrada do erro-médio), é uma medida frequentemente usada das diferenças entre os valores (amostra ou população) previstos por um modelo ou um estimador e os valores observados. Sua fórmula é dada por:
O RMSE de um estimador \(\hat{\theta}\) com respeito a um parâmetro estimado \(\theta\) é definido como a raiz quadrada do erro quadrático médio :
\[{\displaystyle {\operatorname {RMSE} ({\hat {\theta}}) = {\sqrt {\operatorname {MSE} ({\hat {\theta}})}} = {\sqrt {\operatorname {E} (({\hat {\theta}} - \theta) ^ {2})}}.}} \]
O erro quadrático médio (RMSE) tem sido usado como um parâmetro estatístico padrão para medir o desempenho do modelo em várias ciências.
Breve revisão da literatura
“Gradient boosting é uma técnica de machine learning para problemas de regressão e classificação, que produz um modelo de previsão na forma de um ensemble.” English Wikipedia.org
“O modelo em si é o que chamamos de ensemble, uma combinação de vários modelos fracos para gerar um modelo poderoso. O modelo fraco utilizado pelo XGBoost é a árvore de decisão.” Serasa Experian, 2017
“Em um problema de regressão, os passos são equivalentes, com a diferença que a métrica que deve ser minimizada em cada divisão não é uma estimativa de impureza, mas tipicamente um erro quadrático médio do ajuste (ou outra métrica mais apropriada para o problema específico).” DataLab serasa experian 2019
“Um classificador ensemble (também chamado de comitê de learners, mistura de especialistas ou sistema de classificadores múltiplo), consiste em um conjunto de classificadores treinados individualmente, classificadores de base, cujas decisões são de alguma forma combinadas.” (Marques et al., 2012).
“A idéia do gradiente boosting originou-se da observação de Leo Breiman de que o boosting pode ser interpretado como um algoritmo de otimização em uma função de custo adequada.” English Wikipedia.org, 2019
“Gradient Boosting Machine é um meta-algoritmo de aprendizado supervisionado que é geralmente utilizado em problemas de classificação e regressão. O principio algorítmico por trás do GBM é a produção de previsões/classificações derivadas de modelos preditivos fracos (Weak Learners), em especial árvores de decisão essas que por sua vez combinadas via ensemble learning para redução de vieses dos algoritmos.” Mineração de Dados, 2018
Esta é uma técnica desenvolvida recentemente que se mostrou muito poderosa e hoje corresponde a uma das mais utilizadas em competições de machine learning. O princípio que está por trás de qualquer algoritmo de boosting é a combinação do resultado de muitos classificadores (ou regressores) fracos, se combinando para formar uma espécie de comitê forte de decisão. Embora não haja restrições quanto a estes classificadores e regressores, é usual a utilização de árvores.
Em sua definição matemática, boosting é uma forma de expansão, ajustando os dados em uma soma ponderada de funções elementares:
\[ f(x)=\sum_{m=1}^{M} \beta_m (x;\gamma_m),\]
onde \(\beta_m\) são os coeficientes da expansão e \(b(x;\gamma)\) são funções simples do argumento \(x\), caracterizadas pelo parâmetro \(\gamma\). Tipicamente estes modelos são ajustados ao se minimizar o valor esperado (sobre o conjunto de treino).
“O XGBoost (eXtreme Gradient Boosting) é uma conhecida e eficiente implementação de código aberto do algoritmo baseado em árvores com aumento de gradiente. O aumento de gradiente é um algoritmo de aprendizagem supervisionada que tenta prever com precisão uma variável de destino. O XGBoost tem excelente desempenho em competições de machine learning, pois lida de maneira robusta com uma variedade de tipos de dados, relacionamentos e distribuições, e o grande número de hiperparâmetros que podem ser aperfeiçoados e ajustados para um cenário mais apropriado. Essa flexibilidade faz do XGBoost uma escolha consistente para problemas de regressão, classificação (binária e multiclasse) e pontuação.” AWS, acesso em 2019
ver em https://medium.com/data-hackers/crossvalidation-de-maneira-did%C3%A1tica-79c9b080a6ec
Lista dos pacotes utilizados nesse trabalho.
library('tidyverse')
library('dplyr')
library('lubridate')
library('data.table')
library('ggplot2')
library('RColorBrewer')
library('corrplot')
library('readr')
library('data.table')
library('tibble')
library('tidyr')
library('stringr')
library('leaflet')
library('xgboost')
library('readr')
library('glm2')
library('grid')
library('yardstick')
library('caret')
library('xgboost')
Função extra: multiplot.
Referência: Multiple graphs on one page
multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) {
# Make a list from the ... arguments and plotlist
plots <- c(list(...), plotlist)
numPlots = length(plots)
# If layout is NULL, then use 'cols' to determine layout
if (is.null(layout)) {
# Make the panel
# ncol: Number of columns of plots
# nrow: Number of rows needed, calculated from # of cols
layout <- matrix(seq(1, cols * ceiling(numPlots/cols)),
ncol = cols, nrow = ceiling(numPlots/cols))
}
if (numPlots==1) {
print(plots[[1]])
} else {
# Set up the page
grid.newpage()
pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout))))
# Make each plot, in the correct location
for (i in 1:numPlots) {
# Get the i,j matrix positions of the regions that contain this subplot
matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE))
print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row,
layout.pos.col = matchidx$col))
}
}
}
Usou-se a função fread do pacote data.table para acelerar a leitura dos dados originais do Kaggle.
# Dados Originais
train_full <- fread("~/Trabalho_Analise2/train.csv")
test_full <- fread("~/Trabalho_Analise2/test.csv")
Visão geral da base de dados de treinamento:
glimpse(train_full)
## Observations: 1,458,644
## Variables: 11
## $ id <chr> "id2875421", "id2377394", "id3858529", "id350…
## $ vendor_id <int> 2, 1, 2, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, …
## $ pickup_datetime <chr> "2016-03-14 17:24:55", "2016-06-12 00:43:35",…
## $ dropoff_datetime <chr> "2016-03-14 17:32:30", "2016-06-12 00:54:38",…
## $ passenger_count <int> 1, 1, 1, 1, 1, 6, 4, 1, 1, 1, 1, 4, 2, 1, 1, …
## $ pickup_longitude <dbl> -73.98215, -73.98042, -73.97903, -74.01004, -…
## $ pickup_latitude <dbl> 40.76794, 40.73856, 40.76394, 40.71997, 40.79…
## $ dropoff_longitude <dbl> -73.96463, -73.99948, -74.00533, -74.01227, -…
## $ dropoff_latitude <dbl> 40.76560, 40.73115, 40.71009, 40.70672, 40.78…
## $ store_and_fwd_flag <chr> "N", "N", "N", "N", "N", "N", "N", "N", "N", …
## $ trip_duration <int> 455, 663, 2124, 429, 435, 443, 341, 1551, 255…
A base de dados de treinamento tem tamanho 1.458.644 observações e 11 variáveis que serão explanadas na seção 3.5.
Visão geral do conjunto de teste:
# Essa base não possui a variável dropoff_datetime e nem a trip_duration.
glimpse(test_full)
## Observations: 625,134
## Variables: 9
## $ id <chr> "id3004672", "id3505355", "id1217141", "id215…
## $ vendor_id <int> 1, 1, 1, 2, 1, 1, 1, 1, 2, 2, 1, 2, 1, 2, 1, …
## $ pickup_datetime <chr> "2016-06-30 23:59:58", "2016-06-30 23:59:53",…
## $ passenger_count <int> 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 4, 1, 1, 1, 1, …
## $ pickup_longitude <dbl> -73.98813, -73.96420, -73.99744, -73.95607, -…
## $ pickup_latitude <dbl> 40.73203, 40.67999, 40.73758, 40.77190, 40.76…
## $ dropoff_longitude <dbl> -73.99017, -73.95981, -73.98616, -73.98643, -…
## $ dropoff_latitude <dbl> 40.75668, 40.65540, 40.72952, 40.73047, 40.75…
## $ store_and_fwd_flag <chr> "N", "N", "N", "N", "N", "N", "N", "N", "N", …
Um breve resumo descritivo das variáveis.
A duração média em segundos de uma viagem de táxi em Nova York registrada no banco de dados foi de 959, que equivale a aproximadamente 16 minutos.
A duração máxima foi de 3.526.282 segundos que equivale a aproximadamente 40 dias, alarmando um outlier. A mediana da variável trip_duration foi de 662 segundos (~ 11 minutos).
Medidas descritivas da variável dependente trip_duration:
summary(train_full$trip_duration)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 1 397 662 959 1075 3526282
A distribuição da variável dependente é mostrada no ggplot abaixo. Observa-se nos gráficos que essa variável possui uma distribuição fortemente assimétrica.
g1 <- ggplot(train_full, aes(trip_duration)) +
geom_histogram (color = "white", fill= "#2171b5", bins = 30) +
xlab("trip_duration") +
ylab("Frequência") + ggtitle("Histograma")
g2 <- ggplot(train_full, aes(y = trip_duration, x =NULL)) +
geom_boxplot(fill= "#2171b5") +
ylab("trip_duration") + xlab(" ") + ggtitle("Boxplot")
layout <- matrix(c(1,2),1,2,byrow=TRUE)
multiplot(g1, g2, layout=layout)
Pela forte assimetria dos dados, vamos observar sua distribuição abaixo e acima da mediana \(mediana = 662\).
dados_full_abaixo <- train_full %>% filter(trip_duration < 662)
dados_full_acima <- train_full %>% filter(trip_duration >= 662)
t1 <- ggplot(dados_full_abaixo, aes(trip_duration)) +
geom_histogram (color = "white", fill= "#2171b5", bins = 30) +
xlab("trip_duration (< 662)") +
ylab("Frequência") + ggtitle("Histograma")
t2 <- ggplot(dados_full_acima, aes(trip_duration)) +
geom_histogram (color = "white", fill= "#2171b5", bins = 30) +
xlab("trip_duration (> = 662)") +
ylab("Frequência") + ggtitle("Histograma")
t3 <- ggplot(dados_full_abaixo, aes(y = trip_duration, x =NULL)) +
geom_boxplot(fill= "#2171b5") +
ylab("trip_duration (< 662)") + xlab(" ") + ggtitle("Boxplot")
t4 <- ggplot(dados_full_acima, aes(y = trip_duration, x =NULL)) +
geom_boxplot(fill= "#2171b5") +
ylab("trip_duration (> = 662)") + xlab(" ") + ggtitle("Boxplot")
layout <- matrix(c(1,2),1,2,byrow=TRUE)
multiplot(t1, t3, layout=layout)
layout <- matrix(c(1,2),1,2,byrow=TRUE)
multiplot(t2, t4, layout=layout)
Será utilizado o log da variável dependente para tentar um bom ajuste no modelo:
train_full$trip_duration2 <- log(train_full$trip_duration)
summary(train_full$trip_duration2)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.000 5.984 6.495 6.465 6.980 15.076
g9 <- ggplot(train_full, aes(trip_duration2)) +
geom_histogram (color = "white", fill= "#2171b5", bins = 30) +
xlab("log(trip_duration)") +
ylab("Frequência") + ggtitle("Histograma")
g7 <- ggplot(train_full, aes(y = trip_duration2, x =NULL)) +
geom_boxplot(fill= "#2171b5") +
ylab("log(trip_duration)") + xlab(" ") + ggtitle("Boxplot")
layout <- matrix(c(1,2),1,2,byrow=TRUE)
multiplot(g9, g7, layout=layout)
Só aceita os valores 1 ou 2, provavelmente para diferenciar duas empresas de táxi.
Frequência do vendor_id:
table(train_full$vendor_id)
##
## 1 2
## 678342 780302
ggplot(train_full, aes(x=factor(vendor_id))) +
geom_bar(color = "white", fill= "#2171b5" ) +
xlab("Vendor Id") + ylab("Frequência")
Frequência de Store_and_fwd_flag:
table(train_full$store_and_fwd_flag)
##
## N Y
## 1450599 8045
ggplot(train_full, aes(x=factor(store_and_fwd_flag))) +
geom_bar(color = "white", fill= "#2171b5" ) +
xlab("Store and fwd flag") + ylab("Frequência")
Store_and_fwd_flag foi codificada em: N = 1 e Y = 2.
# N = 1
# Y = 2
train_full = train_full %>% mutate(store_and_fwd_flag = ifelse(.$store_and_fwd_flag == "N", 1,2))
pickup_datetime e dropoff_datetime (no conjunto de treinamento) são combinações de data e hora que teremos que reformatar para uma forma mais útil. Foi usada a função read_delim do pacote readr para formatar a varivável pickup_datetime em uma formas úteis de analisar, utilizando o pacote lubridate.#abrindo novamente a base de dados para ter as variaveis no formato "datatime"
train_full <- read_delim("train.txt", "\t", escape_double = FALSE,
col_types = cols(dropoff_datetime = col_datetime(format = "%Y-%m-%d %H:%M:%S"),
pickup_datetime = col_datetime(format = "%Y-%m-%d %H:%M:%S")),
trim_ws = TRUE)
train_full$trip_duration2 <- log(train_full$trip_duration)
Uilizando o pacote lubridate, foram extraídos o dia da semana, hora e o mês da variável pickup_datetime (data, hora e mês em que o medidor foi ativado). Nessa variável podemos analisar o quanto teve de demanda por dia, mês e hora. Não foi analisada dropoff_datetime, pois ela não entrará no modelo que será construído, uma vez que não está na base de teste.
# Tratamento da variável `pickup_datetime`
######pickup_datetime
train_full <- train_full %>% mutate(hr_up_int = hour(train_full$pickup_datetime)) %>%
mutate(minuto_up_int = (minute(train_full$pickup_datetime))/60) %>%
mutate(horas_up = hr_up_int + minuto_up_int) %>%
mutate(dia_up = wday(train_full$pickup_datetime))%>%
mutate(mes_up = month(train_full$pickup_datetime))
# dia_up
train_full = train_full %>% mutate(dia_up = ifelse(.$dia_up == 1, "Domingo",
ifelse(.$dia_up == 2, "Segunda",
ifelse(.$dia_up == 3, "Terca",
ifelse(.$dia_up == 4, "Quarta",
ifelse(.$dia_up == 5, "Quinta",
ifelse(.$dia_up == 6, "Sexta",
ifelse(.$dia_up == 7, "Sabado", .$dia_up))))))))
# mes_up
train_full = train_full %>% mutate(mes_up = ifelse(.$mes_up == 1, "Jan",
ifelse(.$mes_up == 2, "Fev",
ifelse(.$mes_up == 3, "Mar",
ifelse(.$mes_up == 4, "Abr",
ifelse(.$mes_up == 5, "Mai",
ifelse(.$mes_up == 6, "Jun",
ifelse(.$mes_up == 7, "Jul", .$mes_up))))))))
Análise das novas variáveis que foram extraídas da variável pickup_datetime:
# Variável `pickup_datetime` após extraído o mês
table(train_full$mes_up)
##
## Abr Fev Jan Jun Mai Mar
## 25241 23946 22967 23576 24622 25512
dados1 <- train_full %>%
dplyr::select(mes_up) %>%
transmute(Mes = mes_up) %>%
group_by(Mes) %>%
summarise(n = n()) %>%
mutate(Frequencia = n/sum(n)) %>%
arrange(desc(n)) %>%
mutate(Mes = factor (Mes, levels = Mes))
# grafico
dados1 %>%
ggplot(aes(x = reorder(Mes, n), y= n, fill= Mes)) +
geom_bar(stat = "identity") +
guides(fill = "none") + #tirou a legenda
coord_flip() + #muda a direcao do grafico de barras
labs(x = "Mês", y = "Frequência", title = "Frequência dos meses de ativação do medidor") +
geom_label(aes(label = paste(round(100*Frequencia), "%", sep = ""))) + # colocou o rotulo
scale_fill_brewer(palette = "Blues", direction = -1)
# Variável `pickup_datetime` após extraído o dia da semana
table(train_full$dia_up)
##
## Domingo Quarta Quinta Sabado Segunda Sexta Terca
## 19427 21090 21805 22019 18980 22274 20269
dados2 <- train_full %>%
dplyr::select(dia_up) %>%
transmute(Dia = dia_up) %>%
group_by(Dia) %>%
summarise(n = n()) %>%
mutate(Frequencia = n/sum(n)) %>%
arrange(desc(n)) %>%
mutate(Dia = factor (Dia, levels = Dia))
# grafico
dados2 %>%
ggplot(aes(x = reorder(Dia, n), y= n, fill= Dia)) +
geom_bar(stat = "identity") +
guides(fill = "none") + #tirou a legenda
coord_flip() + #muda a direcao do grafico de barras
labs(x = "Dia da semana", y = "Frequência", title = "Frequência dos dias de ativação do medidor") +
geom_label(aes(label = paste(round(100*Frequencia), "%", sep = ""))) + # colocou o rotulo
scale_fill_brewer(palette = "Blues", direction = -1)
#Variável `pickup_datetime` após extraído o horário
summary(train_full$horas_up)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00 9.55 14.75 14.09 19.45 23.98
u1 <- ggplot(train_full, aes(horas_up)) +
geom_histogram (color = "white", fill= "#2171b5", bins = 30) +
xlab("Horários ativação do medidor") +
ylab("Frequência") + ggtitle("Histograma")
u2 <- ggplot(train_full, aes(y = horas_up, x =NULL)) +
geom_boxplot( fill= "#2171b5") +
ylab("Horários ativação do medidor") + xlab(" ") + ggtitle("Boxplot")
layout <- matrix(c(2,1),2,1,byrow=TRUE)
multiplot(u1, u2, layout=layout)
ggplot(train_full, aes(x=horas_up)) +
geom_density(color = "white", fill= "#2171b5") +
xlab("Horários ativação do medidor") + ylab("Densidade")
passenger_count tem mediana de 1 e um máximo de 9.table(train_full$passenger_count)
##
## 0 1 2 3 4 5 6 7
## 7 103136 21141 6058 2835 7797 4889 1
train_full %>%
group_by(passenger_count) %>%
count() %>%
ggplot(., aes(x=reorder(passenger_count, -n), y=n)) +
geom_bar(stat="identity", color = "white", fill= "#2171b5") + xlab("Número de passageiros") + ylab("Frequência")
distancia <- ((train_full$pickup_latitude - train_full$dropoff_latitude)^2 +
(train_full$pickup_longitude - train_full$dropoff_longitude)^2)
train_full <- train_full %>%
mutate(distancia = distancia)
summary(train_full$distancia)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.00000 0.00016 0.00045 0.00337 0.00148 40.60621
d1 <- ggplot(train_full, aes(distancia)) +
geom_histogram (color = "white", fill= "#2171b5", bins = 30) +
xlab("distancia") +
ylab("Frequência") + ggtitle("Histograma")
d2 <- ggplot(train_full, aes(y = distancia, x =NULL)) +
geom_boxplot() +
ylab("distancia") + xlab(" ") + ggtitle("Boxplot")
layout <- matrix(c(2,1),2,1,byrow=TRUE)
multiplot(d1, d2, layout=layout)
Foi retirada uma amostra equivalente a 10% do tamanho da base para acelerar a análise exploratória por gráficos do pacote leaflet, totalizando 145.864 observações.
train_5perc <- train_full %>% sample_frac(0.05)
Com uso do pacote leaflet foram feitos mapas de pontos para observar as localizações que o taxista ligou e desligou o medidor do táxi nas viagens.
Localizações que o motorista ligou o medidor:
leaflet() %>% addTiles() %>% addCircles(data = train_5perc,
lng = train_5perc$pickup_longitude,
lat = train_5perc$pickup_latitude,
radius = 1)
Localizações que o motorista desligou o medidor:
leaflet() %>% addTiles() %>% addCircles(data = train_5perc,
lng = train_5perc$dropoff_longitude,
lat = train_5perc$dropoff_latitude,
radius = 1)
O objetivo é fazer a previsão do tempo de duração das viagens de táxi.
As variáveis de entrada do modelo são: trip_duration & trip_durantion2 (log de trip_duration), como as variáveis dependentes do modelo Gama e do modelo Gradient Bossting, respectivamente. As demais sendo as variáveis independentes vendor_id, passenger_count, horas_up (horarios que o motorista ligou o medidor), dia_up (dias da semana que o motorista ligou o medidor), mes_up (meses que o motorista ligou o medidor), pickup_longitude, pickup_latitude, dropoff_longitude e dropoff_latitude.
Para modelagem, vamos precisar da base de Treinamento (80% da atual base de treinamento dada pelo kaggle) e da base de Validação (20% da atual base de treinamento dada pelo kaggle).
####------- divide-se a base de train em trn = 80% e validacao = 20%
set.seed(8676)
train_full <- train_full %>%
mutate(flag = sample(0:1, n(), replace = T, prob=c(0.8, 0.2)))
train_80 <- train_full %>% filter(flag == 0) %>% dplyr::select(-flag) #Base de treinamento com 80% da base original
val_20 <- train_full %>% filter(flag==1) %>% dplyr::select(-flag) #Base de Validação com 20% da base original
O modelo Gamma foi escolhido para esse ajuste, por ser um modelo adequado para variáveis respostas positivas assimétricas. A função densidade de probabilidade é dada por :
\[{\displaystyle f (x; \alpha, \beta) = {\frac {\beta ^ {\alpha} x ^ {\alpha -1} e ^ {- \beta x}} {\Gamma (\alpha)} } \quad {\text {for}} \ \ x> 0 \ \ {\text {e}} \ \ \alpha,\ \beta> 0,} \]
Utilizou-se a variável trip_duration sem a transformação logarítimica e será observado o seu ajuste:
set.seed(7871)
k = 5 #vezes que vou dividir o train
# Cross Validation
train_80$crossvalidation <- sample(1:k, nrow(train_80), replace = TRUE)
predicao = rep(0,nrow(val_20))
for(i in 1:k){
traincv <- train_80 %>% filter(crossvalidation !=i)
valcv <- train_80 %>% filter(crossvalidation == i)
modelo.gama <- glm2(formula = trip_duration ~ vendor_id + passenger_count +
pickup_longitude + pickup_latitude + dropoff_longitude +
dropoff_latitude + factor(store_and_fwd_flag) + horas_up +
dia_up + mes_up + distancia, family = Gamma(link = "log"),
data = train_80)
predicao <- predicao + predict(modelo.gama, val_20, type = "response")
}
RMSE referente ao mlg Gamma ajustado:
yardstick::rmse_vec(val_20$trip_duration, predicao)
# valid rmse: 10.87768
Nsesse modelo em XGBoost (eXtreme Gradient Boosting), utilizou-se a variável trip_durationcom a tranformação logarítimica afim de ter um modelo melhor que o MLG ajustado anteriormente.
set.seed(30)
train <- read_delim("train.txt", "\t", escape_double = FALSE,
col_types = cols(dropoff_datetime = col_datetime(format = "%Y-%m-%d %H:%M:%S"),
pickup_datetime = col_datetime(format = "%Y-%m-%d %H:%M:%S")),
trim_ws = TRUE)
train$trip_duration2 <- log(train$trip_duration)
#Tratando as variaveis pickup_datetime e dropoff_datetime
# pickup_datetime
train <- train %>% mutate(hr_up_int = hour(train$pickup_datetime)) %>%
mutate(minuto_up_int = (minute(train$pickup_datetime))/60) %>%
mutate(horas_up = hr_up_int + minuto_up_int) %>%
mutate(dia_up = wday(train$pickup_datetime))%>%
mutate(mes_up = month(train$pickup_datetime))
# dropoff_datetime
train <- train %>% mutate(hr_off_int = hour(train$dropoff_datetime)) %>%
mutate(minuto_off_int = (minute(train$dropoff_datetime))/60) %>%
mutate(horas_off = hr_off_int + minuto_off_int) %>%
mutate(dia_off = wday(train$dropoff_datetime))%>%
mutate(mes_off = month(train$dropoff_datetime))
## Levels: Sun1 < Mon2 < Tues3 < Wed4 < Thurs5 < Fri6 < Sat7
#### criando variavel a partir da distancia euclidiana de lat long
distancia <- ((train$pickup_latitude - train$dropoff_latitude)^2 +
(train$pickup_longitude - train$dropoff_longitude)^2)
train <- train %>%
mutate(distancia = distancia)
#-------------- store_and_fwd_flag
# N = 1
# Y = 2
train = train %>% mutate(store_and_fwd_flag = ifelse(.$store_and_fwd_flag == "N", 1,2))
####----------------- selecionando as variaveis que vou utilizar
train <- train %>% dplyr::select(vendor_id, passenger_count,
pickup_longitude,pickup_latitude,
dropoff_longitude, dropoff_latitude,
store_and_fwd_flag, trip_duration2,
horas_up, dia_up, mes_up,distancia)
####------- divide-se a base de train em trn = 80% e validacao = 20%
train <- train %>%
mutate(flag = sample(0:1, n(), replace = T, prob=c(0.8, 0.2)))
train_80 <- train %>% filter(flag == 0) %>% dplyr::select(-flag) #Base de treinamento com 80% da base original
val_20 <- train %>% filter(flag==1) %>% dplyr::select(-flag) #Base de Validação com 20% da base original
Tem-se como resultado, o RMSE referente ao modelo ajustado:
# RMSE
yardstick::rmse_vec(val_20$trip_duration2, predicao2)
# valid-rmse: 0.429299
Segue a importanância das variáveis do modelo gradient boosting:
imp_matrix <- as.tibble(xgb.importance(feature_names = colnames(train %>% dplyr::select(-trip_duration2)), model = gb_dt))
imp_matrix %>%
ggplot(aes(reorder(Feature, Gain, FUN = max), Gain, fill = Feature)) +
geom_col() +
coord_flip() +
theme(legend.position = "none") +
labs(x = "Variáveis", y = "Importância") +
ggtitle ("Importância das Variáveis")
O modelo mais adequado para prever o tempo de viagens de táxi de Nova York foi o o Gradient Boosting que apresntou menor RMSE.
| Modelo | RMSE |
|---|---|
| MLG Gamma (CV) | 10.87768 |
| Gradient Boosting (CV) | 0.429299 |
| :———: | :—— |
NYC Taxi EDA - Update: The fast & the curious. Acesso em 12 de Abr. de 2019. Disponível em Link
ZAMPIERI, Fernando Godinho et al. Modelo de análise gradiente boosted do impacto do índice de massa corporal nos desfechos em curto prazo de pacientes clínicos gravemente enfermos. Revista Brasileira de Terapia Intensiva, 2015.