La alta accidentalidad en la ciudad de Medellín, se ha convertido en un problema de salud pública, por esta razón, las entidades gubernamentales y el cuerpo de tránsito, requieren de campañas y metodologías fuertes con el fin de atacar dicha problemática. El objetivo principal de este trabajo, es realizar un aporte a dichas entidades gubernamentales, con el fin de atacar este problema social y de salud pública, donde tuvimos como base, los datos proporcionados por el portal MEData: MeData la cual, es una estrategia de datos de la ciudad de Medellín, que busca la apropiación, apertura y uso de los datos como herramienta de gobierno, de allí, se utilizó como ingrediente, la base de datos de incidentes viales en la ciudad de Medellín entre los años 2014 y 2021.
claro esta, que la estadística es una herramienta de suma importancia para la toma de decisiones y análisis que pueden contribuir a la solución de problemas actuales, por esta razón, este campo ha tomado un importante auge en la sociedad, las empresas requieren más estadísticos para realizar este tipo de tareas, elaboración, manejo y análisis de bases de datos. El objetivo de este trabajo es utilizar la Estadística y el desarrollo computacional para analizar los datos de incidentes georreferenciados de 2014 a 2021 de la ciudad de Medellín para predecir accidentes del año 2020 y 2021 con el fin de descubrir factores que se relacionan con los accidentes y aportar de forma significativa a las entidades públicas a tomar decisiones en temas de seguridad vial.
En el enlace se encuentra alojado el aplicativo web AccApp que permite visualizar la accidentalidad y pronosticar Enlace: Aplicacion web AccApp
En el enlace se encuentra alojado el Github principal que contiene todos los archivos y scripts utilizados para la construcción e implementación de este trabajo Enlace: Github principal
En el enlace se encuentra el video promocional de la aplicación AccApp que permite visualizar la accidentalidad y pronosticar Enlace: Video Promocional AccApp
Para la realización de este informe, se dispuso de una base de datos de incidentes viales en la ciudad de Medellín, entre los años 2014 y 2021, que se utilizaron como insumo principal para su respectivo análisis, con el fin de aplicar modelos predictivos y contribuir a la toma de decisiones.
La Alcaldía de Medellín en el portal GeoMedellín suministra las bases de datos anuales para incidentes de tránsito registrados por la Secretaria de Movilidad. Los datos se encuentran en MEData: MeData. Para el entendimiento del conjunto de datos se define el accidente de transito como: “evento, generalmente involuntario, generado al menos por un vehiculo en movimiento, que causa daños a personas y bienes involucrados en él que igualmente afecta la normal circulación de los vehiculos que se movilizan por la via o vias comprendidas en el lugar o dentro de la zona de influencia del hecho”
Las variables que se tienen en cuenta para el estudio son las siguientes:
| Variable | Descripción | Tipo | Detalle |
|---|---|---|---|
| X | Coordenada X (longitud) de la ubicación del accidente | float | - |
| Y | Coordenada Y (latitud) de la ubicación del accidente) | float | - |
| OBJECTID | Identificación del registro | integer | - |
| RADICADO | Identificación única del accidente ante la Secretaría de Movilidad | string | - |
| FECHA | Fecha de la ocurrencia del accidente | string | - |
| HORA | Hora aproximada del accidente | datetime | - |
| DIA | Número día dentro del mes del accidente | integer | - |
| PERIODO | Año de la ocurrencia del accidente | integer | - |
| CLASE | Tipo de accidente | String | Clases: atropello, caída del ocupante, choque, incendio, volcamiento, otro |
| DIRECCION | Dirección detallada de la ubicación del accidente | String | - |
| DIRECCION_ENC | Dirección encasillada de la ubicación del accidente | string | Formato único de direcciones de la Alcaldía de Medellín |
| CBML | Identificación única del lote más cercano a la ubicación del accidente | string | Acrónimo de comuna, barrio, manzana, lote |
| TIPO_GEOCOD | Tipo de ubicación catastral | string | Formato de la oficina de catastro de la Alcaldía de Medellín |
| GRAVEDAD | Gravedad del accidente | string | Clases: herido, muerto, solo daños |
| BARRIO | Barrio donde ocurrió el accidente | string | 340 niveles dentro de la variable |
| COMUNA | Comuna donde ocurrió el accidente | string | 85 niveles dentro de la variable |
| DISENO | Tipo de diseño en donde ocurrió el accidente | string | Clases: ciclo ruta, glorieta, intersección, lote o predio, paso a nivel, paso elevado, paso inferior, pontón, puente, tramo de vía, túnel, vía peatonal |
| DIA_NOMBRE | Nombre del día de la semana del accidente | string | - |
| MES | Número de mes dentro del año del accidente | integer | - |
| MES_NOMBRE | Nombre del mes del accidente | string | - |
| X_MAGNAMED | - | - | - |
| Y_MAGNAMED | - | - | - |
| LONGITUD | Coordenada longitud de la ubicación del accidente | float | - |
| LATITUD | Coordenada latitud de la ubicación del accidente | float | - |
El conjunto de datos fue tratado y previamente depurado, ya que había presencia de datos vacíos y otras anomalías que afectaban el análisis, para esto, utilizamos librerías de R como Tidyverse para tratar la base.
Se crean nuevas variables para analizar de forma óptima los datos, en un ambiente más específico.
Cabe resaltar, que para la obtención de la base de datos final, se realizó un procedimiento de depuración y manejo de datos detalladamente, el cual esta especificado en el archivo ManejoDatos.Rmd ubicado en el repositorio de Github, de forma resumida, se realizaron los siguientes procesos:
library(data.table);library(purrr);library(dplyr)
library(plotly);library(tidyr);library(stringr)
library(lubridate);library(sf);library(knitr);library(kableExtra)
medellin <- read.csv("incidentes_viales.csv", dec=",", header=T,sep=";", encoding = "UTF-8")
# Registros por día
medellin_dia <- medellin %>% group_by(DIA_SEMANA) %>% dplyr::summarize(total_accidentes = n())
# Ordenar de Lunes a Domingo
medellin_dia$DIA_SEMANA <- ordered(medellin_dia$DIA_SEMANA,
levels = c("LUNES","MARTES","MIERCOLES","JUEVES","VIERNES",
"SABADO","DOMINGO"))
grafico_1 <- ggplot(data = medellin_dia, aes(x = DIA_SEMANA, y = total_accidentes)) +
geom_bar(stat = "identity", alpha = 0.65, fill = "grey20", color = "black") +
geom_text(aes(y = total_accidentes, label = total_accidentes),
position = position_dodge(width = 0.8), size = 2.8, vjust = 0.5, hjust = -0.1, col = "gray10") +
xlab("Días") +
ylab("Total Accidentes") +
ggtitle("Total Accidentes por día de la semana") +
theme_minimal() +
ylim(c(0,40000)) +
coord_flip()library(dummies)
library(stringr)
library(readxl)
library(sf)
library(dplyr)
library(lubridate)
library(ggplot2)
library(GGally)
library(car)
library(MLmetrics)
library(wordcloud)
library(gplots)
library(R.utils)
library(tm)
library(DescTools)
library(raster)
library(mclust)
library(rgdal)
library(raster)
library(geosphere)
library(NbClust)
library(factoextra)
library(vegan)
library(qpcR)
library(leaflet)#Lectura de la Base de datos con la cual se trabajará en este proyecto
base_final <- read.csv("accident_final.csv", encoding="UTF-8")Según el enunciado, tendremos en cuenta los años 2014 hasta 2017 para realizar entrenamiento y para validación los años 2018 y 2019
#Modelo lineal
base_final$CLASE <- as.factor(as.character(base_final$CLASE))
datos_vl <- subset(base_final, (AÑO == '2018'))
base_final01 <- subset(base_final, (AÑO != '2018'))
base_final02 <- subset(base_final01, (AÑO != '2019'))
base_final03 <- subset(base_final02, (AÑO != '2020'))
datos_ml1 <- base_final03 %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
DISENO) %>% dplyr::count(name ="NRO_ACCID")
ml1 <- lm(NRO_ACCID ~ FESTIVIDAD+DIA_SEMANA+DISENO, data = datos_ml1)
promedio <- mean(datos_ml1$NRO_ACCID)
TSS <- sum((datos_ml1$NRO_ACCID - promedio)^2)
RSS <- RSS(ml1)
r2 <- 1-RSS/TSS
RSS2 <- anova(ml1)[4, 2]
r2 <- 1-RSS/TSSAquí podemos observar el MSE y el R^2, con el fin de determinar la potencia de dicho modelo.
ml1_data <- base_final03 %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
DISENO) %>% dplyr::count(name = "NRO_ACCID")
ml1_tr <- ml1_data[,-c(5)]
predicted <- round(predict(ml1, newdata=ml1_tr))
actual <- ml1_data$NRO_ACCID
ml1_mse <- MSE(predicted, actual) # MSE
ml1_mae <- MAE(predicted, actual) # MAE
ml1_r2 <- R2_Score(predicted, actual) # R2
sprintf("MSE: %f, MAE: %f, R2: %f", ml1_mse, ml1_mae, ml1_r2)## [1] "MSE: 116.151546, MAE: 5.882622, R2: 0.896806"
ml1_2018 <- datos_vl %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
DISENO) %>% dplyr::count(name = "NRO_ACCID")
predicted <- round(predict(ml1, newdata=ml1_2018))
actual <- ml1_2018$NRO_ACCID
lm1_mse <- MSE(predicted, actual) # MSE
lm1_mae <- MAE(predicted, actual) # MAE
lm1_r2 <- R2_Score(predicted, actual) # R2
sprintf("MSE: %f, MAE: %f, R2: %f", lm1_mse, lm1_mae, lm1_r2)## [1] "MSE: 150.632552, MAE: 6.739856, R2: 0.728641"
En primera instancia, podemos observar que el \(R^2\) de los datos de validación para el año 2018, predice en un 72.86% y los datos de validación y entrenamiento del año 2018 tienen una variación en cuanto al MSE del 34.4%
datos_vl02 <- subset(base_final, (AÑO == '2019'))
ml1_2019 <- datos_vl02 %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
DISENO) %>% dplyr::count(name = "NRO_ACCID")
predicted <- round(predict(ml1, newdata=ml1_2019))
actual <- ml1_2019$NRO_ACCID
ml1_mse <- MSE(predicted, actual) # MSE
ml1_mae <- MAE(predicted, actual) # MAE
ml1_r2 <- R2_Score(predicted, actual) # R2
sprintf("MSE: %f, MAE: %f, R2: %f", ml1_mse, ml1_mae, ml1_r2)## [1] "MSE: 157.439013, MAE: 7.161181, R2: 0.765329"
Según el \(R^2\) obtenido, con este modelo, para el año 2019 se predice en un 76.53%
Teniendo en cuenta solo las variables FESTIVIDAD y DIA_SEMANA
datos_ml2 <- base_final03 %>% group_by(FECHA,FESTIVIDAD, DIA_SEMANA) %>%
dplyr::count(name = "NRO_ACCID")
lm2 <- lm(NRO_ACCID ~ FESTIVIDAD+DIA_SEMANA, data = datos_ml2)lm2_tr <- base_final03 %>% group_by(FECHA,FESTIVIDAD, DIA_SEMANA) %>%
dplyr::count(name = "NRO_ACCID")
predicted <- round(predict(lm2, newdata=lm2_tr))
actual <- lm2_tr$NRO_ACCID
lm2_mse <- MSE(predicted, actual) # MSE
lm2_mae <- MAE(predicted, actual) # MAE
lm2_r2 <- R2_Score(predicted, actual) # R2
sprintf("MSE: %f, MAE: %f, R2: %f", lm2_mse, lm2_mae, lm2_r2)## [1] "MSE: 687.801563, MAE: 20.398438, R2: 0.071931"
lm2_2018 <- datos_vl %>% group_by(FECHA,FESTIVIDAD, DIA_SEMANA) %>%
dplyr::count(name = "NRO_ACCID")
predicted <- round(predict(lm2, newdata=lm2_2018))
actual <- lm2_2018$NRO_ACCID
lm2_mse <- MSE(predicted, actual) # MSE
lm2_mae <- MAE(predicted, actual) # MAE
lm2_r2 <- R2_Score(predicted, actual) # R2
sprintf("MSE: %f, MAE: %f, R2: %f", lm2_mse, lm2_mae, lm2_r2)## [1] "MSE: 629.906849, MAE: 18.904110, R2: 0.028546"
Se evidencia claramente, que se predice un porcentaje muy bajo con dicho modelo, únicamente se explica el 2.85% de los datos
lm2_2019 <- datos_vl02 %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA) %>%
dplyr::count(name = "NRO_ACCID")
predicted <- round(predict(lm2, newdata=lm2_2019))
actual <- lm2_2019$NRO_ACCID
lm2_mse <- MSE(predicted, actual) # MSE
lm2_mae <- MAE(predicted, actual) # MAE
lm2_r2 <- R2_Score(predicted, actual) # R2
sprintf("MSE: %f, MAE: %f, R2: %f", lm2_mse, lm2_mae, lm2_r2)## [1] "MSE: 778.819178, MAE: 22.430137, R2: 0.100687"
Para el año 2019 se predice en un 10%, porcentaje muy bajo, por lo cual, los resultados no fueron los esperados
datos_lm3 <- base_final03 %>% group_by(FECHA,FESTIVIDAD, DIA_SEMANA) %>%
dplyr::count(name = "NRO_ACCID")
lm3 <- glm(NRO_ACCID ~ FESTIVIDAD+DIA_SEMANA, family = "poisson", data = datos_lm3) lm3_tr <- base_final03 %>% group_by(FECHA,FESTIVIDAD, DIA_SEMANA) %>%
dplyr::count(name = "NRO_ACCID")
lm3_tr_1 <- lm3_tr[,-4]
predicted <- round(predict(lm3, newdata=lm3_tr_1, type="response"))
actual <- lm3_tr$NRO_ACCID
lm3_mse <- MSE(predicted, actual) # MSE
lm3_mae <- MAE(predicted, actual) # MAE
lm3_r2 <- R2_Score(predicted, actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f", lm3_mse, lm3_mae, lm3_r2)## [1] "MSE: 687.635937, MAE: 20.395312, R2 Score: 0.072154"
lm3_2018 <- datos_vl %>% group_by(FECHA,FESTIVIDAD, DIA_SEMANA) %>%
dplyr::count(name = "NRO_ACCID")
predicted <- round(predict(lm3, newdata=lm3_2018, type="response"))
actual <- lm3_2018$NRO_ACCID
lm3_mse <- MSE(predicted, actual) # MSE
lm3_mae <- MAE(predicted, actual) # MAE
lm3_r2 <- R2_Score(predicted, actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f", lm3_mse, lm3_mae, lm3_r2)## [1] "MSE: 629.742466, MAE: 18.898630, R2 Score: 0.028800"
En la etapa de entrenamiento, se obtiene un \(R^2\) de 7% y para la etapa de validación de 2.88%, lo cual indica que el modelo tiene una potencia muy baja, por lo que no se recomienda para el uso de predicciones.
lm3_2019 <- datos_vl02 %>% group_by(FECHA,FESTIVIDAD, DIA_SEMANA) %>%
dplyr::count(name = "NRO_ACCID")
predicted <- round(predict(lm3, newdata=lm3_2019, type="response"))
actual <- lm3_2019$NRO_ACCID
lm3_mse <- MSE(predicted, actual) # MSE
lm3_mae <- MAE(predicted, actual) # MAE
lm3_r2 <- R2_Score(predicted, actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f", lm3_mse, lm3_mae, lm3_r2)## [1] "MSE: 778.545205, MAE: 22.419178, R2 Score: 0.101004"
Según el \(R^2\) obtenido, claramente debemos adicionar otra variable, ya que la potencia fue muy baja
datos_lm4 <- base_final03 %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
CLASE) %>% dplyr::count(name = "NRO_ACCID")
lm4 <- glm(NRO_ACCID ~ FESTIVIDAD+DIA_SEMANA+CLASE, family = "poisson",
data = datos_lm4)datos_lm4_p <- datos_lm4[,-5]
y_train <- round(predict(lm4, newdata= datos_lm4_p, type="response"))
y_actual <- datos_lm4$NRO_ACCID
lm4_tmse <- MSE(y_train, y_actual)
lm4_tmae <- MAE(y_train, y_actual)
lm4_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f",
lm4_tmse, lm4_tmae, lm4_r2)## [1] "MSE: 98.608264, MAE: 5.762025, R2 Score: 0.886066"
datos_lm4_v1 <- datos_vl %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
CLASE) %>% dplyr::count(name = "NRO_ACCID")
datos_lm4_v2 <- datos_lm4_v1[,-5]
y_train <- round(predict(lm4, newdata= datos_lm4_v2, type="response"))
y_actual <- datos_lm4_v1$NRO_ACCID
lm4_tmse <- MSE(y_train, y_actual)
lm4_tmae <- MAE(y_train, y_actual)
lm4_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f", lm4_tmse, lm4_tmae, lm4_r2)## [1] "MSE: 88.650194, MAE: 5.470850, R2 Score: 0.895079"
Este modelo es mucho más acertivo, pues su potencia es mucho mayor, obteniendo un \(R^2\) de 88% para la etapa de entrenamiento y un \(R^2\) de 89% para validación en el año 2018, por ende, el modelo es útil para predecir accidentalidad en Medellín.
datos_lm4_v1 <- datos_vl02 %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
CLASE) %>% dplyr::count(name = "NRO_ACCID")
datos_lm4_v2 <- datos_lm4_v1[,-5]
y_train <- round(predict(lm4, newdata= datos_lm4_v2, type="response"))
y_actual <- datos_lm4_v1$NRO_ACCID
lm4_tmse <- MSE(y_train, y_actual)
lm4_tmae <- MAE(y_train, y_actual)
lm4_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f", lm4_tmse, lm4_tmae, lm4_r2)## [1] "MSE: 99.620330, MAE: 5.971978, R2 Score: 0.886356"
Se obtiene un \(R^2\) para los datos de validación de 88.6% evidenciando que el modelo tiene potencia para realizar predicciones sobre la accidentalidad en Medellín.
datos_lm5 <- base_final03 %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
CLASE, DISENO) %>% dplyr::count(name = "NRO_ACCID")
lm5 <- glm(NRO_ACCID ~ FESTIVIDAD+DIA_SEMANA+CLASE+DISENO, family = "poisson",
data = datos_lm5)datos_lm5_p <- datos_lm5[,-6]
y_train <- round(predict(lm5, newdata= datos_lm5_p, type="response"))
y_actual <- datos_lm5$NRO_ACCID
lm5_tmse01 <- MSE(y_train, y_actual)
lm5_tmae <- MAE(y_train, y_actual)
lm5_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f",
lm5_tmse01, lm5_tmae, lm5_r2)## [1] "MSE: 32.500873, MAE: 3.238339, R2 Score: 0.865619"
datos_lm5_v1 <- datos_vl %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
CLASE, DISENO) %>% dplyr::count(name = "NRO_ACCID")
datos_lm5_v2 <- datos_lm5_v1[,-6]
y_train <- round(predict(lm5, newdata= datos_lm5_v2, type="response"))
y_actual <- datos_lm5_v1$NRO_ACCID
lm5_tmse02 <- MSE(y_train, y_actual)
lm5_tmae <- MAE(y_train, y_actual)
lm5_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f",
lm5_tmse02, lm5_tmae, lm5_r2)## [1] "MSE: 27.591440, MAE: 3.236468, R2 Score: 0.819347"
Utilizando este modelo lineal generalizado poisson, teniendo en cuenta que se cuenta también con la variable DISEÑO, se obtiene un \(R^2\) en las etapas de entrenamiento y validación, de 86.5% y 82% respectivamente,lo que indica una potencia adecuada.
datos_lm5_v1 <- datos_vl02 %>% group_by(FECHA, FESTIVIDAD, DIA_SEMANA,
CLASE, DISENO) %>% dplyr::count(name = "NRO_ACCID")
datos_lm5_v2 <- datos_lm5_v1[,-6]
y_train <- round(predict(lm5, newdata= datos_lm5_v2, type="response"))
y_actual <- datos_lm5_v1$NRO_ACCID
lm5_tmse02 <- MSE(y_train, y_actual)
lm5_tmae <- MAE(y_train, y_actual)
lm5_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f",
lm5_tmse02, lm5_tmae, lm5_r2)## [1] "MSE: 29.108963, MAE: 3.385074, R2 Score: 0.829171"
Para concluir, se decide trabajar con el modelo lineal generalizado, que contiene la variable CLASE, ya que según los resultados anteriores, son mucho más óptimos para la realización de predicciones
datos_lm7 <- base_final03 %>% group_by(FECHA, FESTIVIDAD, MES,
CLASE) %>% dplyr::count(name = "NRO_ACCID")
lm7 <- glm(NRO_ACCID ~ FESTIVIDAD+MES+CLASE, family = "poisson",
data = datos_lm7)datos_lm7_p <- datos_lm7[,-5]
y_train <- round(predict(lm7, newdata= datos_lm7_p, type="response"))
y_actual <- datos_lm7$NRO_ACCID
lm7_tmse <- MSE(y_train, y_actual)
lm7_tmae <- MAE(y_train, y_actual)
lm7_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f",
lm7_tmse, lm7_tmae, lm7_r2)## [1] "MSE: 96.534080, MAE: 5.724992, R2 Score: 0.888488"
datos_lm7_v1 <- datos_vl %>% group_by(FECHA, FESTIVIDAD, MES,
CLASE) %>% dplyr::count(name = "NRO_ACCID")
datos_lm7_v2 <- datos_lm7_v1[,-5]
y_train <- round(predict(lm7, newdata= datos_lm7_v2, type="response"))
y_actual <- datos_lm7_v1$NRO_ACCID
lm7_tmse <- MSE(y_train, y_actual)
lm7_tmae <- MAE(y_train, y_actual)
lm7_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f", lm7_tmse, lm7_tmae, lm7_r2)## [1] "MSE: 94.413068, MAE: 5.552602, R2 Score: 0.888105"
Se obtiene un \(R^2\) en la etapa de entrenamiento y validación del 88.84% y de 88.81% respectivamente, lo cual indica una buena potencia para predecir accidentalidad en Medellín
datos_lm7_v1 <- datos_vl02 %>% group_by(FECHA, FESTIVIDAD, MES,
CLASE) %>% dplyr::count(name = "NRO_ACCID")
datos_lm7_v2 <- datos_lm7_v1[,-5]
y_train <- round(predict(lm7, newdata= datos_lm7_v2, type="response"))
y_actual <- datos_lm7_v1$NRO_ACCID
lm7_tmse <- MSE(y_train, y_actual)
lm7_tmae <- MAE(y_train, y_actual)
lm7_r2 <- R2_Score(y_train, y_actual)
sprintf("MSE: %f, MAE: %f, R2 Score: %f", lm7_tmse, lm7_tmae, lm7_r2)## [1] "MSE: 97.898352, MAE: 5.923626, R2 Score: 0.888320"
En este modelo la diferencia del MSE entre los datos de entrenamiento y validaci?n del 2019 es del 1.3%, que fue menor al valor obtenido con la validaci?n del 2018 (2.19%), que indica claramente que no hay problemas de sobreentrenamiento. Adem?s se puede observar que el \(R^2\) de los datos de validaci?n para el AÑO 2019 predice un 88.83%, evidenciando as? que este modelo lineal generalizado con la adici?n de la variable Clase es un buen candidato para predecir la accidentalidad en Medell?n.
Se concluye que el modelo tiene buena potencia para predecir accidentes en la ciudad de Medellin.
datos_real_pred <- read_excel("Base_2020_real_predict.xlsx")Encabezado de datos con predicciones diarias para el año 2020
Base_prediccion <- read.csv("prediccion.csv", sep = ",", encoding = "UTF-8")
Base_prediccion <- Base_prediccion[,-1]
Base_prediccion_2020 <- subset(Base_prediccion, (AÑO != '2020'))
Base_prediccion_2020$FECHA <- as.Date(Base_prediccion_2020$FECHA)
Base_prediccion_2020$CLASE <- as.factor(Base_prediccion_2020$CLASE)
Base_prediccion_2020$DIA_SEMANA <- as.factor(Base_prediccion_2020$DIA_SEMANA)
Base_prediccion_2020$AÑO <- as.integer(Base_prediccion_2020$AÑO)
Base_prediccion_2020$FESTIVIDAD <- as.factor(Base_prediccion_2020$FESTIVIDAD)
prediccion_2020 <- predict(object = lm4, newdata = Base_prediccion_2020,
type = "response")
prediccion_diaria2020 <- Base_prediccion_2020 %>%
mutate(NRO_ACCID = round(prediccion_2020,0))
diario_20_02 <- prediccion_diaria2020 %>%
group_by(FECHA, DIA_SEMANA, CLASE, FESTIVIDAD) %>%
summarise(NRO_TOTAL_ACCID=NRO_ACCID)
head(diario_20_02, 6)Encabezado de datos con predicciones mensual para el año 2020
Base_prediccion <- read.csv("prediccion.csv", sep = ",", encoding = "UTF-8")
Base_prediccion_2020 <- subset(Base_prediccion, (AÑO != '2020'))
Base_prediccion_2020$FECHA <- as.Date(Base_prediccion_2020$FECHA)
Base_prediccion_2020$CLASE <- as.factor(Base_prediccion_2020$CLASE)
Base_prediccion_2020$DIA_SEMANA <- as.factor(Base_prediccion_2020$DIA_SEMANA)
Base_prediccion_2020$AÑO <- as.integer(Base_prediccion_2020$AÑO)
Base_prediccion_2020$FESTIVIDAD <- as.factor(Base_prediccion_2020$FESTIVIDAD)
prediccion_2020 <- predict(object = lm4, newdata = Base_prediccion_2020,
type = "response")
prediccion_mensual2020 <- Base_prediccion_2020 %>%
mutate(NRO_ACCID = round(prediccion_2020,0))
#Se borraron columnas no necesarias
prediccion_mensual2020 <- prediccion_mensual2020[,c(-1,-2,-3,-5,-7)]
#Agrupamiento por mes 2020
#Se agrup? por mes y si fue en d?a festivo o no
mensual_20 <- prediccion_mensual2020 %>% group_by(CLASE, MES, NRO_ACCID, FESTIVIDAD) %>% dplyr::summarize(total = n())
mensual_20 <- mutate(mensual_20, NRO_ACCID_TOTAL=NRO_ACCID*total)
mensual_20_02 <- mensual_20 %>%
group_by(MES, CLASE, FESTIVIDAD) %>%
summarise(NRO_TOTAL_ACCID=sum(NRO_ACCID_TOTAL))
head(mensual_20_02, 6)Encabezado de datos con predicciones diarias para el año 2021
Base_prediccion_2021 <- subset(Base_prediccion, (AÑO != '2021'))
Base_prediccion_2021$FECHA <- as.Date(Base_prediccion_2021$FECHA)
Base_prediccion_2021$CLASE <- as.factor(Base_prediccion_2021$CLASE)
Base_prediccion_2021$DIA_SEMANA <- as.factor(Base_prediccion_2021$DIA_SEMANA)
Base_prediccion_2021$AÑO <- as.integer(Base_prediccion_2021$AÑO)
Base_prediccion_2021$FESTIVIDAD <- as.factor(Base_prediccion_2021$FESTIVIDAD)
prediccion_2021 <- predict(object = lm4, newdata = Base_prediccion_2021,
type = "response")
prediccion_diaria2021 <- Base_prediccion_2021 %>%
mutate(NRO_ACCID = round(prediccion_2021,0))
diario_21_02 <- prediccion_diaria2021 %>%
group_by(FECHA, DIA_SEMANA, CLASE, FESTIVIDAD) %>%
summarise(NRO_TOTAL_ACCID=NRO_ACCID)
head(diario_21_02, 6)Encabezado de datos con predicciones mensual para el año 2021
Base_prediccion <- read.csv("prediccion.csv", sep = ",", encoding = "UTF-8")
Base_prediccion_2020 <- subset(Base_prediccion, (AÑO != '2021'))
Base_prediccion_2020$FECHA <- as.Date(Base_prediccion_2020$FECHA)
Base_prediccion_2020$CLASE <- as.factor(Base_prediccion_2020$CLASE)
Base_prediccion_2020$DIA_SEMANA <- as.factor(Base_prediccion_2020$DIA_SEMANA)
Base_prediccion_2020$AÑO <- as.integer(Base_prediccion_2020$AÑO)
Base_prediccion_2020$FESTIVIDAD <- as.factor(Base_prediccion_2020$FESTIVIDAD)
prediccion_2020 <- predict(object = lm4, newdata = Base_prediccion_2020,
type = "response")
prediccion_mensual2020 <- Base_prediccion_2020 %>%
mutate(NRO_ACCID = round(prediccion_2020,0))
#Se borraron columnas no necesarias
prediccion_mensual2020 <- prediccion_mensual2020[,c(-1,-2,-3,-5,-7)]
#Agrupamiento por mes 2020
#Se agrup? por mes y si fue en d?a festivo o no
mensual_20 <- prediccion_mensual2020 %>% group_by(CLASE, MES, NRO_ACCID, FESTIVIDAD) %>% dplyr::summarize(total = n())
mensual_20 <- mutate(mensual_20, NRO_ACCID_TOTAL=NRO_ACCID*total)
mensual_20_02 <- mensual_20 %>%
group_by(MES, CLASE, FESTIVIDAD) %>%
summarise(NRO_TOTAL_ACCID=sum(NRO_ACCID_TOTAL))
head(mensual_20_02, 6)Mapa de calor de accidentalidad en la ciudad de Medellín entre los años 2014 y 2019 (Histórico)
#lectura de .csv y .shp
catastral <- read.csv("Limite_Barrio_Vereda_Catastral.csv", encoding="UTF-8")
catastro <- read_sf("Limite_Barrio_Vereda_Catastral.shp")
barrio_vereda <- read.csv("Barrio_Vereda_2014.csv", encoding="UTF-8")#Mapa para todos los barrios, usando 'innerjoin' con el .shp de Limite_Barrio_Vereda_Catastral
Unido <- inner_join(catastral, base_final, by = c("COMUNA" = "NUMCOMUNA"))
nueva_base <- Unido %>% filter(AÑO >= 2014 & AÑO <= 2019) %>%
group_by(CODIGO) %>%
dplyr::summarise(accidentes = n()) %>%
dplyr::ungroup()
#Se realiz? la conversi?n de CODIGO a formato num?rico
catastro$CODIGO <- as.numeric(as.character(catastro$CODIGO))
#Se utiliz? 'inner join' para unir dos bases y para luego generar mapa
mapa <- inner_join(catastro, nueva_base, by = c("CODIGO" = "CODIGO"))
mypal <- colorNumeric(palette = c("#000000","#280100","#3D0201","#630201","#890100","#B00100","#DD0100","#F50201",
"#FF5F5E","#FF7A79","#FF9796","#FEB1B0","#FDC9C8", "#FFE5E4"), domain = mapa$accidentes, reverse = T)
# Creaci?n del mapa
leaflet() %>% addPolygons(data = mapa, color = "#0A0A0A", opacity = 0.6, weight = 1, fillColor = ~mypal(mapa$accidentes),
fillOpacity = 0.6, label = ~NOMBRE_BAR,
highlightOptions = highlightOptions(color = "black", weight = 3, bringToFront = T, opacity = 1),
popup = paste("Barrio: ", mapa$NOMBRE_BAR, "<br>", "Accidentes: ", mapa$accidentes, "<br>")) %>%
addProviderTiles(providers$OpenStreetMap) %>%
addLegend(position = "bottomright", pal = mypal, values = mapa$accidentes, title = "Accidentes", opacity = 0.6)