Prever a duração de corridas de táxi em ambientes urbanos complexos, como a cidade de Nova Iorque, é um desafio com aplicações diretas na logística urbana, precificação dinâmica e satisfação do cliente. A imprevisibilidade do tráfego, condições climáticas e comportamento de passageiros tornam difícil oferecer estimativas confiáveis em tempo real. O objetivo deste projeto é entender os padrões que influenciam a duração das viagens e detectar anomalias — como corridas com durações incoerentes ou localizações inconsistentes — que possam distorcer análises ou indicar comportamentos atípicos.
O interesse nesse problema vem do seu potencial prático e analítico: ele permite explorar aspectos de ciência de dados como limpeza de dados, engenharia de variáveis, análise temporal e espacial, e modelagem supervisionada e não supervisionada. Além disso, anomalias podem sinalizar erros, fraudes ou eventos únicos que são críticos em muitas aplicações reais.
Utilizaremos o conjunto de dados da competição “NYC Taxi Trip Duration”, disponível no Kaggle. Esse dataset contém registros detalhados de corridas de táxi realizados em 2016, incluindo atributos como data/hora de início, duração da viagem (em segundos), coordenadas geográficas de origem e destino, número de passageiros e identificadores de empresa de táxi.
Nossa abordagem será estruturada da seguinte forma: - Importação, limpeza e transformação dos dados; - Criação de variáveis derivadas, como: hora do dia, dia da semana, distância geográfica e velocidade média; - Análise exploratória com foco espacial e temporal; - Aplicação de técnicas de detecção de anomalias para identificar corridas incomuns ou inconsistentes; - Construção de modelos preditivos para estimar a duração das corridas.
Além dos modelos clássicos de regressão supervisionada (como Regressão Linear, Árvores de Decisão e XGBoost), será aplicada detecção de anomalias com métodos não supervisionados como: - Análise de outliers por z-score ou IQR; - Algoritmos baseados em densidade, como DBSCAN; - Avaliação visual de dispersões em scatterplots (ex: duração vs. distância, velocidade vs. hora do dia).
Essas técnicas permitirão tanto identificar outliers que prejudiquem a modelagem quanto extrair perfis interessantes e inesperados do comportamento das corridas.
A análise permitirá: - Criar modelos mais robustos ao identificar e tratar outliers; - Melhorar a estimativa de tempo de viagem para usuários e empresas; - Fornecer insights operacionais, como identificar horários com maior risco de desvios anômalos; - Detectar eventos atípicos (como corridas suspeitas ou incoerentes) que podem sinalizar fraudes, erros ou exceções operacionais.
O dataset é especialmente rico para esse tipo de trabalho, pois reúne dados temporais, espaciais, categóricos e numéricos — permitindo uma exploração profunda e significativa, com aplicações em machine learning, estatística e visualização de dados.
A seguir, estão listados os pacotes utilizados neste projeto, junto com uma explicação breve sobre o papel de cada um no processo de análise. Embora os pacotes sejam carregados no script, esta seção tem o objetivo de documentar claramente os requisitos para reprodutibilidade do trabalho.
tidyverse utilizado
para manipulação de dados, como filtragem, seleção de colunas, criação
de variáveis e agrupamentos.ggplot2, facilitando a
comparação visual de informações.Os dados utilizados neste projeto foram obtidos da competição NYC Taxi Trip Duration - Kaggle. O dataset contém registros públicos de corridas de táxi realizadas em Nova Iorque durante o ano de 2016.
O conjunto de dados utilizado neste projeto tem como propósito original subsidiar a modelagem preditiva da duração das corridas de táxi na cidade de Nova York. Ele foi originalmente disponibilizado pela plataforma Kaggle, no contexto de uma competição realizada em 2016, e contém registros detalhados de corridas de táxi realizadas ao longo do ano de 2016 (período de coleta).
A amostra selecionada para este projeto contém 1.458.644 registros (linhas), e a versão original da base incluía 11 variáveis principais:
id: identificador único da corrida.vendor_id: código da empresa fornecedora do táxi (1 ou
2).pickup_datetime: data e hora da coleta do
passageiro.dropoff_datetime: data e hora da finalização da
corrida.passenger_count: número de passageiros na
corrida.pickup_longitude e pickup_latitude:
coordenadas de origem.dropoff_longitude e dropoff_latitude:
coordenadas de destino.store_and_fwd_flag: indica se os dados foram
armazenados no veículo antes de serem enviados (Y/N).trip_duration: duração da corrida em segundos
(variável-alvo).Durante a análise exploratória e preparação dos dados, foram identificadas as seguintes peculiaridades:
trip_duration: foram encontradas corridas com
duração de apenas 1 segundo ou mais de 10 horas, o que pode indicar
erros de coleta ou registros atípicos.store_and_fwd_flag:
essa variável categórica aparece como string (‘Y’ ou ‘N’), o que exige
tratamento prévio antes de ser usada em modelos preditivos.Essas características exigiram uma etapa cuidadosa de limpeza, transformação e amostragem para garantir que o conjunto de dados estivesse adequado às análises subsequentes.
Para realizar a análise e modelagem das corridas de táxi, foi conduzido um processo estruturado de importação, limpeza e transformação dos dados. Esta etapa teve como objetivo garantir a qualidade, consistência e relevância das informações, eliminando registros inadequados que poderiam distorcer os resultados dos modelos preditivos.
Os dados utilizados foram extraídos de um arquivo .csv
contendo informações detalhadas sobre corridas realizadas na cidade de
Nova York. A leitura e manipulação das informações foi facilitada pelo
uso de pacotes especializados para tratamento de dados e manipulação de
datas e variáveis.
Durante a etapa de limpeza, foram definidos critérios específicos para excluir registros que apresentavam inconsistências ou valores atípicos. Foram removidas:
Além da limpeza, o conjunto de dados foi enriquecido com variáveis derivadas relevantes para análise, tais como:
Essas etapas garantiram que apenas dados confiáveis e coerentes fossem mantidos no conjunto final, aumentando a robustez da análise e a acurácia dos modelos que seriam aplicados na fase seguinte.
Após a limpeza, o conjunto foi enriquecido com variáveis auxiliares importantes para a análise:
Essas transformações possibilitaram uma base de dados mais confiável, reduzindo ruídos e inconsistências que poderiam impactar negativamente a performance dos modelos preditivos.
Abaixo está uma visualização condensada do conjunto de dados final, limitado a 200 linhas para fins de clareza.
library(dplyr)
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(lubridate)
##
## Attaching package: 'lubridate'
## The following objects are masked from 'package:base':
##
## date, intersect, setdiff, union
library(geosphere)
library(knitr)
library(kableExtra)
##
## Attaching package: 'kableExtra'
## The following object is masked from 'package:dplyr':
##
## group_rows
dados <- readr::read_csv("/Users/lucasaraujo/Projects/R_Projects/CPAD/nyc-taxi-trip-duration/train.csv")
## Rows: 1458644 Columns: 11
## ── Column specification ────────────────────────────────────────────────────────
## Delimiter: ","
## chr (2): id, store_and_fwd_flag
## dbl (7): vendor_id, passenger_count, pickup_longitude, pickup_latitude, dro...
## dttm (2): pickup_datetime, dropoff_datetime
##
## ℹ Use `spec()` to retrieve the full column specification for this data.
## ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
dados <- dados %>%
mutate(
trip_duration = as.numeric(difftime(dropoff_datetime, pickup_datetime, units = "secs")),
distance_km = distHaversine(
cbind(pickup_longitude, pickup_latitude),
cbind(dropoff_longitude, dropoff_latitude)
) / 1000,
speed_kmph = distance_km / (trip_duration / 3600)
)
dados %>%
select(id, pickup_datetime, passenger_count, trip_duration, distance_km, speed_kmph) %>%
head(200) %>%
kable() %>%
kable_styling(full_width = FALSE)
| id | pickup_datetime | passenger_count | trip_duration | distance_km | speed_kmph |
|---|---|---|---|---|---|
| id2875421 | 2016-03-14 17:24:55 | 1 | 455 | 1.5001995 | 11.869710 |
| id2377394 | 2016-06-12 00:43:35 | 1 | 663 | 1.8075298 | 9.814641 |
| id3858529 | 2016-01-19 11:35:24 | 1 | 2124 | 6.3922513 | 10.834324 |
| id3504673 | 2016-04-06 19:32:31 | 1 | 429 | 1.4871625 | 12.479686 |
| id2181028 | 2016-03-26 13:30:55 | 1 | 435 | 1.1899200 | 9.847613 |
| id0801584 | 2016-01-30 22:01:40 | 6 | 443 | 1.1001735 | 8.940462 |
| id1813257 | 2016-06-17 22:34:59 | 4 | 341 | 1.3277643 | 14.017453 |
| id1324603 | 2016-05-21 07:54:58 | 1 | 1551 | 5.7213827 | 13.279805 |
| id1301050 | 2016-05-27 23:12:23 | 1 | 255 | 1.3118212 | 18.519828 |
| id0012891 | 2016-03-10 21:45:01 | 1 | 1225 | 5.1268985 | 15.066804 |
| id1436371 | 2016-05-10 22:08:41 | 1 | 1274 | 3.8104032 | 10.767230 |
| id1299289 | 2016-05-15 11:16:11 | 4 | 1128 | 3.7773227 | 12.055285 |
| id1187965 | 2016-02-19 09:52:46 | 2 | 1114 | 1.8615661 | 6.015833 |
| id0799785 | 2016-06-01 20:58:29 | 1 | 260 | 0.9927958 | 13.746403 |
| id2900608 | 2016-05-27 00:43:36 | 1 | 1414 | 6.3899860 | 16.268706 |
| id3319787 | 2016-05-16 15:29:02 | 1 | 211 | 0.6573135 | 11.214828 |
| id3379579 | 2016-04-11 17:29:50 | 1 | 2316 | 3.4319262 | 5.334600 |
| id1154431 | 2016-04-14 08:48:26 | 1 | 731 | 2.5415157 | 12.516357 |
| id3552682 | 2016-06-27 09:55:13 | 1 | 1317 | 4.6103600 | 12.602351 |
| id3390316 | 2016-06-05 13:47:23 | 1 | 251 | 1.3047312 | 18.713276 |
| id2070428 | 2016-02-28 02:23:02 | 1 | 486 | 2.5087334 | 18.583210 |
| id0809232 | 2016-04-01 12:12:25 | 1 | 652 | 1.7264820 | 9.532723 |
| id2352683 | 2016-04-09 03:34:27 | 1 | 423 | 2.0694005 | 17.611919 |
| id1603037 | 2016-06-25 10:36:26 | 1 | 1163 | 4.8802533 | 15.106545 |
| id3321406 | 2016-06-03 08:15:05 | 1 | 2485 | 20.6256547 | 29.880224 |
| id0129640 | 2016-02-14 13:27:56 | 1 | 1283 | 4.5646327 | 12.808011 |
| id3587298 | 2016-02-27 21:56:01 | 1 | 1130 | 6.0628937 | 19.315414 |
| id2104175 | 2016-06-20 23:07:16 | 1 | 694 | 3.7429304 | 19.415777 |
| id3973319 | 2016-06-13 21:57:27 | 1 | 892 | 2.5276776 | 10.201389 |
| id1410897 | 2016-03-23 14:10:39 | 1 | 2331 | 9.9505774 | 15.367687 |
| id0266980 | 2016-05-17 10:47:51 | 1 | 1479 | 4.5697066 | 11.123018 |
| id2822549 | 2016-05-21 13:03:24 | 1 | 1048 | 5.4291271 | 18.649673 |
| id3075902 | 2016-05-10 19:27:38 | 2 | 1022 | 4.5043245 | 15.866505 |
| id0023813 | 2016-04-17 14:38:30 | 1 | 2269 | 10.2498541 | 16.262439 |
| id3970352 | 2016-01-09 12:55:35 | 1 | 707 | 1.4347050 | 7.305429 |
| id3361153 | 2016-03-11 07:11:23 | 1 | 526 | 1.4939083 | 10.224467 |
| id1870624 | 2016-01-05 15:29:54 | 3 | 553 | 1.1376650 | 7.406138 |
| id2403238 | 2016-06-23 23:00:09 | 1 | 277 | 0.9605102 | 12.483165 |
| id3323083 | 2016-05-27 14:26:12 | 2 | 1189 | 3.3161211 | 10.040400 |
| id3720663 | 2016-05-10 16:14:56 | 1 | 1523 | 2.5904220 | 6.123125 |
| id0578558 | 2016-04-21 21:28:27 | 2 | 1450 | 5.4831821 | 13.613418 |
| id2573056 | 2016-04-14 13:27:52 | 2 | 1102 | 2.2388027 | 7.313693 |
| id2129090 | 2016-03-14 14:05:39 | 1 | 1346 | 1.9744150 | 5.280753 |
| id3961107 | 2016-03-19 01:12:46 | 1 | 363 | 1.1485252 | 11.390332 |
| id3326491 | 2016-02-12 07:41:56 | 1 | 559 | 2.2012435 | 14.176166 |
| id0718344 | 2016-06-13 15:52:20 | 1 | 1478 | 8.1803566 | 19.925090 |
| id3188770 | 2016-01-03 16:59:02 | 1 | 348 | 1.3159194 | 13.612959 |
| id1956279 | 2016-02-26 08:37:00 | 1 | 375 | 1.7726931 | 17.017854 |
| id2391523 | 2016-05-18 21:50:24 | 3 | 1217 | 5.0737098 | 15.008509 |
| id2662609 | 2016-04-10 19:11:03 | 1 | 876 | 3.4809316 | 14.305198 |
| id2067879 | 2016-01-19 23:19:01 | 1 | 1557 | 17.3602432 | 40.139291 |
| id1939961 | 2016-05-07 13:18:52 | 1 | 1647 | 4.7532816 | 10.389687 |
| id0675800 | 2016-02-15 09:25:15 | 6 | 634 | 2.0273415 | 11.511719 |
| id2569332 | 2016-04-13 14:24:47 | 1 | 365 | 1.1542083 | 11.383972 |
| id0526266 | 2016-05-15 09:42:58 | 1 | 819 | 9.6286109 | 42.323565 |
| id3827863 | 2016-04-19 11:29:08 | 3 | 3528 | 3.8501675 | 3.928742 |
| id1388344 | 2016-01-02 15:41:11 | 2 | 1228 | 1.5624758 | 4.580548 |
| id1079955 | 2016-04-22 11:28:00 | 1 | 2607 | 4.5636362 | 6.301914 |
| id0256505 | 2016-03-14 15:04:38 | 1 | 695 | 2.5198670 | 13.052549 |
| id1530524 | 2016-03-19 17:41:05 | 1 | 472 | 4.0255040 | 30.702997 |
| id1674872 | 2016-02-29 02:46:24 | 1 | 526 | 3.1326524 | 21.440207 |
| id1040444 | 2016-01-07 17:01:32 | 4 | 721 | 2.0464611 | 10.218114 |
| id1674996 | 2016-05-13 12:32:12 | 1 | 512 | 1.6945387 | 11.914725 |
| id1965939 | 2016-05-24 12:16:33 | 1 | 720 | 3.3261667 | 16.630834 |
| id0442192 | 2016-04-10 16:07:46 | 1 | 174 | 1.2205858 | 25.253500 |
| id0515898 | 2016-05-21 17:38:55 | 1 | 478 | 1.1016367 | 8.296846 |
| id1182327 | 2016-02-29 11:22:35 | 1 | 788 | 2.4773736 | 11.317951 |
| id3913101 | 2016-06-25 22:05:46 | 2 | 1003 | 13.1258238 | 47.111631 |
| id1680350 | 2016-03-18 20:56:16 | 1 | 215 | 0.6253121 | 10.470342 |
| id0913838 | 2016-02-03 16:22:50 | 5 | 870 | 2.6052727 | 10.780439 |
| id3896508 | 2016-06-07 22:32:32 | 1 | 814 | 5.8385009 | 25.821380 |
| id2846400 | 2016-03-16 20:13:12 | 1 | 637 | 1.3528707 | 7.645737 |
| id1510700 | 2016-02-20 21:58:13 | 1 | 57 | 0.3287004 | 20.760025 |
| id0813128 | 2016-02-20 18:57:43 | 2 | 589 | 1.0752873 | 6.572214 |
| id1158195 | 2016-03-24 17:58:51 | 1 | 2275 | 11.2180124 | 17.751580 |
| id0959273 | 2016-03-20 23:16:39 | 1 | 647 | 2.8253513 | 15.720657 |
| id0739660 | 2016-05-16 13:07:10 | 3 | 1628 | 5.3796343 | 11.895997 |
| id3769871 | 2016-06-17 17:32:59 | 1 | 2337 | 4.9193956 | 7.578016 |
| id1818021 | 2016-03-23 00:34:10 | 1 | 674 | 4.2280963 | 22.583304 |
| id0982165 | 2016-04-12 21:29:16 | 1 | 1190 | 6.4926460 | 19.641618 |
| id1519515 | 2016-06-11 12:52:19 | 1 | 1191 | 5.0911457 | 15.388853 |
| id1082443 | 2016-02-25 14:56:26 | 1 | 785 | 1.3634640 | 6.252828 |
| id2934884 | 2016-01-07 19:32:15 | 1 | 520 | 1.2607153 | 8.728029 |
| id1205949 | 2016-06-05 18:43:14 | 1 | 218 | 0.9175598 | 15.152363 |
| id2592310 | 2016-06-13 07:20:46 | 1 | 222 | 0.7912175 | 12.830554 |
| id0883711 | 2016-01-16 21:22:41 | 1 | 1204 | 4.7550854 | 14.217863 |
| id0283075 | 2016-04-06 23:42:26 | 1 | 1782 | 18.7945170 | 37.968721 |
| id2107497 | 2016-05-13 20:46:55 | 2 | 1174 | 1.5019894 | 4.605760 |
| id2090852 | 2016-01-28 11:25:20 | 1 | 336 | 0.9069032 | 9.716820 |
| id1297351 | 2016-06-24 14:24:31 | 1 | 470 | 1.5934134 | 12.204868 |
| id0667605 | 2016-05-27 16:17:36 | 1 | 346 | 1.3866304 | 14.427369 |
| id1476107 | 2016-05-22 15:41:29 | 1 | 419 | 1.4821387 | 12.734366 |
| id0673727 | 2016-05-18 19:15:27 | 1 | 1762 | 9.9955371 | 20.422210 |
| id2030290 | 2016-03-31 11:33:30 | 3 | 2341 | 10.2951677 | 15.831954 |
| id3770790 | 2016-02-13 13:12:49 | 1 | 406 | 1.4409540 | 12.776932 |
| id3025098 | 2016-01-20 19:21:31 | 1 | 596 | 2.2203558 | 13.411545 |
| id3333094 | 2016-06-02 23:34:00 | 1 | 435 | 1.4199746 | 11.751514 |
| id2228940 | 2016-02-04 13:22:02 | 1 | 1108 | 2.9896337 | 9.713611 |
| id2102594 | 2016-03-30 16:14:29 | 1 | 2824 | 16.0255152 | 20.429127 |
| id0010677 | 2016-04-29 10:40:34 | 2 | 769 | 1.3074381 | 6.120647 |
| id3194108 | 2016-06-01 11:48:41 | 1 | 1826 | 2.7858013 | 5.492270 |
| id2063827 | 2016-05-18 21:09:02 | 1 | 593 | 0.9220924 | 5.597863 |
| id0105610 | 2016-02-19 20:01:24 | 3 | 2065 | 19.8822987 | 34.661635 |
| id3502065 | 2016-03-15 21:03:44 | 1 | 653 | 3.0192890 | 16.645391 |
| id3508035 | 2016-06-06 20:13:56 | 6 | 1884 | 19.6120274 | 37.475212 |
| id3236276 | 2016-01-27 08:07:32 | 1 | 989 | 2.3585496 | 8.585216 |
| id3277902 | 2016-04-09 15:04:31 | 1 | 419 | 2.4578575 | 21.117630 |
| id2335059 | 2016-05-27 11:10:32 | 4 | 962 | 1.1931962 | 4.465183 |
| id2300865 | 2016-05-10 10:31:22 | 1 | 243 | 0.9847841 | 14.589394 |
| id3962434 | 2016-01-10 08:45:31 | 2 | 373 | 1.2249670 | 11.822738 |
| id2677672 | 2016-02-18 17:47:39 | 2 | 384 | 1.0471787 | 9.817300 |
| id0589360 | 2016-05-22 17:34:08 | 1 | 2753 | 14.0976148 | 18.434949 |
| id0970832 | 2016-03-12 20:39:39 | 1 | 1561 | 4.0050314 | 9.236459 |
| id0694434 | 2016-01-26 23:40:14 | 1 | 505 | 5.0538767 | 36.027636 |
| id3729136 | 2016-01-30 15:15:47 | 2 | 900 | 3.3210886 | 13.284354 |
| id2358953 | 2016-06-27 00:31:28 | 1 | 2116 | 27.1930783 | 46.264216 |
| id0935429 | 2016-05-02 06:58:06 | 1 | 611 | 2.5513063 | 15.032247 |
| id3056417 | 2016-04-11 14:18:21 | 1 | 972 | 1.0608966 | 3.929247 |
| id1152886 | 2016-01-21 14:34:06 | 1 | 604 | 1.6742156 | 9.978768 |
| id1796723 | 2016-02-09 15:54:53 | 1 | 594 | 1.6336230 | 9.900745 |
| id0045014 | 2016-04-20 20:29:42 | 1 | 574 | 2.2135527 | 13.882909 |
| id2648478 | 2016-01-18 11:13:59 | 1 | 297 | 0.9827126 | 11.911668 |
| id0702030 | 2016-01-07 23:24:44 | 1 | 101 | 0.8426892 | 30.036448 |
| id3024438 | 2016-06-10 22:24:37 | 1 | 1041 | 6.3018236 | 21.793050 |
| id2146569 | 2016-06-23 22:17:35 | 1 | 212 | 0.6150834 | 10.444813 |
| id2307151 | 2016-02-07 18:08:06 | 1 | 422 | 2.4057702 | 20.523158 |
| id2049424 | 2016-03-02 20:15:07 | 1 | 1356 | 4.2620531 | 11.315185 |
| id2209089 | 2016-02-24 22:56:43 | 1 | 416 | 0.3754779 | 3.249328 |
| id0391524 | 2016-04-06 12:14:40 | 1 | 1118 | 1.7871640 | 5.754732 |
| id2681033 | 2016-06-17 10:01:39 | 1 | 874 | 2.9176547 | 12.017800 |
| id2040275 | 2016-06-16 20:31:09 | 1 | 321 | 2.0886922 | 23.424585 |
| id0073842 | 2016-03-30 23:49:41 | 1 | 400 | 1.4262318 | 12.836087 |
| id3942339 | 2016-01-05 17:58:04 | 1 | 934 | 1.0630788 | 4.097520 |
| id2991616 | 2016-03-19 19:51:34 | 3 | 773 | 1.2728678 | 5.927974 |
| id1047459 | 2016-01-22 17:31:53 | 3 | 337 | 1.3384801 | 14.298304 |
| id1737558 | 2016-05-18 19:08:31 | 1 | 234 | 1.6680986 | 25.663055 |
| id2135557 | 2016-05-25 13:19:56 | 5 | 474 | 2.2376670 | 16.994940 |
| id0659170 | 2016-03-26 13:07:08 | 1 | 1314 | 8.1158442 | 22.235190 |
| id1125774 | 2016-01-19 22:20:43 | 2 | 482 | 2.9306606 | 21.888752 |
| id1886740 | 2016-05-29 00:15:12 | 1 | 566 | 2.8904274 | 18.384344 |
| id1982306 | 2016-02-10 21:06:14 | 2 | 189 | 0.8456475 | 16.107572 |
| id2684106 | 2016-02-26 20:59:13 | 2 | 913 | 4.5198783 | 17.822083 |
| id0038484 | 2016-03-09 13:41:11 | 2 | 736 | 0.7302157 | 3.571707 |
| id1734208 | 2016-04-11 10:44:32 | 6 | 714 | 2.8135113 | 14.185771 |
| id0561467 | 2016-02-09 06:58:53 | 1 | 815 | 3.4569512 | 15.269968 |
| id3092788 | 2016-03-03 22:01:32 | 2 | 972 | 2.2141663 | 8.200616 |
| id1741519 | 2016-03-26 14:47:44 | 1 | 318 | 1.1373488 | 12.875647 |
| id1330402 | 2016-05-22 18:06:05 | 1 | 625 | 1.9000831 | 10.944479 |
| id2505596 | 2016-05-28 22:53:12 | 1 | 859 | 2.3071740 | 9.669181 |
| id1630509 | 2016-03-16 05:42:49 | 2 | 141 | 1.5805059 | 40.353343 |
| id0512853 | 2016-05-28 17:40:21 | 1 | 983 | 4.5530033 | 16.674274 |
| id3089912 | 2016-06-13 13:22:04 | 2 | 565 | 1.3052604 | 8.316703 |
| id1137965 | 2016-05-16 15:02:10 | 1 | 351 | 1.1728137 | 12.028859 |
| id3677225 | 2016-01-09 15:07:03 | 1 | 342 | 2.4310775 | 25.590289 |
| id0401226 | 2016-05-26 06:37:10 | 4 | 909 | 5.0771370 | 20.107473 |
| id2452605 | 2016-05-22 22:42:31 | 1 | 227 | 1.4937871 | 23.690015 |
| id3618302 | 2016-04-19 09:27:04 | 6 | 1078 | 2.0954375 | 6.997751 |
| id1552358 | 2016-04-01 07:55:30 | 1 | 900 | 1.3012538 | 5.205015 |
| id1168234 | 2016-02-01 18:02:59 | 1 | 631 | 1.6676255 | 9.514187 |
| id2910320 | 2016-04-20 07:33:12 | 1 | 1385 | 8.7245507 | 22.677533 |
| id3331830 | 2016-04-12 09:21:27 | 1 | 869 | 0.9388300 | 3.889284 |
| id0195963 | 2016-06-19 18:39:05 | 1 | 574 | 1.8227089 | 11.431624 |
| id0762989 | 2016-03-17 08:24:27 | 1 | 104 | 0.5012282 | 17.350206 |
| id2671060 | 2016-04-07 08:44:32 | 1 | 418 | 1.3370995 | 11.515689 |
| id3620795 | 2016-01-01 10:45:24 | 1 | 383 | 1.7206065 | 16.172803 |
| id2282206 | 2016-01-04 16:32:42 | 2 | 1117 | 7.0100081 | 22.592685 |
| id0591292 | 2016-06-09 18:43:04 | 1 | 1447 | 2.1503952 | 5.349981 |
| id0906779 | 2016-04-19 08:31:48 | 2 | 2543 | 13.3467550 | 18.894344 |
| id2326430 | 2016-06-10 22:06:53 | 1 | 981 | 9.3224280 | 34.210745 |
| id3863815 | 2016-03-14 04:24:36 | 3 | 755 | 2.9081677 | 13.866760 |
| id3048297 | 2016-04-06 08:53:11 | 1 | 1257 | 8.6617693 | 24.806976 |
| id3649509 | 2016-04-02 14:46:23 | 2 | 1221 | 6.6600649 | 19.636555 |
| id1783063 | 2016-04-06 12:24:22 | 2 | 940 | 1.6408089 | 6.283949 |
| id3363012 | 2016-04-12 20:22:49 | 1 | 126 | 0.5623428 | 16.066938 |
| id0514638 | 2016-02-10 08:36:33 | 1 | 350 | 0.9333386 | 9.600054 |
| id0627115 | 2016-02-26 16:10:47 | 1 | 737 | 1.8627681 | 9.099003 |
| id3141299 | 2016-01-14 12:25:54 | 3 | 690 | 2.4367191 | 12.713317 |
| id2003497 | 2016-04-15 11:58:45 | 2 | 671 | 1.4361068 | 7.704895 |
| id3748197 | 2016-02-07 23:17:58 | 1 | 463 | 1.5895422 | 12.359291 |
| id2983261 | 2016-04-15 14:41:14 | 1 | 367 | 1.2496724 | 12.258366 |
| id0485870 | 2016-06-19 20:23:09 | 1 | 369 | 1.8431997 | 17.982436 |
| id0835694 | 2016-01-15 19:25:12 | 1 | 402 | 1.2725104 | 11.395615 |
| id3426410 | 2016-02-18 09:27:07 | 5 | 1093 | 7.4755112 | 24.621995 |
| id3673678 | 2016-01-31 13:52:55 | 1 | 657 | 2.8091250 | 15.392466 |
| id2460349 | 2016-01-07 15:40:34 | 2 | 530 | 1.3070416 | 8.878018 |
| id3198639 | 2016-06-05 03:02:46 | 1 | 733 | 5.7066598 | 28.027251 |
| id1872601 | 2016-05-31 19:16:05 | 2 | 699 | 1.9798782 | 10.196797 |
| id0125957 | 2016-06-14 21:16:43 | 2 | 294 | 2.2355509 | 27.374093 |
| id3526986 | 2016-02-23 13:28:59 | 1 | 661 | 1.7885431 | 9.740931 |
| id3170873 | 2016-06-30 21:35:27 | 1 | 652 | 1.7513807 | 9.670200 |
| id1674373 | 2016-02-15 17:52:27 | 5 | 586 | 4.0856460 | 25.099532 |
| id2973697 | 2016-04-07 22:52:23 | 2 | 1057 | 3.5051393 | 11.938033 |
| id1592044 | 2016-01-29 11:23:23 | 1 | 580 | 1.3787249 | 8.557603 |
| id3899813 | 2016-06-01 20:15:24 | 5 | 1151 | 1.9775453 | 6.185198 |
| id2075052 | 2016-04-09 09:09:03 | 1 | 660 | 5.8328532 | 31.815563 |
| id3707411 | 2016-01-03 02:03:39 | 1 | 803 | 2.0772423 | 9.312668 |
| id1608545 | 2016-04-14 08:31:03 | 1 | 1954 | 4.0634195 | 7.486341 |
| id3517425 | 2016-01-16 20:34:06 | 6 | 1030 | 3.4764426 | 12.150673 |
| id3942917 | 2016-04-29 14:18:39 | 4 | 2817 | 10.6540829 | 13.615441 |
| id2000923 | 2016-03-29 06:07:38 | 5 | 85 | 0.8382142 | 35.500839 |
# Resumo estatístico das variáveis principais
resumo <- dados %>%
summarise(
trip_duration_min = min(trip_duration, na.rm = TRUE),
trip_duration_1Q = quantile(trip_duration, 0.25, na.rm = TRUE),
trip_duration_median = median(trip_duration, na.rm = TRUE),
trip_duration_mean = mean(trip_duration, na.rm = TRUE),
trip_duration_3Q = quantile(trip_duration, 0.75, na.rm = TRUE),
trip_duration_max = max(trip_duration, na.rm = TRUE),
distance_min = min(distance_km, na.rm = TRUE),
distance_1Q = quantile(distance_km, 0.25, na.rm = TRUE),
distance_median = median(distance_km, na.rm = TRUE),
distance_mean = mean(distance_km, na.rm = TRUE),
distance_3Q = quantile(distance_km, 0.75, na.rm = TRUE),
distance_max = max(distance_km, na.rm = TRUE),
speed_min = min(speed_kmph, na.rm = TRUE),
speed_1Q = quantile(speed_kmph, 0.25, na.rm = TRUE),
speed_median = median(speed_kmph, na.rm = TRUE),
speed_mean = mean(speed_kmph, na.rm = TRUE),
speed_3Q = quantile(speed_kmph, 0.75, na.rm = TRUE),
speed_max = max(speed_kmph, na.rm = TRUE)
)
resumo_tabela <- data.frame(
Variável = c("trip_duration (s)", "distance_km", "speed_kmph"),
Mínimo = c(resumo$trip_duration_min, resumo$distance_min, resumo$speed_min),
`1º Quartil` = c(resumo$trip_duration_1Q, resumo$distance_1Q, resumo$speed_1Q),
Mediana = c(resumo$trip_duration_median, resumo$distance_median, resumo$speed_median),
Média = c(resumo$trip_duration_mean, resumo$distance_mean, resumo$speed_mean),
`3º Quartil` = c(resumo$trip_duration_3Q, resumo$distance_3Q, resumo$speed_3Q),
Máximo = c(resumo$trip_duration_max, resumo$distance_max, resumo$speed_max)
)
kable(resumo_tabela, caption = "Tabela resumo das variáveis principais") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"))
| Variável | Mínimo | X1º.Quartil | Mediana | Média | X3º.Quartil | Máximo |
|---|---|---|---|---|---|---|
| trip_duration (s) | 1 | 397.000000 | 662.000000 | 959.492273 | 1075.000000 | 3526282.000 |
| distance_km | 0 | 1.233216 | 2.096063 | 3.444719 | 3.879679 | 1242.299 |
| speed_kmph | 0 | 9.131493 | 12.806309 | 14.439366 | 17.864903 | 9285.227 |
A análise exploratória teve início com a inspeção da variável
passenger_count, que indica o número de passageiros em cada
corrida registrada. A distribuição dessa variável pode revelar padrões
importantes sobre o tipo de serviço prestado (ex.: viagens individuais
ou compartilhadas).
# Carregar pacotes
library(ggplot2)
# Gráfico de barras com a contagem de passageiros
ggplot(dados, aes(x = factor(passenger_count))) +
geom_bar(fill = "#0073C2FF") +
labs(
title = "Distribuição da quantidade de passageiros por corrida",
x = "Quantidade de passageiros",
y = "Frequência"
) +
theme_minimal()
A visualização revela a frequência de corridas com diferentes quantidades de passageiros. É possível observar, por exemplo, se há predominância de viagens individuais ou em grupo, o que pode influenciar a duração e o trajeto das corridas.
focamos na variável trip_duration, que representa a duração de cada corrida em segundos. A distribuição dessa variável foi visualizada para identificar padrões de duração típicos, além de detectar possíveis valores extremos ou inconsistências nos dados. Para isso, foi criado um histograma com binagem de 60 segundos, restringindo a visualização até o percentil 99 para minimizar o impacto de valores extremos.
ggplot(dados, aes(x = trip_duration)) +
geom_histogram(binwidth = 60, fill = "#404080", color = "white") +
xlim(0, quantile(dados$trip_duration, 0.99)) + # remover extremos
labs(
title = "Distribuição da duração das corridas",
x = "Duração (segundos)",
y = "Frequência"
) +
theme_minimal()
Para entender o padrão temporal das corridas, foi extraída a hora do dia a partir da variável pickup_datetime, que registra o momento de início de cada corrida. A nova variável horario representa a hora em formato numérico (0 a 23), facilitando a análise da distribuição das corridas ao longo do dia.
O histograma resultante, com binagem de 1 hora, mostra a frequência de corridas por cada hora do dia, permitindo identificar os períodos de maior e menor demanda.
dados <- dados %>% mutate(horario = hour(hms(substr(pickup_datetime, 12, 19))))
ggplot(dados, aes(x = horario)) +
geom_histogram(binwidth = 1, fill = "#ffa600", color = "black") +
labs(
title = "Distribuição de corridas por horário de início",
x = "Hora do dia",
y = "Número de corridas"
) +
theme_minimal()
Para identificar as regiões com maior concentração de embarques na
cidade de Nova York, foi criado um mapa de calor com base nas
coordenadas geográficas de início das corridas
(pickup_longitude e pickup_latitude). A
visualização utiliza dados do OpenStreetMap para compor um mapa da
cidade com ruas principais e bairros, sobre o qual é sobreposta uma
estimativa de densidade bidimensional. Dessa forma, é possível
identificar visualmente os principais polos de demanda por corridas na
cidade.
# Carregar pacotes
library(ggplot2)
library(sf)
library(osmdata)
library(viridis)
# 1. Filtrar dados para área de interesse (NYC)
dados_filtrados <- subset(dados,
pickup_longitude > -74.3 & pickup_longitude < -73.7 &
pickup_latitude > 40.5 & pickup_latitude < 40.95)
# 2. Definir bounding box da cidade de Nova York
bbox_nyc <- c(-74.3, 40.5, -73.7, 40.95) # xmin, ymin, xmax, ymax
# 3. Baixar ruas principais (motorways, primary, secondary etc.)
ruas <- opq(bbox = bbox_nyc) %>%
add_osm_feature(key = "highway",
value = c("motorway", "primary", "secondary", "tertiary")) %>%
osmdata_sf()
# 4. Baixar limites dos bairros (administração local)
bairros <- opq(bbox = bbox_nyc) %>%
add_osm_feature(key = "admin_level", value = "10") %>%
add_osm_feature(key = "boundary", value = "administrative") %>%
osmdata_sf()
# 5. Plotar mapa de calor sobre camadas reais
ggplot() +
# Camada dos bairros
geom_sf(data = bairros$osm_multipolygons, fill = "gray95", color = "gray60", size = 0.3, alpha = 0.4) +
# Camada de ruas
geom_sf(data = ruas$osm_lines, color = "gray50", size = 0.2, alpha = 0.5) +
# Mapa de calor
stat_density2d(
data = dados_filtrados,
aes(x = pickup_longitude, y = pickup_latitude, fill = ..level.., alpha = ..level..),
geom = "polygon",
bins = 30
) +
scale_fill_viridis(option = "inferno") +
scale_alpha(range = c(0.3, 0.7), guide = FALSE) +
coord_sf(xlim = c(-74.3, -73.7), ylim = c(40.5, 40.95), expand = FALSE) +
labs(
title = "Mapa de Calor dos Locais de Embarque - NYC",
x = "Longitude",
y = "Latitude",
fill = "Densidade"
) +
theme_minimal()
A seguir, apresentamos algumas descobertas extraídas da base de dados, utilizando diferentes formas de visualização, como gráficos e tabelas. Essa abordagem facilita a interpretação dos padrões de comportamento no serviço de transporte, permitindo a identificação de tendências temporais e geográficas.
Este gráfico mostra o volume de embarques ao longo das 24 horas do dia, indicando os períodos de maior atividade.
library(ggplot2)
library(dplyr)
library(lubridate)
dados %>%
mutate(hora = hour(pickup_datetime)) %>%
count(hora) %>%
ggplot(aes(x = hora, y = n)) +
geom_col(fill = "#440154ff") +
labs(
title = "Número de Corridas por Hora do Dia",
x = "Hora do Dia",
y = "Quantidade de Corridas"
) +
theme_minimal()
Visualização da frequência de embarques ao longo dos dias da semana.
dados %>%
mutate(dia_semana = wday(pickup_datetime, label = TRUE, abbr = FALSE)) %>%
count(dia_semana) %>%
ggplot(aes(x = dia_semana, y = n)) +
geom_line(group = 1, color = "#21908dff", size = 1.2) +
geom_point(size = 3, color = "#21908dff") +
labs(
title = "Corridas por Dia da Semana",
x = "Dia da Semana",
y = "Total de Corridas"
) +
theme_minimal()
Visualização da frequência de embarques ao longo dos dias da semana.
dados %>%
mutate(data = as.Date(pickup_datetime)) %>%
count(data, sort = TRUE) %>%
top_n(5, n) %>%
knitr::kable(
caption = "Top 5 Dias com Maior Número de Corridas",
col.names = c("Data", "Número de Corridas")
)
| Data | Número de Corridas |
|---|---|
| 2016-04-09 | 9796 |
| 2016-04-16 | 9602 |
| 2016-03-05 | 9597 |
| 2016-04-02 | 9325 |
| 2016-02-13 | 9309 |
A qualidade de um gráfico está diretamente ligada à sua capacidade de comunicar de forma clara e objetiva o ponto central da análise. Nesta seção, apresentamos um gráfico ajustado cuidadosamente para destacar um padrão importante nos dados: a variação do número de corridas ao longo dos dias da semana.
Para isso, foram aplicadas boas práticas de visualização de dados: escolha apropriada do tipo de gráfico, escalas informativas, títulos e legendas claros, e paleta de cores que favorece a leitura.
library(dplyr)
library(ggplot2)
library(lubridate)
# Agregação por dia da semana
corridas_dia <- dados %>%
mutate(dia_semana = wday(pickup_datetime, label = TRUE, abbr = FALSE, week_start = 1)) %>%
count(dia_semana)
# Gráfico com formatação refinada
ggplot(corridas_dia, aes(x = dia_semana, y = n)) +
geom_col(fill = "#3B9AB2", width = 0.7) +
geom_text(aes(label = n), vjust = -0.3, size = 3.5) +
labs(
title = "Distribuição de Corridas por Dia da Semana",
subtitle = "Volume total de embarques em cada dia",
x = "Dia da Semana",
y = "Número de Corridas"
) +
scale_y_continuous(labels = scales::comma) +
theme_minimal(base_size = 12) +
theme(
plot.title = element_text(face = "bold", size = 14),
plot.subtitle = element_text(size = 11, color = "gray30"),
axis.title = element_text(face = "bold"),
axis.text.x = element_text(angle = 45, hjust = 1)
)
Tabelas bem estruturadas são ferramentas essenciais para a análise e apresentação de dados, pois permitem comparações rápidas e claras entre diferentes variáveis e categorias. A escolha cuidadosa do formato, da ordenação e do destaque visual contribui para que as informações relevantes sejam facilmente identificadas pelo leitor.
Nesta seção, apresentamos um exemplo de tabela construída com atenção ao tamanho, alinhamento e formatação dos dados para facilitar a compreensão e a comparação.
library(dplyr)
library(knitr)
library(kableExtra)
# Remover linhas com coordenadas faltantes
dados_geo <- dados %>%
filter(!is.na(dropoff_longitude), !is.na(dropoff_latitude))
# Aplicar k-means para agrupar regiões aproximadas (simulando bairros)
set.seed(42)
kmeans_result <- kmeans(dados_geo[, c("dropoff_longitude", "dropoff_latitude")], centers = 5)
# Adicionar coluna com "zona aproximada"
dados_geo <- dados_geo %>%
mutate(zona_aproximada = paste("Zona", kmeans_result$cluster))
# Contar corridas por zona
corridas_zona <- dados_geo %>%
count(zona_aproximada) %>%
arrange(desc(n)) %>%
rename(`Zona Aproximada` = zona_aproximada, `Número de Corridas` = n)
# Construir a tabela com formatação
corridas_zona %>%
kable(format = "html",
digits = 0,
caption = "Número de Corridas por Zona Aproximada (K-means)") %>%
kable_styling(full_width = FALSE,
position = "left",
bootstrap_options = c("striped", "hover", "condensed")) %>%
column_spec(2, bold = TRUE, color = "blue") %>%
scroll_box(height = "300px")
| Zona Aproximada | Número de Corridas |
|---|---|
| Zona 2 | 676241 |
| Zona 1 | 406125 |
| Zona 4 | 283059 |
| Zona 5 | 52387 |
| Zona 3 | 40832 |
Esta tabela mostra estatísticas básicas para a variável de distância das corridas, facilitando a análise rápida da distribuição e variação dos dados.
library(dplyr)
library(tidyr)
library(knitr)
library(kableExtra)
# Selecionar variáveis numéricas disponíveis
resumo <- dados %>%
select(trip_duration, passenger_count) %>%
summarise(
`Mínimo` = sapply(., min, na.rm = TRUE),
`Máximo` = sapply(., max, na.rm = TRUE),
`Média` = sapply(., mean, na.rm = TRUE),
`Desvio Padrão` = sapply(., sd, na.rm = TRUE)
) %>%
pivot_longer(cols = everything(), names_to = "Estatística", values_to = "Valor") %>%
separate(Estatística, into = c("Variável", "Medida"), sep = "\\.") %>%
pivot_wider(names_from = Medida, values_from = Valor)
# Tabela formatada
resumo %>%
kable("html", digits = 2, caption = "Resumo Estatístico das Variáveis Numéricas") %>%
kable_styling(full_width = FALSE, position = "left", bootstrap_options = c("striped", "hover"))
| Variável | NA |
|---|---|
| Mínimo | 1, 0 |
| Máximo | 3526282, 9 |
| Média | 959.49227, 1.66453 |
| Desvio Padrão | 5237.431724, 1.314242 |
Aqui apresentamos a porcentagem que cada bairro representa do total de corridas, com barras de progresso para visualização rápida da proporção.
library(dplyr)
library(formattable)
# Filtrar apenas linhas com coordenadas de destino válidas
dados_geo <- dados %>%
filter(!is.na(dropoff_longitude), !is.na(dropoff_latitude))
# Agrupamento por zona geográfica (k-means com 5 zonas)
set.seed(42)
kmeans_result <- kmeans(dados_geo[, c("dropoff_longitude", "dropoff_latitude")], centers = 5)
# Adicionar zona ao dataframe
dados_geo <- dados_geo %>%
mutate(zona_aproximada = paste("Zona", kmeans_result$cluster))
# Calcular número de corridas e percentual por zona
corridas_zona_pct <- dados_geo %>%
count(zona_aproximada) %>%
mutate(Percentual = n / sum(n) * 100) %>%
arrange(desc(Percentual)) %>%
rename(`Zona Aproximada` = zona_aproximada,
`Número de Corridas` = n)
# Tabela formatada com barra de preenchimento visual
formattable(corridas_zona_pct, list(
Percentual = color_bar("#3B9AB2")
))
| Zona Aproximada | Número de Corridas | Percentual |
|---|---|---|
| Zona 2 | 676241 | 46.360935 |
| Zona 1 | 406125 | 27.842640 |
| Zona 4 | 283059 | 19.405626 |
| Zona 5 | 52387 | 3.591486 |
| Zona 3 | 40832 | 2.799312 |
A seguir, apresentamos os principais insights extraídos da análise exploratória, de forma clara e objetiva, para facilitar a compreensão dos padrões relevantes nos dados:
A variável passenger_count revelou que a maioria das
corridas foi realizada com apenas um passageiro. Isso indica um perfil
de uso majoritariamente individual do serviço, possivelmente por
moradores ou trabalhadores em deslocamento.
A análise da variável trip_duration, após remoção de
valores extremos, mostrou que grande parte das corridas ocorre em menos
de 1.000 segundos (cerca de 17 minutos). Isso sugere um uso do serviço
principalmente para deslocamentos curtos dentro da cidade.
O volume de corridas aumenta consideravelmente entre 7h e 9h e entre 17h e 19h. Esses picos coincidem com os horários típicos de entrada e saída do trabalho, o que reforça a hipótese de que o serviço é amplamente utilizado como alternativa de transporte urbano diário.
A distribuição semanal das corridas revela um crescimento progressivo ao longo da semana, com pico às sextas-feiras. Isso pode estar relacionado à maior mobilidade no final da semana, seja por motivos profissionais ou sociais.
O mapa de calor evidenciou uma alta densidade de embarques em regiões centrais de Nova York, como Manhattan. Isso reflete tanto a concentração de atividades econômicas quanto a presença de pontos turísticos e conexões de transporte público.
O agrupamento por k-means das coordenadas de destino identificou zonas aproximadas de desembarque, permitindo classificar os bairros com maior volume de corridas. Essas zonas podem ser usadas em análises futuras para políticas de mobilidade ou estratégias de operação.
As tabelas descritivas e as visualizações temporais e geográficas permitiram detectar padrões consistentes no comportamento das corridas. Em especial, os gráficos ajustados destacaram tendências sazonais e geográficas relevantes para interpretação dos dados.
O objetivo central desta análise foi entender quais são os piores horários e regiões para conseguir um táxi na cidade de Nova York, com base em dados reais de corridas realizadas. Essa questão é especialmente relevante em contextos urbanos onde a demanda por transporte varia significativamente ao longo do tempo e do espaço.
Para responder à pergunta proposta, utilizamos um conjunto de dados públicos contendo informações detalhadas sobre corridas de táxi em Nova York. Os dados incluíam variáveis como horário de embarque, duração da viagem, número de passageiros e coordenadas geográficas.
A metodologia envolveu:
plotly, facilitando a exploração dos padrões
encontrados.A análise revelou diversos padrões interessantes:
Para usuários do serviço de táxi (e apps de mobilidade), a análise sugere que:
Além disso, empresas de táxi e prefeituras podem usar esses dados para otimizar alocação de frotas ou implementar políticas públicas de mobilidade urbana.
Apesar dos resultados úteis, a análise possui limitações:
Futuros aprimoramentos podem incluir:
O código foi desenvolvido seguindo boas práticas de estilo em R, com:
#),
facilitando a navegação;Essas práticas tornam o código mais legível, reprodutível e fácil de manter.
Problemas mais complexos foram divididos em subproblemas resolvíveis, como:
O código priorizou eficiência e simplicidade, fazendo uso de estruturas apropriadas:
data.frame e tibble para manipulação
tabular;vector e factor para colunas
categóricas;dplyr para processamento
eficiente;ggplot2 e plotly para visualizações com
propósito claro.A aplicação das técnicas do curso foi feita com competência e organização, incluindo:
ggplot2;plotly, melhorando a
exploração dos dados;Além disso, a análise foi conduzida de forma criativa e exploratória, indo além da simples visualização, ao identificar padrões relevantes de comportamento urbano.
O trabalho foi além do esperado ao utilizar:
plotly,
recurso não exigido no curso;Esses elementos demonstram domínio técnico e capacidade analítica aplicada a um problema real com potencial prático.