El análisis se basa en el conjunto de datos “Suicide Rates Overview 1985 to 2016”, disponible en Kaggle. Este conjunto de datos, que abarca 27,820 observaciones, proporciona información socioeconómica y demográfica de diversos países, con el objetivo de identificar señales correlacionadas con el aumento de las tasas de suicidio globales durante el período de 1985 a 2016.
df <- read_csv("C:/Users/jcami/Downloads/archive/master.csv")
df %<>% clean_names
En un primer momento, estandarizamos el nombre de las variables
utilizando la función clean_names y estudiamos las
dimensiones de la base de datos. Tal como se puede observar a
continuación, el dataset cuenta con 27,820 observaciones y 12 variables,
entre las cuales se encuentran: país, year, sexo, edad (o rango de
edad), número de suicidios, población, tasa de suicidio por cada 100,000
habitantes, entre otras.
df %>% glimpse
## Rows: 27,820
## Columns: 12
## $ country <chr> "Albania", "Albania", "Albania", "Albania", "Albania…
## $ year <dbl> 1987, 1987, 1987, 1987, 1987, 1987, 1987, 1987, 1987…
## $ sex <chr> "male", "male", "female", "male", "male", "female", …
## $ age <chr> "15-24 years", "35-54 years", "15-24 years", "75+ ye…
## $ suicides_no <dbl> 21, 16, 14, 1, 9, 1, 6, 4, 1, 0, 0, 0, 2, 17, 1, 14,…
## $ population <dbl> 312900, 308000, 289700, 21800, 274300, 35600, 278800…
## $ suicides_100k_pop <dbl> 6.71, 5.19, 4.83, 4.59, 3.28, 2.81, 2.15, 1.56, 0.73…
## $ country_year <chr> "Albania1987", "Albania1987", "Albania1987", "Albani…
## $ hdi_for_year <dbl> NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, NA, …
## $ gdp_for_year <dbl> 2156624900, 2156624900, 2156624900, 2156624900, 2156…
## $ gdp_per_capita <dbl> 796, 796, 796, 796, 796, 796, 796, 796, 796, 796, 79…
## $ generation <chr> "Generation X", "Silent", "Generation X", "G.I. Gene…
En cuanto al tipo de variable, se observa que la mayoría de las variables tipo factor vienen en forma de cadena de caracteres, por lo cual a continuación se procede a cambiar el tipo de variable para que sea acorde con la descripción del dataset:
selected_columns <- c("country","sex","country_year","generation","age")
df[selected_columns] <- lapply(df[selected_columns], as.factor)
Además de las variables categóricas ya mencionadas, el dataset cuenta con variables continuas relacionadas con la población, la tasa de suicidio por cada 100,000 habitantes, el índice de desarrollo humano por year, el producto interno bruto (PIB) por year y el producto interno bruto per cápita. A continuación, se presenta una descripción general de la base de datos:
summary(df)
## country year sex age
## Austria : 382 Min. :1985 female:13910 15-24 years:4642
## Iceland : 382 1st Qu.:1995 male :13910 25-34 years:4642
## Mauritius : 382 Median :2002 35-54 years:4642
## Netherlands: 382 Mean :2001 5-14 years :4610
## Argentina : 372 3rd Qu.:2008 55-74 years:4642
## Belgium : 372 Max. :2016 75+ years :4642
## (Other) :25548
## suicides_no population suicides_100k_pop country_year
## Min. : 0.0 Min. : 278 Min. : 0.00 Albania1987: 12
## 1st Qu.: 3.0 1st Qu.: 97498 1st Qu.: 0.92 Albania1988: 12
## Median : 25.0 Median : 430150 Median : 5.99 Albania1989: 12
## Mean : 242.6 Mean : 1844794 Mean : 12.82 Albania1992: 12
## 3rd Qu.: 131.0 3rd Qu.: 1486143 3rd Qu.: 16.62 Albania1993: 12
## Max. :22338.0 Max. :43805214 Max. :224.97 Albania1994: 12
## (Other) :27748
## hdi_for_year gdp_for_year gdp_per_capita generation
## Min. :0.483 Min. :4.692e+07 Min. : 251 Boomers :4990
## 1st Qu.:0.713 1st Qu.:8.985e+09 1st Qu.: 3447 G.I. Generation:2744
## Median :0.779 Median :4.811e+10 Median : 9372 Generation X :6408
## Mean :0.777 Mean :4.456e+11 Mean : 16866 Generation Z :1470
## 3rd Qu.:0.855 3rd Qu.:2.602e+11 3rd Qu.: 24874 Millenials :5844
## Max. :0.944 Max. :1.812e+13 Max. :126352 Silent :6364
## NA's :19456
Finalmente, concluimos esta primera sección examinando la presencia
de datos faltantes haciendo uso de la función missmap del
paquete Amelia. Tal como se puede observar a continuación, la variable
asociada al índice de desarrollo humano por year cuenta con una gran
cantidad de datos faltantes:
missmap(df)
Se nota que, aunque en general estos datos faltantes solo representan alrededor del 6% del total de datos, si se analiza solo la proporción de faltantes dentro de la variable, se llega a la conclusión de que estos datos representan alrededor del 70% de las observaciones del índice de desarrollo humano por year:
missing_data <- ifelse(is.na(df$hdi_for_year),1,0)
porcentaje_NA <- round(sum(missing_data)/length(df$hdi_for_year)*100,3)
porcentaje_NA
## [1] 69.935
El primer análisis de los datos no indica que no hay datos faltantes y que tienden a tener un numero consistente de observaciones. A continuación se presentan las primeras 10 observaciones del dataframe con el fin de entender mejor la estructura de esta variable:
head(df,10)
## # A tibble: 10 × 12
## country year sex age suicides_no population suicides_100k_pop
## <fct> <dbl> <fct> <fct> <dbl> <dbl> <dbl>
## 1 Albania 1987 male 15-24 years 21 312900 6.71
## 2 Albania 1987 male 35-54 years 16 308000 5.19
## 3 Albania 1987 female 15-24 years 14 289700 4.83
## 4 Albania 1987 male 75+ years 1 21800 4.59
## 5 Albania 1987 male 25-34 years 9 274300 3.28
## 6 Albania 1987 female 75+ years 1 35600 2.81
## 7 Albania 1987 female 35-54 years 6 278800 2.15
## 8 Albania 1987 female 25-34 years 4 257200 1.56
## 9 Albania 1987 male 55-74 years 1 137500 0.73
## 10 Albania 1987 female 5-14 years 0 311000 0
## # ℹ 5 more variables: country_year <fct>, hdi_for_year <dbl>,
## # gdp_for_year <dbl>, gdp_per_capita <dbl>, generation <fct>
Ahora se presentan las ultimas 10 observaciones del dataframe.
tail(df,10)
## # A tibble: 10 × 12
## country year sex age suicides_no population suicides_100k_pop
## <fct> <dbl> <fct> <fct> <dbl> <dbl> <dbl>
## 1 Uzbekistan 2014 female 15-24 years 347 2992817 11.6
## 2 Uzbekistan 2014 male 55-74 years 144 1271111 11.3
## 3 Uzbekistan 2014 male 15-24 years 347 3126905 11.1
## 4 Uzbekistan 2014 male 75+ years 17 224995 7.56
## 5 Uzbekistan 2014 female 25-34 years 162 2735238 5.92
## 6 Uzbekistan 2014 female 35-54 years 107 3620833 2.96
## 7 Uzbekistan 2014 female 75+ years 9 348465 2.58
## 8 Uzbekistan 2014 male 5-14 years 60 2762158 2.17
## 9 Uzbekistan 2014 female 5-14 years 44 2631600 1.67
## 10 Uzbekistan 2014 female 55-74 years 21 1438935 1.46
## # ℹ 5 more variables: country_year <fct>, hdi_for_year <dbl>,
## # gdp_for_year <dbl>, gdp_per_capita <dbl>, generation <fct>
Al examinar más detalladamentes el número de observaciones por país, se evindencia que no se cuenta con los datos de algunos paises en algunos years. Más aún, no encuentran datos faltantes que más alla de lo ya mencionado.
which(is.na(df$country)) # no se encuentran datos faltantes
## integer(0)
head(table(df$country),20)
##
## Albania Antigua and Barbuda Argentina
## 264 324 372
## Armenia Aruba Australia
## 298 168 360
## Austria Azerbaijan Bahamas
## 382 192 276
## Bahrain Barbados Belarus
## 252 300 252
## Belgium Belize Bosnia and Herzegovina
## 372 336 24
## Brazil Bulgaria Cabo Verde
## 372 360 12
## Canada Chile
## 348 372
Ahora se construir una tabla de frecuencia con medidas descriptivas:
Tabla_pais <- df %>%
group_by(country) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_pais
## # A tibble: 101 × 4
## country n Proporcion Porcentaje
## <fct> <int> <dbl> <chr>
## 1 Mongolia 10 0.000359 0.0359%
## 2 Cabo Verde 12 0.000431 0.0431%
## 3 Dominica 12 0.000431 0.0431%
## 4 Macau 12 0.000431 0.0431%
## 5 Bosnia and Herzegovina 24 0.000863 0.0863%
## 6 Oman 36 0.00129 0.1294%
## 7 Saint Kitts and Nevis 36 0.00129 0.1294%
## 8 San Marino 36 0.00129 0.1294%
## 9 Nicaragua 72 0.00259 0.2588%
## 10 United Arab Emirates 72 0.00259 0.2588%
## # ℹ 91 more rows
Finalmente se culmina que el estudio de esta variable, se presentara un diagrama de barra con los paises con el menor número de observaciones debido a la gran número de categorias.
Tabla_pais <- Tabla_pais %>%
arrange(desc(Proporcion))
ggplot(tail(Tabla_pais,20), aes(x=reorder(
country, -n),y=n))+
geom_bar(stat="identity", position=position_dodge(),fill="darkolivegreen")+
theme(plot.title = element_text(hjust = 0.5, size = 12, vjust = 2),
axis.text.x = element_text(angle = 90, hjust = 0.8, vjust = 0.5, ))+
ggtitle("Observaciones por pais")+
xlab("Pais")+
ylab("Observaciones")
En el apartado anterior observamos que cada paises tiene varias observaciones por year y que en principio esta variable no presenta datos faltantes.Con el fin de corroborar esto y de conocer de manera más detallada cuantas observaciones se cuenta por cada year, se presenta un tabla que se resume esta información:
table(df$year)
##
## 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000
## 576 576 648 588 624 768 768 780 780 816 936 924 924 948 996 1032
## 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016
## 1056 1032 1032 1008 1008 1020 1032 1020 1068 1056 1032 972 960 936 744 160
Dado que no se observan datos faltantes, procedemos a visualizar el número de observaciones por year en un grafico de barras:
Tabla_year <- df %>%
group_by(year) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_year
## # A tibble: 32 × 4
## year n Proporcion Porcentaje
## <dbl> <int> <dbl> <chr>
## 1 2016 160 0.00575 0.575%
## 2 1985 576 0.0207 2.070%
## 3 1986 576 0.0207 2.070%
## 4 1988 588 0.0211 2.114%
## 5 1989 624 0.0224 2.243%
## 6 1987 648 0.0233 2.329%
## 7 2015 744 0.0267 2.674%
## 8 1990 768 0.0276 2.761%
## 9 1991 768 0.0276 2.761%
## 10 1992 780 0.0280 2.804%
## # ℹ 22 more rows
ggplot(Tabla_year, aes(x = factor(year), y = n)) +
geom_bar(stat = "identity", position = position_dodge(), fill = "cyan4") +
theme(plot.title = element_text(hjust = 0.5, size = 12, vjust = 2),
axis.text.x = element_text(angle = 90, hjust = 1, vjust = 0.5)) +
ggtitle("Observaciones por perido") +
xlab("Periodo") +
ylab("Observaciones") +
scale_x_discrete(breaks = unique(Tabla_year$year))
### Sexo
En lo que concierne al número de observaciones por sexo, el analisis inical muestra que no hay datos faltantes y que las observaciones entre hombres y mujeres es similar. Debido a esto, a continuación se presenta un tabla de con el porcentaje de observaciones por sexo y un diagrama de barras que ayudara a detallar la distribución de esta variables en el dataset:
Tabla_sex <- df %>%
group_by(sex) %>%
count() %>%
ungroup() %>%
mutate(proporcion = `n` / sum(`n`)) %>%
arrange(proporcion) %>%
mutate(Porcentaje = scales::percent(proporcion))
Tabla_sex
## # A tibble: 2 × 4
## sex n proporcion Porcentaje
## <fct> <int> <dbl> <chr>
## 1 female 13910 0.5 50%
## 2 male 13910 0.5 50%
ggplot(Tabla_sex , aes(x = "", y = proporcion, fill = sex)) +
geom_col(color = "black") +
geom_label(aes(label = Porcentaje),
position = position_stack(vjust = 0.5),
show.legend = FALSE) +
guides(fill = guide_legend(title = "Sexo")) + scale_color_gradient() +
coord_polar(theta = "y") + ggtitle ("Distribucion de sexo")+
theme(plot.title = element_text(hjust = 0.5, size = 12, vjust = 2))
En lo que respecta al rango de edad, el análisis inicial nos indica
que no hay datos faltantes. Con el fin de examinar de manera más
detallada la variable age a continuación se presenta una
tabla de frecuencias:
table(df$age)
##
## 15-24 years 25-34 years 35-54 years 5-14 years 55-74 years 75+ years
## 4642 4642 4642 4610 4642 4642
Tal como se noto inicialmente, la tabla indica que nos hay observaciones faltantes y, más aún, todas las categorias de edad tienen el mismo número de observaciones. Por lo cual se procede a construir la tabla de frecuencia con medidas descritivas:
Por lo cual se culmina por el momento en análisis de esta varibale
presentado una diagrama de barras de age:
Tabla_age <- df %>%
group_by(age) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_age
## # A tibble: 6 × 4
## age n Proporcion Porcentaje
## <fct> <int> <dbl> <chr>
## 1 5-14 years 4610 0.166 16.57%
## 2 15-24 years 4642 0.167 16.69%
## 3 25-34 years 4642 0.167 16.69%
## 4 35-54 years 4642 0.167 16.69%
## 5 55-74 years 4642 0.167 16.69%
## 6 75+ years 4642 0.167 16.69%
ggplot(Tabla_age, aes(x=age,y=n))+
geom_bar(stat="identity", position=position_dodge(),fill="cyan4")+
coord_cartesian(ylim = c(0, 5000))+
theme(plot.title = element_text(hjust = 0.5, size = 12, vjust = 2),
axis.text.x = element_text(angle = 90, hjust = 0.7, vjust = 0.5))+
ggtitle("Observaciones por rango de edad")+
xlab("Rango de edad")+
ylab("Observaciones")
Tal como en el caso anterior, el análisis inicial indico que no hay
datos faltantes en la variablegeneration. A continuación,
se presente una tabla de frecuencias absolutas:
table(df$generation)
##
## Boomers G.I. Generation Generation X Generation Z Millenials
## 4990 2744 6408 1470 5844
## Silent
## 6364
Ahora se presenta la tabla con las respectivas medidas descriptivas:
Tabla_gene <- df %>%
group_by(generation) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_gene
## # A tibble: 6 × 4
## generation n Proporcion Porcentaje
## <fct> <int> <dbl> <chr>
## 1 Generation Z 1470 0.0528 5.28%
## 2 G.I. Generation 2744 0.0986 9.86%
## 3 Boomers 4990 0.179 17.94%
## 4 Millenials 5844 0.210 21.01%
## 5 Silent 6364 0.229 22.88%
## 6 Generation X 6408 0.230 23.03%
La tabla de frecuencias confirma la supocisión en cuanto la ausencia de datos faltantes y que cada una de los generaciones difieren en el número de las observaciones, para ver esto a más detalle de presenta un diagrama de barras:
ggplot(Tabla_gene, aes(x=reorder(
generation, -n),y=n))+
geom_bar(stat="identity", position=position_dodge(),fill="darkolivegreen")+
theme(plot.title = element_text(hjust = 0.5, size = 12, vjust = 2),
axis.text.x = element_text(angle = 90, hjust = 0.8, vjust = 0.5, ))+
ggtitle("Observaciones por generacion")+
xlab("generacion")+
ylab("Observaciones")
Ahora analizaremos las varibale population. Dedido a que
esta es una varibale númerica se comenzara construyendo un histograma y
un diagrama de cajas (Boxplot) para estudiar la distribución de la
varibale.
par(mfrow = c(1, 2))
hist(df$population, xlab = "Poblacion", ylab = "Frecuencia", main = "Poblacion por year")
boxplot <- boxplot(df$population, ylab = "Poblacion por year", main = "Boxplot")
Los graficos muestran que la distribución esta fuertamente sesgada a
la izquierda. Dicho esto, en el contexto de las varibales relacionados
con la economia se suele utilizar la transformación logaritmica para
centrar estas distribuciones. Debido a esto se creara una nueva varibale
population_logy se estudiara su distribución:
df$population_log <- log(df$population)
Ahora volveremos a generar el histograma y el diagrama de cajas para estudiar la distribución de la nueva variable:
par(mfrow = c(1, 2))
hist(df$population_log, xlab = "Poblacion por year (Log)", ylab = "Frecuencia", main = "Poblacion por year")
boxplot <- boxplot(df$population_log, ylab = "Poblacion por year", main = "Boxplot")
Tal como se puede apreciar el los graficos la distribución de esta
variable es más simetrica, con lo cual concluimos que la transformación
fue beneficiosa. Sin embargo, el diagrama de cajas aún muestra
observaciones que pueden llegar a ser datos atipicos.
Los graficos revelan la existencia de valores atipicos en la variable
population_log . Por lo cual, antes de proseguir
utilizaremos el filtro de Hampel y el método de los percentiles para
estudiar más a profundidad estas observaciones.
# Calcular los límites usando el filtro de Hampel
lower_bound <- median(df$population_log, na.rm = TRUE) - 3 * mad(df$population_log, constant = 1, na.rm = TRUE)
upper_bound <- median(df$population_log, na.rm = TRUE) + 3 * mad(df$population_log, constant = 1, na.rm = TRUE)
# Identificar los índices de los outliers
outlier_ind <- which(df$population_log < lower_bound | df$population_log > upper_bound)
# Crear una columna que marque los outliers
df$Hampel <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
# Ver el número de outliers
length(outlier_ind)
## [1] 1491
lower_bound <- quantile(df$population_log, 0.025)
upper_bound <- quantile(df$population_log, 0.975)
outlier_ind <- which(df$population_log < lower_bound | df$population_log > upper_bound)
# Crear una columna que marque los outliers
df$Perc <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
# Ver el número de outliers
length(outlier_ind)
## [1] 1391
table(df$Hampel, df$Perc)
##
## 0 1
## 0 25723 606
## 1 706 785
Vemos que existen discrepancias en entre el filtor de Hampel y el metodo de los percentiles. Por se aplicara la prueba de Rosner para confirmar la existencias de estos datos atipicos:
test <- rosnerTest(df$population_log, k = 1000)
test <- test$all.stats
outlier_ind <- test[test$Outlier == TRUE,]$Obs.Num
df$Rosner <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
Los resultado de la prueba de Rosner indico que ninguno de las
observaciones analisadas son datos atipicos, por lo cual se culmina esta
sección con medidas descriptivas de la variable
population_log:
df %>%
get_summary_stats(population_log, type = "five_number")
## # A tibble: 1 × 7
## variable n min max q1 median q3
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 population_log 27820 5.63 17.6 11.5 13.0 14.2
La variable suicides_no contiene información sobre los
suicidios por year. Debido a su naturaleza procederemos de misma manera
que en la sección anterior:
par(mfrow = c(1, 2))
hist(df$suicides_no, xlab = "Suicidios", ylab = "Frecuencia", main = "Suicidios por year")
boxplot(df$suicides_no, ylab = "Suicidios por year", main = "Boxplot")
La distribución de
suicides_no presenta un sesgo
significativo hacia la izquierda. Sin embargo, no es viable aplicar una
transformación debido a la presencia de ceros en los datos. Dado que,
por la naturaleza de la variable, se anticipa una alta frecuencia de
valores bajos en comparación con los valores elevados, no es posible
descartar que los valores que se desvían de la mediana sean errores de
codificación. Por lo tanto, esta sección concluirá presentando algunas
métricas descriptivas.
df%>%
get_summary_stats(suicides_no, type = "five_number")
## # A tibble: 1 × 7
## variable n min max q1 median q3
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 suicides_no 27820 0 22338 3 25 131
En lo que concierne al producto interno producto por year
(gdp_for_year), la exploración inicial de los datos no
revela datos faltanes. Con el fin de estudiar de manera más detallada de
distribucipon de la variables se genera un histograma de frecuencia y un
diagrama de cajas:
par(mfrow = c(1, 2))
hist(df$gdp_for_year, xlab = "GDP por year", ylab = "Frecuencia", main = "Histograma del GDP por year")
boxplot(df$gdp_for_year, ylab = "GDP por year", main = "Boxplot del DGP por year")
Al trabajar con variables economicas es usual utiliar la
transformación logaritmica, por lo cual vamos a calcular el logartimo
del producto interno bruto por year y lo registramos como una nueva
variable en el conjunto de datos (gdp_for_year_log):
df$gdp_for_year_log <- log(df$gdp_for_year)
Hecho esto, volvemos volvemos a revisar la distribución de
gdp_for_year_log utlizando un histograma y un diagrama de
cajas:
par(mfrow = c(1, 2))
hist(df$gdp_for_year_log, xlab = "GDP por year (Log)", ylab = "Frecuencia", main = "Histograma del GDP por year")
boxplot <- boxplot(df$gdp_for_year_log, ylab = "GDP por year (Log)", main = "Boxplot del DGP por year")
Del diagrama de cajas, observamos que existen posibles datos atipicos
en la variable gdp_for_year_log. Por lo cual, vamos a
proceder a un estudio detallado de estas observaciones:
Los graficos revelan la existencia de valores atipicos en la variable
gdp_for_year_log . Por lo cual, antes de proseguir
utilizaremos el filtro de Hampel y el método de los percentiles para
estudiar más a profundidad estas observaciones.
# Calcular los límites usando el filtro de Hampel
lower_bound <- median(df$gdp_for_year_log, na.rm = TRUE) - 3 * mad(df$gdp_for_year_log, constant = 1, na.rm = TRUE)
upper_bound <- median(df$gdp_for_year_log, na.rm = TRUE) + 3 * mad(df$gdp_for_year_log, constant = 1, na.rm = TRUE)
# Identificar los índices de los outliers
outlier_ind <- which(df$gdp_for_year_log < lower_bound | df$gdp_for_year_log > upper_bound)
# Crear una columna que marque los outliers
df$Hampel <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
# Ver el número de outliers
length(outlier_ind)
## [1] 636
lower_bound <- quantile(df$gdp_for_year_log, 0.025)
upper_bound <- quantile(df$gdp_for_year_log, 0.975)
outlier_ind <- which(df$gdp_for_year_log < lower_bound | df$gdp_for_year_log > upper_bound)
# Crear una columna que marque los outliers
df$Perc <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
# Ver el número de outliers
length(outlier_ind)
## [1] 1392
table(df$Hampel, df$Perc)
##
## 0 1
## 0 26428 756
## 1 0 636
Vemos que existen discrepancias en entre el filtor de Hampel y el metodo de los percentiles. Por se aplicara la prueba de Rosner para confirmar la existencias de estos datos atipicos:
test <- rosnerTest(df$gdp_for_year_log, k = 1000)
test <- test$all.stats
outlier_ind <- test[test$Outlier == TRUE,]$Obs.Num
df$Rosner <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
Los resultado de la prueba de Rosner indico que ninguno de las
observaciones analisadas son datos atipicos, por lo cual se culmina esta
sección con medidas descriptivas de la variable
gdp_for_year_log:
nortest::ad.test(df$gdp_for_year_log)
##
## Anderson-Darling normality test
##
## data: df$gdp_for_year_log
## A = 38.016, p-value < 2.2e-16
nortest::lillie.test(df$gdp_for_year_log)
##
## Lilliefors (Kolmogorov-Smirnov) normality test
##
## data: df$gdp_for_year_log
## D = 0.034712, p-value < 2.2e-16
Dado que ambas pruebas indican que la distribución de
gdp_for_year_log no se aproxima a una distribución
guassiana, culiminaremos el analisis de la varibale con algunas
estadisticas descriptivas:
df %>%
get_summary_stats(gdp_for_year_log, type = "five_number")
## # A tibble: 1 × 7
## variable n min max q1 median q3
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 gdp_for_year_log 27820 17.7 30.5 22.9 24.6 26.3
Tal como en el caso anterior, la exploración inicial de los datos no
revela datos faltanes. Con el fin de estudiar de manera más detallada de
distribucipon de la varible gdp_per_capita se genera un
histograma de frecuencia y un diagrama de cajas:
par(mfrow = c(1, 2))
hist(df$gdp_per_capita, xlab = "GDP per capita", ylab = "Frecuencia", main = "Histograma del GDP per capita")
boxplot(df$gdp_per_capita, ylab = "GDP per capita", main = "Boxplot del DGP per capita")
Ahora procedemos a calcular una nueva variable con la función
logaritmica llamada gdp_per_capita_log y utilizamos un
histograma y una diagrama de cajas para estudiar su distribución.
df$gdp_per_capita_log <- log(df$gdp_per_capita)
par(mfrow = c(1, 2))
hist(df$gdp_per_capita_log, xlab = "GDP per capita (Log)", ylab = "Frecuencia", main = "Histograma del GDP per capita")
boxplot(df$gdp_per_capita_log, ylab = "GDP per capita (Log)", main = "Boxplot del DGP per capita")
En este caso, no se evidenicas datos atipicos, por lo cual se procede
a comporbar la distribución de la variable
gdp_per_capita_log.
nortest::ad.test(df$gdp_per_capita_log)
##
## Anderson-Darling normality test
##
## data: df$gdp_per_capita_log
## A = 155.57, p-value < 2.2e-16
nortest::lillie.test(df$gdp_per_capita_log)
##
## Lilliefors (Kolmogorov-Smirnov) normality test
##
## data: df$gdp_per_capita_log
## D = 0.061759, p-value < 2.2e-16
Dado que ambas pruebas indican que la distribución de
gdp_per_capita_log no se aproxima a una distribución
guassiana, culiminaremos el analisis de la varibale con algunas
estadisticas descriptivas:
df %>%
get_summary_stats(gdp_per_capita_log, type = "five_number")
## # A tibble: 1 × 7
## variable n min max q1 median q3
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 gdp_per_capita_log 27820 5.52 11.7 8.14 9.14 10.1
Al analizar la variable del Índice de Desarrollo Humano (HDI) por year, se observa una proporción considerable de datos faltantes. Por lo tanto, procederemos a 1) realizar una descripción detallada de la variable y 2) explorar la forma más adecuada de manejar estos valores faltantes.
Primero, se explorará la distribución de la variable hdi_for_year utilizando un histograma y un diagrama de cajas:
par(mfrow = c(1, 2))
hist(df$hdi_for_year, xlab = "HDI por year", ylab = "Frecuencia", main = "Histograma del HDI por year")
boxplot(df$hdi_for_year, ylab = "HDI por year", main = "Boxplot del HDI por year")
Los gráficos sugieren que la distribución muestral del Índice de Desarrollo Humano por year está sesgada a la derecha y presenta al menos un valor atípico. Para complementar esta descripción, se realizaron dos pruebas de normalidad utilizando el paquete nortest para determinar si la variable sigue una distribución gaussiana:
nortest::lillie.test(df$hdi_for_year)
##
## Lilliefors (Kolmogorov-Smirnov) normality test
##
## data: df$hdi_for_year
## D = 0.055914, p-value < 2.2e-16
nortest::ad.test(df$hdi_for_year)
##
## Anderson-Darling normality test
##
## data: df$hdi_for_year
## A = 46.448, p-value < 2.2e-16
Dado que ambas pruebas de normalidad indican que la distribución del HDI por year no se aproxima a una distribución normal (probablemente debido a la asimetría y a la presencia de datos atípicos), finalizamos esta parte de la descripción presentando algunas medidas descriptivas robustas:
df%>%
get_summary_stats(hdi_for_year, type = "robust")
## # A tibble: 1 × 4
## variable n median iqr
## <fct> <dbl> <dbl> <dbl>
## 1 hdi_for_year 8364 0.779 0.142
En esta sección, exploraremos dos métodos para tratar los datos faltantes: 1) la imputación simple utilizando la mediana y 2) la imputación utilizando un modelo de regresión lineal. Consideramos inviable la omisión de observaciones con datos faltantes debido a su alta proporción en la base de datos. Además, dado que los datos están agrupados por países, la imputación por mediana podría tener limitaciones debido a posibles influencias de las agrupaciones en el HDI.
A continuación, se estudian las correlaciones entre las variables numéricas de la base de datos como punto de partida para construir el modelo de regresión. Utilizamos el coeficiente de Spearman para explorar las relaciones monotónicas entre variables, dado que el HDI no sigue una distribución normal:
round(cor(na.omit(df[c("suicides_no","population","hdi_for_year","gdp_for_year","gdp_for_year_log","gdp_per_capita","gdp_per_capita_log")]), method = "spearman"),3)
## suicides_no population hdi_for_year gdp_for_year
## suicides_no 1.000 0.762 0.185 0.620
## population 0.762 1.000 0.133 0.766
## hdi_for_year 0.185 0.133 1.000 0.612
## gdp_for_year 0.620 0.766 0.612 1.000
## gdp_for_year_log 0.620 0.766 0.612 1.000
## gdp_per_capita 0.084 0.054 0.929 0.591
## gdp_per_capita_log 0.084 0.054 0.929 0.591
## gdp_for_year_log gdp_per_capita gdp_per_capita_log
## suicides_no 0.620 0.084 0.084
## population 0.766 0.054 0.054
## hdi_for_year 0.612 0.929 0.929
## gdp_for_year 1.000 0.591 0.591
## gdp_for_year_log 1.000 0.591 0.591
## gdp_per_capita 0.591 1.000 1.000
## gdp_per_capita_log 0.591 1.000 1.000
Como se esperaba, las variables con transformaciones logarítmicas
muestran una relación perfecta con sus respectivas variables originales.
Sin embargo, se observa que el HDI (hdi_for_year) está
moderadamente relacionado con gdp_for_year y fuertemente
relacionado con gdp_per_capita.
# Establece la disposición de 2x2 para los gráficos
par(mfrow = c(2, 2),
mar = c(4, 4, 2, 1)) # Márgenes ajustados para dar más espacio a las etiquetas
# Primer gráfico: GDP por year vs. HDI por year
plot(df$gdp_for_year, df$hdi_for_year,
ylab = "HDI por year", xlab = "GDP por year",
main = "GDP vs. HDI",
pch = 19, cex = 0.8)
# Segundo gráfico: GDP por year (Log) vs. HDI por year
plot(df$gdp_for_year_log, df$hdi_for_year,
ylab = "", xlab = "GDP por year (Log)",
main = "GDP (Log) vs. HDI",
pch = 19,cex = 0.8)
# Tercer gráfico: GDP per capita vs. HDI por year
plot(df$gdp_per_capita, df$hdi_for_year,
ylab = "HDI por year", xlab = "GDP per capita",
main = "GDP per capita vs. HDI",
pch = 19,cex = 0.8)
# Cuarto gráfico: GDP per capita (Log) vs. HDI por year
plot(df$gdp_per_capita_log, df$hdi_for_year,
ylab = "", xlab = "GDP per capita (Log)",
main = "GDP per capita (Log) vs. HDI",
pch = 19,cex = 0.8)
Los gráficos de dispersión a continuación sugieren que las
transformaciones logarítmicas de las variables
gdp_per_capita y gdp_for_year tienen
relaciones lineales considerables con hdi_for_year. Por lo
tanto, procedemos a ajustar un modelo de regresión lineal utilizando
estas dos variables como predictores del HDI:
model <- lm(hdi_for_year~gdp_per_capita_log+gdp_for_year_log, data = df)
summary(model)
##
## Call:
## lm(formula = hdi_for_year ~ gdp_per_capita_log + gdp_for_year_log,
## data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.131865 -0.023307 0.004735 0.026218 0.109136
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.0543784 0.0046271 11.75 <2e-16 ***
## gdp_per_capita_log 0.0655451 0.0004095 160.05 <2e-16 ***
## gdp_for_year_log 0.0044041 0.0002238 19.68 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.03724 on 8361 degrees of freedom
## (19456 observations deleted due to missingness)
## Multiple R-squared: 0.8409, Adjusted R-squared: 0.8409
## F-statistic: 2.21e+04 on 2 and 8361 DF, p-value: < 2.2e-16
model2 <- lm(hdi_for_year~gdp_per_capita_log, data = df)
summary(model2)
##
## Call:
## lm(formula = hdi_for_year ~ gdp_per_capita_log, data = df)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.129733 -0.026388 0.004922 0.027833 0.110571
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.1209166 0.0032310 37.42 <2e-16 ***
## gdp_per_capita_log 0.0701741 0.0003429 204.64 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.03809 on 8362 degrees of freedom
## (19456 observations deleted due to missingness)
## Multiple R-squared: 0.8336, Adjusted R-squared: 0.8335
## F-statistic: 4.188e+04 on 1 and 8362 DF, p-value: < 2.2e-16
Ambos modelos de regresión explican una parte considerable de la
varianza observada en el HDI por year. La exclusión de
gdp_for_year representa una reducción marginal en la
varianza explicada. Sin embargo, ambos modelos violan los supuestos de
homocedasticidad y normalidad de los residuos.
car::vif(model)
## gdp_per_capita_log gdp_for_year_log
## 1.492244 1.492244
lmtest::bptest(model)
##
## studentized Breusch-Pagan test
##
## data: model
## BP = 770.8, df = 2, p-value < 2.2e-16
hist(residuals(model))
nortest::ad.test(residuals(model))
##
## Anderson-Darling normality test
##
## data: residuals(model)
## A = 59.082, p-value < 2.2e-16
lmtest::bptest(model2)
##
## studentized Breusch-Pagan test
##
## data: model2
## BP = 574.2, df = 1, p-value < 2.2e-16
hist(residuals(model2))
nortest::ad.test(residuals(model2))
##
## Anderson-Darling normality test
##
## data: residuals(model2)
## A = 50.936, p-value < 2.2e-16
A partir del segundo modelo, a continuación se presente el grafico de
dispersión entre gdp_per_capita_log y
hdi_for_year, con su respectiva recta de regresión:
plot(df$gdp_per_capita_log,df$hdi_for_year, ylab = "HDI por year", xlab = "GDP per capita",pch = 19,cex = 0.6)
abline(model2, col = "red")
Para evaluar la capacidad predictiva del modelo, se realiza una
validación cruzada con 10 submuestras utlizando la libreria
caret:
train_control <- trainControl(method = "cv", number = 10)
model_cv <- train(hdi_for_year~gdp_per_capita_log, data = na.omit(df), method = "lm", trControl = train_control)
print(model_cv)
## Linear Regression
##
## 8364 samples
## 1 predictor
##
## No pre-processing
## Resampling: Cross-Validated (10 fold)
## Summary of sample sizes: 7529, 7527, 7527, 7526, 7528, 7528, ...
## Resampling results:
##
## RMSE Rsquared MAE
## 0.03808609 0.8336506 0.03091247
##
## Tuning parameter 'intercept' was held constant at a value of TRUE
Dado que los resultados indican que el modelo tiene una capacidad predictiva considerable, y considerando las violaciones a los supuestos de la regresión lineal, se justifica utilizar las estimaciones del modelo para imputar los datos faltantes del HDI:
# Identificar los índices con datos faltantes
missing_indices <- which(is.na(df$hdi_for_year))
# Imputar los datos faltantes
df$hdi_for_year[missing_indices] <- predict(model2, newdata = df[missing_indices,])
Finalmente, confirmamos que la base de datos ya no presenta datos faltantes:
missmap(df)
## Warning: Unknown or uninitialised column: `arguments`.
## Unknown or uninitialised column: `arguments`.
## Warning: Unknown or uninitialised column: `imputations`.
En esta sección, se filtran los datos para obtener dos conjuntos de
datos específicos: uno para Colombia y otro para los Estados Unidos. Se
crean dos bases de datos llamadas master_col y
master_eu, que contienen solo los datos correspondientes a
cada país.
master_col <- df[df$country == "Colombia",]
master_col$country <- droplevels(master_col$country)
master_eu <- df[df$country == "United States",]
master_eu$country <- droplevels(master_eu$country)
master_col_eu <- rbind(master_col,master_eu)
table(master_col_eu$country)
##
## Colombia United States
## 372 372
Aquí, se realiza un análisis de la evolución de varios indicadores (suicidios por cada 100,000 habitantes, PIB per cápita e IDH) a lo largo de los años en ambos países. El cálculo se realiza agrupando los datos por año y país, y luego se calcula la tasa de suicidios ajustada por la población.
Suicides_years <- master_col_eu %>%
group_by(year, country) %>%
summarise(total_suicides = sum(suicides_no), population = sum(population), gdp_per_capita = mean(gdp_per_capita), hdi_for_year = mean(hdi_for_year))
## `summarise()` has grouped output by 'year'. You can override using the
## `.groups` argument.
Suicides_years <- Suicides_years %>%
mutate(suicidios_por_100k = (total_suicides / population) * 100000)
colnames(Suicides_years) <- c("year","Pais","Total_suicidios","Num_habitantes","PIB_per_capita","hdi_por_year","Suicidios_por_1000")
Suicides_years$year <- as.numeric(as.character(Suicides_years$year))
ggplot(Suicides_years, aes(x = year, y = Suicidios_por_1000,color = Pais, group = Pais)) +
geom_line(size = 1.2) + # Dibuja las líneas
geom_point(size = 2) + # Añade los puntos
labs(title = "Tasa de Suicidio por Cada 100,000 Habitantes (1985-2016)",
x = "year",
y = "Tasa de Suicidio (por 100,000 Habitantes)") +
scale_x_continuous(breaks = seq(min(Suicides_years$year), max(Suicides_years$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
ggplot(Suicides_years, aes(x = year, y = PIB_per_capita ,color = Pais, group = Pais)) +
geom_line(size = 1.2) + # Dibuja las líneas
geom_point(size = 2) + # Añade los puntos
labs(title = "PIB per capita de Colombia y Estados Unidos (1985-2016)",
x = "year",
y = "PIB per capita") +
scale_x_continuous(breaks = seq(min(Suicides_years$year), max(Suicides_years$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
ggplot(Suicides_years, aes(x = year, y = hdi_por_year ,color = Pais, group = Pais)) +
geom_line(size = 1.2) + # Dibuja las líneas
geom_point(size = 2) + # Añade los puntos
labs(title = "HID de Colombia y Estados Unidos (1985-2016)",
x = "year",
y = "HID por year") +
scale_x_continuous(breaks = seq(min(Suicides_years$year), max(Suicides_years$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
En esta sección, se examina cómo la evolución de los suicidios, el PIB per cápita y el IDH varía por género en cada país. Los datos se agrupan por año, género y país, y se calcula la tasa de suicidios por cada 100,000 habitantes.
sucides_year_sex <- master_col_eu%>%
group_by(year,sex,country)%>%
summarise(total_suicides = sum(suicides_no), population = sum(population),dp_per_capita = sum(gdp_per_capita), hdi_for_year = sum(hdi_for_year))
## `summarise()` has grouped output by 'year', 'sex'. You can override using the
## `.groups` argument.
sucides_year_sex <- sucides_year_sex %>%
mutate(suicidios_por_100k = (total_suicides / population) * 100000)
sucides_year_sex$sex <- str_replace(sucides_year_sex$sex, "female", "Mujeres")
sucides_year_sex$sex <- str_replace(sucides_year_sex$sex, "male", "Hombres")
colnames(sucides_year_sex) <- c("year","Sexo","Pais","Total_suicidios","Num_habitantes","PIB_per_capita","hdi_por_year","Suicidios_por_1000")
sucides_year_sex$Pais_Sexo <- paste(sucides_year_sex$Pais, sucides_year_sex$Sexo, sep = "-")
Ahora se presentaran los gráficos para cada indicador, diferenciados por género.
ggplot(sucides_year_sex, aes(x = year, y = Suicidios_por_1000, color = Pais_Sexo, group = Pais_Sexo)) +
geom_line(size = 1) +
geom_point(size = 2) +
labs(title = "Tasa de suicidio por cada 100,000 habitantes por país y sexo",
x = "year",
y = "Tasa de suicidio (por 100,000 habitantes)") +
scale_x_continuous(breaks = seq(min(sucides_year_sex$year), max(sucides_year_sex$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
ggplot(sucides_year_sex, aes(x = year, y = PIB_per_capita ,color = Pais_Sexo, group = Pais_Sexo)) +
geom_line(size = 1.2) +
geom_point(size = 2) +
labs(title = "PIB per capita por sexo (1985-2016)",
x = "year",
y = "PIB per capita") +
scale_x_continuous(breaks = seq(min(sucides_year_sex$year), max(sucides_year_sex$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
ggplot(sucides_year_sex, aes(x = year, y = hdi_por_year ,color = Pais_Sexo, group = Pais_Sexo)) +
geom_line(size = 1.2) + # Dibuja las líneas
geom_point(size = 2) + # Añade los puntos
labs(title = "PIB per capita por sexo (1985-2016)",
x = "year",
y = "PIB per capita") +
scale_x_continuous(breaks = seq(min(sucides_year_sex$year), max(sucides_year_sex$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
Primero, se agrupan los datos por año, grupo de edad y país. Se calculan los suicidios totales, la población total, el PIB per cápita y el IDH para cada combinación de estos factores. Luego, se calcula la tasa de suicidios por cada 100,000 habitantes.
sucides_year_age <- master_col_eu%>%
group_by(year,age,country)%>%
summarise(total_suicides = sum(suicides_no), population = sum(population),dp_per_capita = sum(gdp_per_capita), hdi_for_year = sum(hdi_for_year))
## `summarise()` has grouped output by 'year', 'age'. You can override using the
## `.groups` argument.
sucides_year_age <- sucides_year_age %>%
mutate(suicidios_por_100k = (total_suicides / population) * 100000)
Se realiza una normalización de los nombres de los rangos de edad para garantizar la consistencia en el análisis.
sucides_year_age$age <- str_replace(sucides_year_age$age , "15-24 years", "15-24 years")
sucides_year_age$age <- str_replace(sucides_year_age$age , "25-34 years", "25-34 years")
sucides_year_age$age <- str_replace(sucides_year_age$age , "35-54 years", "35-54 years")
sucides_year_age$age <- str_replace(sucides_year_age$age , "5-14 years", "5-14 years")
sucides_year_age$age <- str_replace(sucides_year_age$age , "55-74 years", "55-74 years")
sucides_year_age$age <- str_replace(sucides_year_age$age , "75+ years", "75+ years")
colnames(sucides_year_age) <- c("year","Rango_edad","Pais","Total_suicidios","Num_habitantes","PIB_per_capita","hdi_por_year","Suicidios_por_1000")
sucides_year_age$Pais_Age <- paste(sucides_year_age$Pais, sucides_year_age$Rango_edad, sep = "-")
Se genera un gráfico que muestra la evolución de la tasa de suicidios por cada 100,000 habitantes, desglosado por rango de edad en Colombia. Se utiliza geom_line para trazar las líneas y geom_point para marcar los puntos en cada año.
ggplot(sucides_year_age[sucides_year_age$Pais == "Colombia",], aes(x = year, y = Suicidios_por_1000, color = Rango_edad, group = Rango_edad)) +
geom_line(size = 1) +
geom_point(size = 2) +
labs(title = "Tasa de suicidio por cada 100,000 habitantes por rango de edad en Colombia",
x = "year",
y = "Tasa de suicidio (por 100,000 habitantes)") +
scale_x_continuous(breaks = seq(min(sucides_year_age$year), max(sucides_year_age$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
De manera similar, se genera un gráfico para los Estados Unidos que muestra la tasa de suicidios por grupo de edad.
ggplot(sucides_year_age[sucides_year_age$Pais == "United States",], aes(x = year, y = Suicidios_por_1000, color = Rango_edad, group = Rango_edad)) +
geom_line(size = 1) +
geom_point(size = 2) +
labs(title = "Tasa de suicidio por cada 100,000 habitantes por rango de edad en los US",
x = "year",
y = "Tasa de suicidio (por 100,000 habitantes)") +
scale_x_continuous(breaks = seq(min(sucides_year_age$year), max(sucides_year_age$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
Se crea un gráfico que muestra la evolución del PIB per cápita por grupo de edad en Colombia. Similar al gráfico de suicidios, se usa geom_line y geom_point.
ggplot(sucides_year_age[sucides_year_age$Pais == "Colombia",], aes(x = year, y = PIB_per_capita, color = Rango_edad, group = Rango_edad)) +
geom_line(size = 1) +
geom_point(size = 2) +
labs(title = "PIB per capita de Colombia por sexo (1985-2016)",
x = "year",
y = "PIB per capita") +
scale_x_continuous(breaks = seq(min(sucides_year_age$year), max(sucides_year_age$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
El gráfico correspondiente para Estados Unidos se genera de la misma manera.
ggplot(sucides_year_age[sucides_year_age$Pais == "United States",], aes(x = year, y = PIB_per_capita, color = Rango_edad, group = Rango_edad)) +
geom_line(size = 1) +
geom_point(size = 2) +
labs(title = "PIB per capita de US por sexo (1985-2016)",
x = "year",
y = "PIB per capita") +
scale_x_continuous(breaks = seq(min(sucides_year_age$year), max(sucides_year_age$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
Finalmente, se crea un gráfico para mostrar la evolución del IDH por grupo de edad en Colombia.
ggplot(sucides_year_age[sucides_year_age$Pais == "Colombia",], aes(x = year, y = hdi_por_year, color = Rango_edad, group = Rango_edad)) +
geom_line(size = 1) +
geom_point(size = 2) +
labs(title = "HDI por year de Colombia por rango de edad (1985-2016)",
x = "year",
y = "HDI por year") +
scale_x_continuous(breaks = seq(min(sucides_year_age$year), max(sucides_year_age$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
Se genera el gráfico equivalente para Estados Unidos.
ggplot(sucides_year_age[sucides_year_age$Pais == "United States",], aes(x = year, y = hdi_por_year, color = Rango_edad, group = Rango_edad)) +
geom_line(size = 1) +
geom_point(size = 2) +
labs(title = "HDI por year de US por rango de edad (1985-2016)",
x = "year",
y = "HDI por year") +
scale_x_continuous(breaks = seq(min(sucides_year_age$year), max(sucides_year_age$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
Durante esta actividad, se trabajara con una base titulada
Accidentalidad en Barranquilla la cual fue suministrada por
la Alcaldía
Distrital de Barranquilla y contiene información sobre accidentes de
tránsito ocurridos en el distrito de Barranquilla, obtenida de los
informes policiales de accidentes de tránsito (IPAT). Esta base de datos
incluye registros de accidentes que han sucedido en el área desde el
year 2018 hasta el 2024. Es importante destacar que la información de la
vigencia actual es preliminar y está sujeta a cambios, lo que implica
que los datos pueden ser actualizados o corregidos en el futuro. La base
de datos proporciona un registro detallado de cada accidente,
permitiendo realizar análisis sobre la frecuencia, severidad y ubicación
de los accidentes en la ciudad.
df <- read_csv("C:/Users/jcami/OneDrive/Escritorio/DATAVIZ/Accidentalidad_en_Barranquilla_20240826.csv", col_names = TRUE)
df %<>% clean_names
El estudio preliminar de la base de datos nos muestra contiene 11 varibales y 25610 observaciones. El estudio superfical de las varibales indica que alguna de ellas necesitaran ser normalizadas, renomabradas, o cambiar su formato para facilitar los analisis posteriores.
dim(df)
## [1] 25610 11
knitr::kable(descr_df)
| Nombre_original | Nombre_recodificado | Tipo_original | Tipo_modificado |
|---|---|---|---|
| fecha_accidente | Fecha | Fecha | Fecha |
| hora_accidente | Hora | Cadena | Hora |
| gravedad_accidente | Gravedad | Cadena | Factor |
| clase_accidente | Clase | Cadena | Factor |
| sitio_exacto_accidente | Sitio | Cadena | Cadena |
| cant_heridos_en_sitio_accidente | Heridos | Númerico | Númerico |
| cant_muertos_en_sitio_accidente | Muertos | Númerico | Númerico |
| cantidad_accidentes | Cantidad | Númerico | Númerico |
| ano_accidente | year | Númerico | Númerico |
| mes_accidente | Mes | Cadena | Factor |
| dia_accidente | Dia | Cadena | Factor |
Con tal de examinar de manera los datos de almacenados en cada una de
las variables y detarminar la presencia de datos faltantes se utiliza la
función Summary de base en R:
summary(df)
## fecha_accidente hora_accidente gravedad_accidente
## Min. :2018-01-01 00:00:00.00 Length:25610 Length:25610
## 1st Qu.:2019-02-02 00:00:00.00 Class :character Class :character
## Median :2020-04-23 12:00:00.00 Mode :character Mode :character
## Mean :2020-07-31 19:57:36.05
## 3rd Qu.:2021-12-13 00:00:00.00
## Max. :2024-06-30 00:00:00.00
##
## clase_accidente sitio_exacto_accidente cant_heridos_en_sitio_accidente
## Length:25610 Length:25610 Min. : 1.000
## Class :character Class :character 1st Qu.: 1.000
## Mode :character Mode :character Median : 1.000
## Mean : 1.472
## 3rd Qu.: 2.000
## Max. :42.000
## NA's :15626
## cant_muertos_en_sitio_accidente cantidad_accidentes ano_accidente
## Min. :1.000 Min. :1 Min. :2018
## 1st Qu.:1.000 1st Qu.:1 1st Qu.:2019
## Median :1.000 Median :1 Median :2020
## Mean :1.036 Mean :1 Mean :2020
## 3rd Qu.:1.000 3rd Qu.:1 3rd Qu.:2021
## Max. :2.000 Max. :2 Max. :2024
## NA's :25358
## mes_accidente dia_accidente
## Length:25610 Length:25610
## Class :character Class :character
## Mode :character Mode :character
##
##
##
##
Tal como se puede observar, no es posible detarminar la presencia de
datos faltantes o el número de observaciones por categoria en la
varibales tipo carácter por lo que más adelante se procede a cambiar el
tipo de dato y analizarlas más a detalla. Dicho esto, se puede observar
una cantidad considerable de datos faltantes en las varibales
cant_muertos_en_sitio_accidente y
cant_heridos_en_sitio_accidente, por lo cual se planifica
examinar diversos métodos de imputación de datos. Habiendo completado el
estudio superfical de la base de datos, ahora se estudiaran una a una
las varibales implicadas. No sin antes modificar el nombre de las
columnas y cambiar el tipo de datos de algunas varibales:
colnames(df) <- c("Fecha","Hora","Gravedad","Clase","Sitio","Heridos","Muertos","Cantidad","year","Mes","Dia")
selected_columns <- c("Gravedad","Clase","Mes","Dia")
df[selected_columns] <- lapply(df[selected_columns], as.factor)
df$Fecha <- as.Date(df$Fecha)
En primera instancia, la variable Fecha no muestra
problemas relacionados con la digitación o los datos faltantes:
knitr::kable(head(df[1:5],5))
| Fecha | Hora | Gravedad | Clase | Sitio |
|---|---|---|---|---|
| 2018-01-01 | 01:30:00:am | Con heridos | Atropello | CL 87 9H 24 |
| 2018-01-01 | 02:00:00:pm | Solo daños | Choque | CL 110 CR 46 |
| 2018-01-01 | 04:00:00:am | Solo daños | Choque | AV CIRCUNVALAR CR 9G |
| 2018-01-01 | 04:30:00:am | Solo daños | Choque | CLLE 72 CRA 29 |
| 2018-01-01 | 05:20:00:pm | Solo daños | Choque | VIA 40 CALLE 75 |
which(is.na(as.factor(df$Fecha)))
## integer(0)
Se concluira visualizando al variable por medio de un histograma:
ggplot(df, aes(x = Fecha)) +
geom_histogram(fill = "cyan4", color = "black") +
theme_minimal() +
labs(
title = "Histograma de los accidentes en Barranquilla por fecha",
x = "Fecha",
y = "Frecuencia de accidentes"
) +
theme(
plot.title = element_text(hjust = 0.5), # Centrar el título
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
En la vector Hora se almacenan las hora en que
sucedieron los accidentes. Comenzaremos cambiando el tipo de la variable
a hora utilizando el paquete lubridate. Para eso, debemos
normalizar el contenido de la varibale y suprimir caracteres que pueden
dificultar la conversión:
hora_modificada <- gsub(":(am|pm)$", " \\1", df$Hora) # Parsear la hora utilizando el formato correcto
hora_modificada <- parse_date_time(hora_modificada, orders = "I:M:S p") # Extraer solo la parte "HH:MM:SS" en formato de 24 horas
hora_modificada <- format(hora_modificada, "%H:%M:%S")
# Convertir a hms
df$Hora <- hms(hora_modificada)
rm(hora_modificada)
Hecho esto podemos asegurarnos que no hayan datos faltantes y calcular estadisticas descriptivas:
which(is.na(df$Hora))
## integer(0)
summary(df[2])
## Hora
## Min. :0S
## 1st Qu.:9H 30M 0S
## Median :13H 30M 0S
## Mean :13H 26M 30.5154236626331S
## 3rd Qu.:17H 30M 0S
## Max. :23H 58M 0S
A <- ggplot(df, aes(x = as.numeric(Hora))) +
geom_histogram(binwidth = 3600, fill = "cyan4", color = "black") +
scale_x_continuous(labels = function(x) format(hms::as_hms(x), "%H:%M:%S")) +
labs(title = "Histograma de Horas", x = "Hora del Dia", y = "Frecuencia") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5), # Centrar el título
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15)),
plot.margin = margin(10, 20, 10, 10)
)
B <- ggplot(df, aes(x = "", y = as.numeric(Hora))) +
geom_boxplot(fill = "cyan4", color = "black") +
scale_y_continuous(labels = function(x) format(hms::as_hms(x), "%H:%M:%S")) +
labs(title = "Boxplot de Horas", x = "", y = "Hora del Dia") +
theme_minimal() +
theme(
plot.title = element_text(hjust = 0.5), # Centrar el título
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15)),
plot.margin = margin(10, 10, 10, 20)
)
grid.arrange(A, B, ncol = 2)
Tal como su nombre lo indica la variable Gravedad indica
la gravedad del accidente. El análisis de esta variable iniciara
construyendo una tabla de frecuencia que nos ayudara a determinar el
número de observaciones en cada condición y la posible existencia de
datos faltantes.
table(df$Gravedad)
##
## Con heridos Con muertos Solo daños
## 9901 252 15457
Debido a que la tabla de frencuencia muestra que no hay datos faltantes en esta variable, procederemos a realizar una tabla con un conteo y el porcentaje de accidentes según su clase:
Tabla_gravedad <- df %>%
group_by(Gravedad) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_gravedad
## # A tibble: 3 × 4
## Gravedad n Proporcion Porcentaje
## <fct> <int> <dbl> <chr>
## 1 Con muertos 252 0.00984 1%
## 2 Con heridos 9901 0.387 39%
## 3 Solo daños 15457 0.604 60%
Podemos utilizar esta tabla para crear un diagrama de barras que nos permita visualizar la cantidad de accidentes segun su gravedad:
Tabla_gravedad$Gravedad <- factor(Tabla_gravedad$Gravedad,
levels = Tabla_gravedad$Gravedad[order(Tabla_gravedad$n, decreasing = TRUE)])
ggplot(Tabla_gravedad, aes(x = Gravedad, y = n)) +
geom_bar(width = 0.7, stat = "identity", position = position_dodge(0.7), fill = "cyan4") +
coord_cartesian(ylim = c(0, 20000)) +
ggtitle("Accidentes en Barranquilla segun su gravedad (2018-2024)") +
labs(x = "Gravedad", y = "Frecuencias") +
geom_text(aes(label = Porcentaje),
vjust = -0.5,
color = "black",
hjust = 0.5,
position = position_dodge(0.7),
angle = 0,
size = 4.5) +
scale_y_continuous(labels = scales::label_number(scale = 1e-3, suffix = "K")) +
theme(
axis.text.x = element_text(angle = 0, vjust = 1, hjust = 0.5),
axis.title.x = element_text(margin = margin(t = 20)),
axis.title.y = element_text(margin = margin(r = 20)),
plot.title = element_text(size = 14,vjust = 2,hjust = 0.5)
)+
theme_minimal()
La varibale Clase indica la clase de accidente. Tal como
en el caso anterior, construimos una tabla de frecuencias para verificar
el número de observaciones por condición y se cuentan con datos
faltantes:
table(df$Clase)
##
## Atropello Caida Ocupante Choque Incendio Otro
## 1344 194 23819 13 123
## Volcamiento
## 117
Debido a que la tabla de frencuencia muestra que no hay datos faltantes en esta variable, procederemos a realizar una tabla con un conteo y el porcentaje de accidentes según su tipo:
df$Clase <- str_replace(df$Clase, "Caida Ocupante", "Caida")
Tabla_Clase <- df %>%
group_by(Clase) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_Clase
## # A tibble: 6 × 4
## Clase n Proporcion Porcentaje
## <chr> <int> <dbl> <chr>
## 1 Incendio 13 0.000508 0.051%
## 2 Volcamiento 117 0.00457 0.457%
## 3 Otro 123 0.00480 0.480%
## 4 Caida 194 0.00758 0.758%
## 5 Atropello 1344 0.0525 5.248%
## 6 Choque 23819 0.930 93.007%
Podemos utilizar esta tabla para crear un diagrama de barras que nos permita visualizar la cantidade de accidentes segun su clase:
Tabla_Clase$Clase <- factor(Tabla_Clase$Clase,
levels = Tabla_Clase$Clase[order(Tabla_Clase$n, decreasing = TRUE)])
ggplot(Tabla_Clase, aes(x = Clase, y = n)) +
geom_bar(width = 0.7, stat = "identity", position = position_dodge(0.7), fill = "cyan4") +
coord_cartesian(ylim = c(0, 30000)) +
ggtitle("Accidentes en Barranquilla segun su clase (2018-2014)") +
labs(x = "Clase", y = "Frecuencias") +
geom_text(aes(label = Porcentaje),
vjust = -0.5,
color = "black",
hjust = 0.5,
position = position_dodge(0.7),
angle = 0,
size = 4.5) +
scale_y_continuous(labels = scales::label_number(scale = 1e-3, suffix = "K")) +
theme(
axis.text.x = element_text(angle = 0, vjust = 1, hjust = 0.5),
axis.title.x = element_text(margin = margin(t = 20)),
axis.title.y = element_text(margin = margin(r = 20)),
plot.title = element_text(size = 14,vjust = 2,hjust = 0.5)
)+
theme_minimal()
En lo que concierne al year del accidente (year)
procederemos a manera similar. Primer construiremos una tabla de
frecuencia para comprobar datos faltantes, calcularemos estadisticos
descriptivos, y finalizaramos vizualizando el número de accidentes a lo
largo de los years.
table(df$year)
##
## 2018 2019 2020 2021 2022 2023 2024
## 5898 5645 3281 4700 3683 1662 741
Tal que no se encuentran datos faltantes, se procede a construir la tabla de frecuencia con estadisticas descriptivas:
Tabla_year <- df %>%
group_by(year) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_year
## # A tibble: 7 × 4
## year n Proporcion Porcentaje
## <dbl> <int> <dbl> <chr>
## 1 2024 741 0.0289 2.89%
## 2 2023 1662 0.0649 6.49%
## 3 2020 3281 0.128 12.81%
## 4 2022 3683 0.144 14.38%
## 5 2021 4700 0.184 18.35%
## 6 2019 5645 0.220 22.04%
## 7 2018 5898 0.230 23.03%
Culminamos el estudio de esta varible construyendo su diagrama de barras:
ggplot(Tabla_year, aes(x = as.factor(year), y = n)) +
geom_bar(width = 0.7, stat = "identity", position = position_dodge(1), fill = "cyan4") +
coord_cartesian(ylim = c(0, 10000)) +
ggtitle("Accidentes en Barranquilla (2018-2014)") +
labs(x = "Year", y = "Frecuencias") +
geom_text(aes(label = Porcentaje),
vjust = -0.5,
color = "black",
hjust = 0.5,
position = position_dodge(1),
angle = 0,
size = 4.5) +
scale_y_continuous(labels = scales::label_number(scale = 1e-3, suffix = "K")) +
theme(
axis.text.x = element_text(angle = 0, vjust = 1, hjust = 0.5),
axis.title.x = element_text(margin = margin(t = 20)),
axis.title.y = element_text(margin = margin(r = 20)),
plot.title = element_text(size = 14,vjust = 2,hjust = 0.5)
)+
theme_minimal()
Tambien podemos construir un grafico de lineas que nos permite vizualizar más clara el número de accidentes en la ciudad a lo largo de los years:
ggplot(Tabla_year, aes(x = year, y = n)) +
geom_line(size = 1) +
geom_point(size = 2) +
labs(title = "Numero de accidentes en Barranquilla (2018-2024)",
x = "Year",
y = "Numero de accidentes") +
scale_x_continuous(breaks = seq(min(Tabla_year$year), max(Tabla_year$year), by = 1)) +
theme_minimal() +
theme(
axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1),
axis.title.x = element_text(margin = margin(t = 15)),
axis.title.y = element_text(margin = margin(r = 15))
)
Según la información suministrada junto a la base de datos, la
variable Cantidad indica la cantidad de accidentes en un
suceso particular. Debido a que es un conteo procedemos de manera
similar a las secciones anteriores, comenzado por construir una tabla de
frecuencia.
table(df$Cantidad)
##
## 1 2
## 25605 5
La tabla nos indica que la varibale no presenta datos faltantes y que la la modo es uno. Procedemos a construir una tabla con la proporción y porcentaje de observaciones en cada categoria.
Tabla_cantidad <- df %>%
group_by(Cantidad) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_cantidad
## # A tibble: 2 × 4
## Cantidad n Proporcion Porcentaje
## <dbl> <int> <dbl> <chr>
## 1 2 5 0.000195 0%
## 2 1 25605 1.00 100%
De manera inmediata que solo cinco observaciones tienen una cantidad de dos, lo cual representa alrededor del 0.01% de las observaciones totales. Es probable que estas observaciones hayan sido el resultado de un error durante la digitación.
knitr::kable(df[which(df$Cantidad == 2),][c(1,2,3,4,6,7,8,9)])
| Fecha | Hora | Gravedad | Clase | Heridos | Muertos | Cantidad | year |
|---|---|---|---|---|---|---|---|
| 2018-06-09 | 9H 35M 0S | Solo daños | Choque | NA | NA | 2 | 2018 |
| 2019-12-28 | 12H 28M 0S | Solo daños | Choque | NA | NA | 2 | 2019 |
| 2020-02-06 | 9H 0M 0S | Solo daños | Choque | NA | NA | 2 | 2020 |
| 2020-05-02 | 19H 40M 0S | Solo daños | Choque | NA | NA | 2 | 2020 |
| 2020-11-05 | 17H 25M 0S | Solo daños | Choque | NA | NA | 2 | 2020 |
Dicho esto, se considera que reemplazar dichas observaciones por la
moda no es lo adecuado. Esto es debido a que el resultado seria una
variables sin variación que en principio poco aportaria al ejercicio.
Con esto en mente, se procede a eliminar la variable
Cantidad de la base de datos.
df <- df[-8]
Procedemos de la misma manera para estudiar los meses en donde
ocurrienron accidentes (Mes):
table(df$Mes)
##
## April August December February January July June March
## 2010 1918 2189 2477 2349 1932 2103 2446
## May November October September
## 2121 1995 2090 1980
Tal que no se identifican datos faltantes se procede a construir la tabla de frecuencias.
Tabla_mes <- df %>%
group_by(Mes) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_mes
## # A tibble: 12 × 4
## Mes n Proporcion Porcentaje
## <fct> <int> <dbl> <chr>
## 1 August 1918 0.0749 7.489%
## 2 July 1932 0.0754 7.544%
## 3 September 1980 0.0773 7.731%
## 4 November 1995 0.0779 7.790%
## 5 April 2010 0.0785 7.848%
## 6 October 2090 0.0816 8.161%
## 7 June 2103 0.0821 8.212%
## 8 May 2121 0.0828 8.282%
## 9 December 2189 0.0855 8.547%
## 10 January 2349 0.0917 9.172%
## 11 March 2446 0.0955 9.551%
## 12 February 2477 0.0967 9.672%
En lo que respecta a la varibale Dia utilizamos el mismo
procedimiento anterior. Comenzamos inspeccionando la cantidad de
observaciones por condición:
table(df$Dia)
##
## Fri Mon Sat Sun Thu Tue Wed
## 3920 3774 3735 2577 3756 4009 3839
Debido a que no se encontraron datos faltantes, se procede a construir una tabla de frecuencia con estadisticos descriptivos:
Tabla_dia <- df %>%
group_by(Dia) %>%
count() %>%
ungroup() %>%
mutate(Proporcion = `n` / sum(`n`)) %>%
arrange(Proporcion) %>%
mutate(Porcentaje = scales::percent(Proporcion))
Tabla_dia
## # A tibble: 7 × 4
## Dia n Proporcion Porcentaje
## <fct> <int> <dbl> <chr>
## 1 Sun 2577 0.101 10.062%
## 2 Sat 3735 0.146 14.584%
## 3 Thu 3756 0.147 14.666%
## 4 Mon 3774 0.147 14.736%
## 5 Wed 3839 0.150 14.990%
## 6 Fri 3920 0.153 15.307%
## 7 Tue 4009 0.157 15.654%
Finalmente la variable sitio contine información de los
lugares en donde ocurrieron accidentes. Sin embargo, tal como se puede
observar a continuación, se suministran las direcciones de los lugares
sin datos de geolocalización que permitan señalar de manera precisisa el
lugar del suceso. En este caso, se considera inviable calcular medidas
descriptivas o estudiar la frecuencia de los datos de manera usual ya
que se encuentran errores de codificación y una gran cantidad de
categoiras.
knitr::kable(tail(df$Sitio,10))
| x |
|---|
| CALLE 111 CON CARRERA 37 |
| CALLE 19 CRA 6B |
| CALLE 30 CRA 14 |
| CALLE 30 CON CRA 13C |
| CARRERA 5C CALLE 90 |
| CARRERA 42G CALLE 90 |
| CALLE 116 CARRERA 38 |
| CALLE 56 FRENTE AL # 8E - 48 |
| CARRERA 43 CON CALLE 41 |
| CARRERA 8 CALLE 49 |
Debido a esto, esta varibale se describira apartir de mapas estaticos
que permitiran vizualizar la cantidad de accindentes de manera más
clara. Para esto utilizaremos la libreria de ggmap y las
API de google Could. Baste de decir que debido a gran volumen de datos
obtención de la coordenadas se realizo de manera automatica con las
siguientes funciones:
limpiar_direccion <- function(direccion) {
direccion <- str_to_upper(direccion) # Convertir a mayúsculas
direccion <- str_replace_all(direccion, "\\s+", " ") # Normalizar espacios
direccion <- str_replace_all(direccion, "\\bCR\\b", "CARRERA")
direccion <- str_replace_all(direccion, "\\bCL\\b", "CALLE")
direccion <- str_replace_all(direccion, "\\bAV\\b", "AVENIDA")
direccion <- str_replace_all(direccion, "\\bVIA\\b", "VIA")
direccion <- str_replace_all(direccion, "\\bCRA\\b", "CARRERA")
direccion <- str_replace_all(direccion, "\\s*CON\\s*", " CON ")
direccion <- str_replace_all(direccion, "\\s*#\\s*", " # ")
direccion <- str_trim(direccion)
+
direccion <- paste(direccion, "BARRANQUILLA")
return(direccion)
}
direcciones <- limpiar_direccion(df$Sitio) # Direcciones normalizadas
# Inicializar el contador global para iteraciones
contador <- 0
# Función para geocodificar una dirección y manejar errores
geocodificar_direccion <- function(direccion) {
tryCatch({
resultado <- suppressWarnings(suppressMessages(geocode(direccion, source = "google")))
if (is.na(resultado$lat) | is.na(resultado$lon)) {
return(data.frame(lat = NA, lon = NA))
}
return(resultado)
}, error = function(e) {
return(data.frame(lat = NA, lon = NA))
})
}
resultados <- lapply(seq_along(direcciones), function(i) {
contador <<- contador + 1
cat("Procesando iteración:", contador, "de", length(direcciones), "\n")
resultado <- geocodificar_direccion(direcciones[i])
return(resultado)
})
coordenadas_df <- do.call(rbind, resultados)
Una vez culminada la geolocalización procedemos a revisar si existen datos faltantes y constuir una base de datos que utilizaremos para crear los mapas:
coordenadas_df %>%
summarize(
Lon_NA = sum(is.na(lon)),
LAt_NA = sum(is.na(lat))
)
# Unir con las direcciones originales
resultados <- cbind(direcciones, coordenadas_df)
Apesar de la normalización, aun se encontraron algunoes errores el
geodecodificación. Por lo cual, se procedio revisar las coordenadas más
extremas y determinar la latitud y longitud aproximada de los lugares
utlizando Google Maps:
coordenadas <- data.frame(
indice = c(1823, 4322, 6332, 6935, 10912, 22409, 20209, 13749, 16066, 16255,
17410, 17527, 19494, 18426, 21651, 17980, 18341, 22494, 16299,
13132, 15642, 19094, 15189, 16089, 7393, 15695, 21454, 2836,
7719, 17800, 6122),
lon = c(-74.795060, -74.843081, -74.812223, -74.791578, -74.800250, -74.805110,
-74.821869, -74.802105, -74.836010, -74.770386, -74.765775, -74.844272,
-74.835221, -74.803440, -74.778708, -74.787420, -74.835940, -74.774765,
-74.836026, -74.781519, -74.835707, -74.891751, -74.810851, -74.835752,
-74.761275, -74.761275, -74.761275, -74.773021, -74.769029, -74.904925,
NA),
lat = c(10.918997, 11.015256, 10.922867, 10.989965, 11.022345, 10.923354,
10.925821, 10.960233, 10.981524, 10.985015, 10.969660, 10.997190,
10.978436, 10.922918, 10.987049, 10.963814, 10.980279, 10.972310,
10.980032, 10.976462, 11.018203, 10.956987, 10.951522, 10.982615,
10.950376, 10.950376, 10.950376, 10.955540, 10.952123, 10.951866,
NA)
)
for (i in 1:nrow(coordenadas)) {
resultados$lon[coordenadas$indice[i]] <- coordenadas$lon[i]
resultados$lat[coordenadas$indice[i]] <- coordenadas$lat[i]
}
knitr::kable(head(resultados,5))
| direcciones | lon | lat |
|---|---|---|
| CALLE 87 9H 24 BARRANQUILLA | -74.82560 | 10.95923 |
| CALLE 110 CARRERA 46 BARRANQUILLA | -74.83095 | 11.03326 |
| AVENIDA CIRCUNVALAR CARRERA 9G BARRANQUILLA | -74.83612 | 10.95671 |
| CLLE 72 CARRERA 29 BARRANQUILLA | -74.81184 | 10.97874 |
| VIA 40 CALLE 75 BARRANQUILLA | -74.79308 | 11.01285 |
Habiendo preparado los datos de geolocalización solo no queda
construir el mapa utilizando a libreria de ggmap y las API
de google Could:
myMap <- get_map(location = "Barranquilla", zoom = 12)
ggmap(myMap) +
stat_density2d(data = resultados,
aes(x = lon, y = lat, fill = ..level.., alpha = ..level..),
size = 0.01, bins = 20, geom = "polygon") +
scale_fill_gradient(low = "green", high = "red",name = "Accidentes") +
scale_alpha(guide = FALSE) +
ggtitle("Mapa de Accidentes en Barranquilla (2018-2024)") +
labs(x = "Longitud", y = "Latitud") +
theme(
plot.title = element_text(hjust = 0.5, size = 12, vjust = 2),
axis.title.x = element_text(margin = margin(t = 10)),
axis.title.y = element_text(margin = margin(r = 10)),
legend.title = element_text(hjust = 1)
)
table(df$Heridos)
##
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
## 6911 2301 469 155 57 29 14 9 6 7 6 7 2 2 1 1
## 18 19 20 21 22 23 42
## 1 1 1 1 1 1 1
Ahora procedemos a examinar por posible datos faltantes:
length(which(is.na(df$Heridos)))
## [1] 15626
Los resultados nos muestran que hacen faltan 15626 observaciones en
la variable Heridos, alrededor de un 61% del número total
del observaciones. Procedemos a examinar cinco de ellas:
head(df[which(is.na(df$Heridos)),],5)
## # A tibble: 5 × 10
## Fecha Hora Gravedad Clase Sitio Heridos Muertos year Mes Dia
## <date> <Period> <fct> <chr> <chr> <dbl> <dbl> <dbl> <fct> <fct>
## 1 2018-01-01 14H 0M 0S Solo daños Choq… CL 1… NA NA 2018 Janu… Mon
## 2 2018-01-01 4H 0M 0S Solo daños Choq… AV C… NA NA 2018 Janu… Mon
## 3 2018-01-01 4H 30M 0S Solo daños Choq… CLLE… NA NA 2018 Janu… Mon
## 4 2018-01-01 17H 20M 0S Solo daños Choq… VIA … NA NA 2018 Janu… Mon
## 5 2018-01-02 14H 30M 0S Solo daños Choq… CARR… NA NA 2018 Janu… Tue
La tabla sugiere que los datos faltantes en la variable
Heridos pueden estar relacionadas con la variable
Gravedad, por lo cual se prodera a agrupar los datos según
la gravedad y calcularan algunas estadisticas descriptivas de los datos
faltantes:
df %>%
group_by(Gravedad) %>%
summarise(
total = n(),
Casos = sum(is.na(Heridos)),
Proporcion = round(mean(is.na(Heridos)),2),
Procentaje = round(mean(is.na(Heridos)) * 100,3 ))
## # A tibble: 3 × 5
## Gravedad total Casos Proporcion Procentaje
## <fct> <int> <int> <dbl> <dbl>
## 1 Con heridos 9901 0 0 0
## 2 Con muertos 252 169 0.67 67.1
## 3 Solo daños 15457 15457 1 100
Resulta evidente que el número de datos faltantes esta relacionado
con la gravedad del accidente. Vemos por ejemplo que no hay datos
faltantes en la categoria de “con heridos”, mientras que no datos sobre
el número de heridos en la categoria de “solo dyears”. Este tipo de
datos faltantes se podría considerar como datos “no al azar”
(MANAR - Missing Not at Random), ya que la ausencia de
datos parece depender directamente de la gravedad del accidente. Esto
implica que el tratamiento de estos datos faltantes debe hacerse con
cuidado, y probablemente no se deba imputar o ignorar sin una estrategia
que considere la estructura de los datos y su relación con la variable
Gravedad.
En este caso comenzaremos por reemplazar los NA con ceros en la
categoría de “Solo dyears”. Esto se debe a que la ausencia de datos en
la variable Heridos podría interpretarse como que no hubo
heridos, lo cual es coherente con la categoría “Solo dyears”.
df <- df %>%
mutate(Heridos = ifelse((Gravedad != "Con heridos" | Gravedad != "Con muertos" )& is.na(Heridos), 0, Heridos))
df %>%
group_by(Gravedad) %>%
summarise(
total = n(),
Casos = sum(is.na(Heridos)),
Proporcion = round(mean(is.na(Heridos)),2),
Procentaje = round(mean(is.na(Heridos)) * 100,3 ))
## # A tibble: 3 × 5
## Gravedad total Casos Proporcion Procentaje
## <fct> <int> <int> <dbl> <dbl>
## 1 Con heridos 9901 0 0 0
## 2 Con muertos 252 0 0 0
## 3 Solo daños 15457 0 0 0
Dado que, por el momento, no contamos con suficiente información para
tratar con los faltantes en la categoria de “Con muestros” el analisis
de la varibale Heridos se suspendera para analizar el
comportamiento de los datos faltantes en al varibale
Muertos.
En la base de datos en cuestión, la varibale Muertos
indica el número de fallecimiento en un determinado accidente.
Procedemos de manera parecida a la variable anterior.
table(df$Muertos)
##
## 1 2
## 243 9
En un primer momento, observamos que solo en dos casos la cantidad de fallecidos fue de cinco, mientras que los accidentes restantes (de los cuales se tienen datos) solo resultaron en un fallecimiento.Ahora procedemos a revisar el número de datos faltantes:
length(which(is.na(df$Muertos)))
## [1] 25358
Tal como en la varibale anterior, los resultados nos muestran que
hacen faltan 25358 observaciones en la variable Muertos,
alrededor de un 99% del número total de observaciones. Procedemos a
examinar cinco de ellas:
head(df[which(is.na(df$Muertos)),],5)
## # A tibble: 5 × 10
## Fecha Hora Gravedad Clase Sitio Heridos Muertos year Mes Dia
## <date> <Period> <fct> <chr> <chr> <dbl> <dbl> <dbl> <fct> <fct>
## 1 2018-01-01 1H 30M 0S Con herid… Atro… CL 8… 1 NA 2018 Janu… Mon
## 2 2018-01-01 14H 0M 0S Solo daños Choq… CL 1… 0 NA 2018 Janu… Mon
## 3 2018-01-01 4H 0M 0S Solo daños Choq… AV C… 0 NA 2018 Janu… Mon
## 4 2018-01-01 4H 30M 0S Solo daños Choq… CLLE… 0 NA 2018 Janu… Mon
## 5 2018-01-01 17H 20M 0S Solo daños Choq… VIA … 0 NA 2018 Janu… Mon
Entonces se observa que una gran proporción de los faltantes podrian estar relacionados con la gravedad del accidente. Por lo cual, se construira una tabla de frecuencia agrupada por la gravedad para estudiar la proporción de faltantes en cada condición:
df %>%
group_by(Gravedad) %>%
summarise(
total = n(),
Casos = sum(is.na(Muertos)),
Proporcion = round(mean(is.na(Muertos)),2),
Procentaje = round(mean(is.na(Muertos)) * 100,3 ))
## # A tibble: 3 × 5
## Gravedad total Casos Proporcion Procentaje
## <fct> <int> <int> <dbl> <dbl>
## 1 Con heridos 9901 9901 1 100
## 2 Con muertos 252 0 0 0
## 3 Solo daños 15457 15457 1 100
Una vez más, los datos faltantes parecen estar fuertemente
relacionados con la gravedad del accidente. En este caso, las categorías
“Solo dyears” y “Con heridos” no tienen datos para la variable Muertos.
Naturalmente, esto indica que los datos faltantes no son
MAR (Missing At Random) y la imputación no es una
estrategia adecuada en este contexto. Además, la estructura de los datos
faltantes sugiere que el registro de heridos y muertos está determinado
por la gravedad del accidente.
Como hipótesis, es posible que en los casos en que la gravedad del accidente fue “Con muertos”, se hayan involucrado personas que, aunque no fallecieron, resultaron heridas, por lo que se registran valores en ambas variables. Sin embargo, si el accidente solo resultó en personas heridas, tiene sentido que solo se reporte este número, y los datos sobre muertos sean faltantes. Asimismo, si el accidente solo involucró dyears materiales, ambas variables Heridos y Muertos deberían estar faltantes. Esto explicaría la estructura encontrada.
df <- df %>%
mutate(Muertos = ifelse(Gravedad != "Con muertos" & is.na(Muertos), 0, Muertos))
df %>%
group_by(Gravedad) %>%
summarise(
total = n(),
Casos = sum(is.na(Muertos)),
Proporcion = round(mean(is.na(Muertos)),2),
Procentaje = round(mean(is.na(Muertos)) * 100,3 ))
## # A tibble: 3 × 5
## Gravedad total Casos Proporcion Procentaje
## <fct> <int> <int> <dbl> <dbl>
## 1 Con heridos 9901 0 0 0
## 2 Con muertos 252 0 0 0
## 3 Solo daños 15457 0 0 0
summary(df)
## Fecha Hora Gravedad
## Min. :2018-01-01 Min. :0S Con heridos: 9901
## 1st Qu.:2019-02-02 1st Qu.:9H 30M 0S Con muertos: 252
## Median :2020-04-23 Median :13H 30M 0S Solo daños :15457
## Mean :2020-07-31 Mean :13H 26M 30.5154236626331S
## 3rd Qu.:2021-12-13 3rd Qu.:17H 30M 0S
## Max. :2024-06-30 Max. :23H 58M 0S
##
## Clase Sitio Heridos Muertos
## Length:25610 Length:25610 Min. : 0.0000 Min. :0.00000
## Class :character Class :character 1st Qu.: 0.0000 1st Qu.:0.00000
## Mode :character Mode :character Median : 0.0000 Median :0.00000
## Mean : 0.5737 Mean :0.01019
## 3rd Qu.: 1.0000 3rd Qu.:0.00000
## Max. :42.0000 Max. :2.00000
##
## year Mes Dia
## Min. :2018 February: 2477 Fri:3920
## 1st Qu.:2019 March : 2446 Mon:3774
## Median :2020 January : 2349 Sat:3735
## Mean :2020 December: 2189 Sun:2577
## 3rd Qu.:2021 May : 2121 Thu:3756
## Max. :2024 June : 2103 Tue:4009
## (Other) :11925 Wed:3839
En esta sección trataremos con los posibles datos atipicos de que
puden existir en las varibales Heridos y
Muertos. Para esto se seguira el siguiente protocolo 1) se
determinan si existens datos atipicos utilizando graficos, estadisiticos
descriptivos, y pruebas analiticas, 2) se reemplazaran por datos
atipicos en el caso de que sean un baja proporción, y 3) se utilizaran
multiples tecnicas de imputación.
df%>%
get_summary_stats(Muertos, type = "five_number")
## # A tibble: 1 × 7
## variable n min max q1 median q3
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Muertos 25610 0 2 0 0 0
boxplot(df$Muertos)
hist(df$Muertos)
Los digramas de cajas y el histograma muestran que los valores de 1 y 2 pueden ser posibles candidatos atipicos. En particular se estarian considerando un total de 252 observaciones (aproximadamente 1% del total).
length(which(df$Muertos > 0))
## [1] 252
lower_bound <- median(df$Muertos) - 3 * mad(df$Muertos, constant = 1)
upper_bound <- median(df$Muertos) + 3 * mad(df$Muertos, constant = 1)
outlier_ind <- which(df$Muertos< lower_bound | df$Muertos > upper_bound)
rm(lower_bound)
rm(upper_bound)
length(outlier_ind)
## [1] 252
rosnerTest(df$Muertos, k = 252)
## Warning in rosnerTest(df$Muertos, k = 252): The true Type I error may be larger than assumed.
## Although the help file for 'rosnerTest' has a table with information
## on the estimated Type I error level,
## simulations were not run for k > 10 or k > floor(n/2).
##
## Results of Outlier Test
## -------------------------
##
## Test Method: Rosner's Test for Outliers
##
## Hypothesized Distribution: Normal
##
## Data: df$Muertos
##
## Sample Size: 25610
##
## Test Statistics: R.1 = 19.15516
## R.2 = 19.29426
## R.3 = 19.43643
## R.4 = 19.58180
## R.5 = 19.73047
## R.6 = 19.88259
## R.7 = 20.03828
## R.8 = 20.19768
## R.9 = 20.36095
## R.10 = 10.21518
## R.11 = 10.23626
## R.12 = 10.25748
## R.13 = 10.27882
## R.14 = 10.30030
## R.15 = 10.32192
## R.16 = 10.34367
## R.17 = 10.36557
## R.18 = 10.38760
## R.19 = 10.40977
## R.20 = 10.43208
## R.21 = 10.45454
## R.22 = 10.47715
## R.23 = 10.49990
## R.24 = 10.52280
## R.25 = 10.54585
## R.26 = 10.56905
## R.27 = 10.59241
## R.28 = 10.61592
## R.29 = 10.63959
## R.30 = 10.66342
## R.31 = 10.68741
## R.32 = 10.71156
## R.33 = 10.73588
## R.34 = 10.76036
## R.35 = 10.78502
## R.36 = 10.80984
## R.37 = 10.83483
## R.38 = 10.86000
## R.39 = 10.88534
## R.40 = 10.91087
## R.41 = 10.93657
## R.42 = 10.96245
## R.43 = 10.98852
## R.44 = 11.01478
## R.45 = 11.04123
## R.46 = 11.06786
## R.47 = 11.09470
## R.48 = 11.12172
## R.49 = 11.14895
## R.50 = 11.17638
## R.51 = 11.20401
## R.52 = 11.23184
## R.53 = 11.25989
## R.54 = 11.28814
## R.55 = 11.31661
## R.56 = 11.34530
## R.57 = 11.37420
## R.58 = 11.40333
## R.59 = 11.43268
## R.60 = 11.46226
## R.61 = 11.49207
## R.62 = 11.52212
## R.63 = 11.55240
## R.64 = 11.58292
## R.65 = 11.61369
## R.66 = 11.64470
## R.67 = 11.67596
## R.68 = 11.70747
## R.69 = 11.73924
## R.70 = 11.77127
## R.71 = 11.80357
## R.72 = 11.83613
## R.73 = 11.86896
## R.74 = 11.90207
## R.75 = 11.93546
## R.76 = 11.96912
## R.77 = 12.00308
## R.78 = 12.03732
## R.79 = 12.07186
## R.80 = 12.10670
## R.81 = 12.14185
## R.82 = 12.17730
## R.83 = 12.21306
## R.84 = 12.24914
## R.85 = 12.28554
## R.86 = 12.32227
## R.87 = 12.35933
## R.88 = 12.39673
## R.89 = 12.43446
## R.90 = 12.47255
## R.91 = 12.51098
## R.92 = 12.54978
## R.93 = 12.58894
## R.94 = 12.62846
## R.95 = 12.66836
## R.96 = 12.70864
## R.97 = 12.74931
## R.98 = 12.79037
## R.99 = 12.83183
## R.100 = 12.87370
## R.101 = 12.91597
## R.102 = 12.95867
## R.103 = 13.00180
## R.104 = 13.04535
## R.105 = 13.08935
## R.106 = 13.13380
## R.107 = 13.17870
## R.108 = 13.22407
## R.109 = 13.26990
## R.110 = 13.31622
## R.111 = 13.36303
## R.112 = 13.41033
## R.113 = 13.45814
## R.114 = 13.50646
## R.115 = 13.55531
## R.116 = 13.60469
## R.117 = 13.65462
## R.118 = 13.70510
## R.119 = 13.75614
## R.120 = 13.80776
## R.121 = 13.85996
## R.122 = 13.91276
## R.123 = 13.96617
## R.124 = 14.02020
## R.125 = 14.07486
## R.126 = 14.13016
## R.127 = 14.18612
## R.128 = 14.24275
## R.129 = 14.30007
## R.130 = 14.35808
## R.131 = 14.41681
## R.132 = 14.47626
## R.133 = 14.53645
## R.134 = 14.59740
## R.135 = 14.65912
## R.136 = 14.72163
## R.137 = 14.78495
## R.138 = 14.84910
## R.139 = 14.91408
## R.140 = 14.97993
## R.141 = 15.04665
## R.142 = 15.11428
## R.143 = 15.18283
## R.144 = 15.25231
## R.145 = 15.32276
## R.146 = 15.39420
## R.147 = 15.46664
## R.148 = 15.54012
## R.149 = 15.61465
## R.150 = 15.69027
## R.151 = 15.76699
## R.152 = 15.84486
## R.153 = 15.92388
## R.154 = 16.00410
## R.155 = 16.08555
## R.156 = 16.16825
## R.157 = 16.25224
## R.158 = 16.33756
## R.159 = 16.42423
## R.160 = 16.51230
## R.161 = 16.60180
## R.162 = 16.69276
## R.163 = 16.78525
## R.164 = 16.87928
## R.165 = 16.97492
## R.166 = 17.07219
## R.167 = 17.17116
## R.168 = 17.27188
## R.169 = 17.37438
## R.170 = 17.47873
## R.171 = 17.58499
## R.172 = 17.69320
## R.173 = 17.80344
## R.174 = 17.91577
## R.175 = 18.03025
## R.176 = 18.14695
## R.177 = 18.26595
## R.178 = 18.38732
## R.179 = 18.51114
## R.180 = 18.63749
## R.181 = 18.76648
## R.182 = 18.89817
## R.183 = 19.03268
## R.184 = 19.17010
## R.185 = 19.31054
## R.186 = 19.45412
## R.187 = 19.60094
## R.188 = 19.75115
## R.189 = 19.90485
## R.190 = 20.06221
## R.191 = 20.22335
## R.192 = 20.38844
## R.193 = 20.55764
## R.194 = 20.73113
## R.195 = 20.90908
## R.196 = 21.09170
## R.197 = 21.27918
## R.198 = 21.47176
## R.199 = 21.66966
## R.200 = 21.87313
## R.201 = 22.08245
## R.202 = 22.29789
## R.203 = 22.51977
## R.204 = 22.74840
## R.205 = 22.98414
## R.206 = 23.22737
## R.207 = 23.47848
## R.208 = 23.73792
## R.209 = 24.00616
## R.210 = 24.28369
## R.211 = 24.57108
## R.212 = 24.86893
## R.213 = 25.17787
## R.214 = 25.49862
## R.215 = 25.83195
## R.216 = 26.17870
## R.217 = 26.53980
## R.218 = 26.91627
## R.219 = 27.30923
## R.220 = 27.71992
## R.221 = 28.14971
## R.222 = 28.60014
## R.223 = 29.07290
## R.224 = 29.56991
## R.225 = 30.09331
## R.226 = 30.64552
## R.227 = 31.22930
## R.228 = 31.84776
## R.229 = 32.50449
## R.230 = 33.20359
## R.231 = 33.94983
## R.232 = 34.74876
## R.233 = 35.60688
## R.234 = 36.53189
## R.235 = 37.53295
## R.236 = 38.62109
## R.237 = 39.80970
## R.238 = 41.11529
## R.239 = 42.55836
## R.240 = 44.16490
## R.241 = 45.96829
## R.242 = 48.01231
## R.243 = 50.35573
## R.244 = 53.07961
## R.245 = 56.29942
## R.246 = 60.18661
## R.247 = 65.00897
## R.248 = 71.21376
## R.249 = 79.61941
## R.250 = 91.93657
## R.251 = 112.59885
## R.252 = 159.23881
##
## Test Statistic Parameter: k = 252
##
## Alternative Hypothesis: Up to 252 observations are not
## from the same Distribution.
##
## Type I Error: 5%
##
## Number of Outliers Detected: 252
##
## i Mean.i SD.i Value Obs.Num R.i+1 lambda.i+1 Outlier
## 1 0 1.019133e-02 0.103878487 2 1295 19.15516 4.757289 TRUE
## 2 1 1.011363e-02 0.103133613 2 3501 19.29426 4.757281 TRUE
## 3 2 1.003593e-02 0.102383202 2 7088 19.43643 4.757273 TRUE
## 4 3 9.958215e-03 0.101627131 2 11470 19.58180 4.757265 TRUE
## 5 4 9.880497e-03 0.100865273 2 18070 19.73047 4.757257 TRUE
## 6 5 9.802773e-03 0.100097497 2 20074 19.88259 4.757249 TRUE
## 7 6 9.725043e-03 0.099323664 2 20361 20.03828 4.757241 TRUE
## 8 7 9.647307e-03 0.098543632 2 25050 20.19768 4.757233 TRUE
## 9 8 9.569565e-03 0.097757253 2 25342 20.36095 4.757225 TRUE
## 10 9 9.491817e-03 0.096964372 1 69 10.21518 4.757217 TRUE
## 11 10 9.453125e-03 0.096768431 1 288 10.23626 4.757209 TRUE
## 12 11 9.414430e-03 0.096572062 1 293 10.25748 4.757201 TRUE
## 13 12 9.375732e-03 0.096375261 1 349 10.27882 4.757194 TRUE
## 14 13 9.337032e-03 0.096178027 1 522 10.30030 4.757186 TRUE
## 15 14 9.298328e-03 0.095980357 1 624 10.32192 4.757178 TRUE
## 16 15 9.259621e-03 0.095782247 1 813 10.34367 4.757170 TRUE
## 17 16 9.220911e-03 0.095583696 1 989 10.36557 4.757162 TRUE
## 18 17 9.182198e-03 0.095384700 1 1045 10.38760 4.757154 TRUE
## 19 18 9.143482e-03 0.095185257 1 1315 10.40977 4.757146 TRUE
## 20 19 9.104763e-03 0.094985363 1 1520 10.43208 4.757138 TRUE
## 21 20 9.066041e-03 0.094785017 1 1537 10.45454 4.757130 TRUE
## 22 21 9.027316e-03 0.094584214 1 1730 10.47715 4.757122 TRUE
## 23 22 8.988588e-03 0.094382953 1 1760 10.49990 4.757114 TRUE
## 24 23 8.949857e-03 0.094181230 1 1823 10.52280 4.757106 TRUE
## 25 24 8.911123e-03 0.093979042 1 2009 10.54585 4.757098 TRUE
## 26 25 8.872386e-03 0.093776386 1 2104 10.56905 4.757091 TRUE
## 27 26 8.833646e-03 0.093573260 1 2120 10.59241 4.757083 TRUE
## 28 27 8.794903e-03 0.093369660 1 2577 10.61592 4.757075 TRUE
## 29 28 8.756157e-03 0.093165582 1 2767 10.63959 4.757067 TRUE
## 30 29 8.717407e-03 0.092961025 1 2835 10.66342 4.757059 TRUE
## 31 30 8.678655e-03 0.092755984 1 3014 10.68741 4.757051 TRUE
## 32 31 8.639900e-03 0.092550456 1 3238 10.71156 4.757043 TRUE
## 33 32 8.601142e-03 0.092344439 1 3521 10.73588 4.757035 TRUE
## 34 33 8.562380e-03 0.092137928 1 3897 10.76036 4.757027 TRUE
## 35 34 8.523616e-03 0.091930921 1 4079 10.78502 4.757019 TRUE
## 36 35 8.484848e-03 0.091723415 1 4109 10.80984 4.757011 TRUE
## 37 36 8.446078e-03 0.091515405 1 4187 10.83483 4.757003 TRUE
## 38 37 8.407305e-03 0.091306888 1 4294 10.86000 4.756995 TRUE
## 39 38 8.368528e-03 0.091097861 1 4509 10.88534 4.756988 TRUE
## 40 39 8.329749e-03 0.090888321 1 4519 10.91087 4.756980 TRUE
## 41 40 8.290966e-03 0.090678263 1 4633 10.93657 4.756972 TRUE
## 42 41 8.252180e-03 0.090467685 1 4768 10.96245 4.756964 TRUE
## 43 42 8.213392e-03 0.090256582 1 4792 10.98852 4.756956 TRUE
## 44 43 8.174600e-03 0.090044951 1 5268 11.01478 4.756948 TRUE
## 45 44 8.135805e-03 0.089832787 1 5277 11.04123 4.756940 TRUE
## 46 45 8.097008e-03 0.089620089 1 5654 11.06786 4.756932 TRUE
## 47 46 8.058207e-03 0.089406850 1 5906 11.09470 4.756924 TRUE
## 48 47 8.019403e-03 0.089193068 1 6301 11.12172 4.756916 TRUE
## 49 48 7.980596e-03 0.088978739 1 6426 11.14895 4.756908 TRUE
## 50 49 7.941786e-03 0.088763859 1 6541 11.17638 4.756900 TRUE
## 51 50 7.902973e-03 0.088548423 1 6662 11.20401 4.756892 TRUE
## 52 51 7.864157e-03 0.088332427 1 6861 11.23184 4.756884 TRUE
## 53 52 7.825338e-03 0.088115869 1 6980 11.25989 4.756876 TRUE
## 54 53 7.786516e-03 0.087898742 1 7217 11.28814 4.756869 TRUE
## 55 54 7.747691e-03 0.087681044 1 7531 11.31661 4.756861 TRUE
## 56 55 7.708863e-03 0.087462769 1 7535 11.34530 4.756853 TRUE
## 57 56 7.670032e-03 0.087243914 1 8153 11.37420 4.756845 TRUE
## 58 57 7.631198e-03 0.087024474 1 8296 11.40333 4.756837 TRUE
## 59 58 7.592361e-03 0.086804445 1 8598 11.43268 4.756829 TRUE
## 60 59 7.553520e-03 0.086583821 1 8659 11.46226 4.756821 TRUE
## 61 60 7.514677e-03 0.086362600 1 8688 11.49207 4.756813 TRUE
## 62 61 7.475831e-03 0.086140775 1 8698 11.52212 4.756805 TRUE
## 63 62 7.436981e-03 0.085918343 1 8699 11.55240 4.756797 TRUE
## 64 63 7.398129e-03 0.085695298 1 8962 11.58292 4.756789 TRUE
## 65 64 7.359273e-03 0.085471636 1 9347 11.61369 4.756781 TRUE
## 66 65 7.320415e-03 0.085247352 1 9359 11.64470 4.756773 TRUE
## 67 66 7.281553e-03 0.085022440 1 9440 11.67596 4.756765 TRUE
## 68 67 7.242689e-03 0.084796897 1 9645 11.70747 4.756757 TRUE
## 69 68 7.203821e-03 0.084570717 1 9795 11.73924 4.756749 TRUE
## 70 69 7.164950e-03 0.084343894 1 10029 11.77127 4.756742 TRUE
## 71 70 7.126077e-03 0.084116424 1 10088 11.80357 4.756734 TRUE
## 72 71 7.087200e-03 0.083888301 1 10103 11.83613 4.756726 TRUE
## 73 72 7.048320e-03 0.083659521 1 10203 11.86896 4.756718 TRUE
## 74 73 7.009437e-03 0.083430076 1 10220 11.90207 4.756710 TRUE
## 75 74 6.970551e-03 0.083199963 1 10245 11.93546 4.756702 TRUE
## 76 75 6.931662e-03 0.082969175 1 10939 11.96912 4.756694 TRUE
## 77 76 6.892770e-03 0.082737707 1 11174 12.00308 4.756686 TRUE
## 78 77 6.853875e-03 0.082505554 1 11181 12.03732 4.756678 TRUE
## 79 78 6.814977e-03 0.082272708 1 11308 12.07186 4.756670 TRUE
## 80 79 6.776076e-03 0.082039165 1 11310 12.10670 4.756662 TRUE
## 81 80 6.737172e-03 0.081804918 1 11597 12.14185 4.756654 TRUE
## 82 81 6.698265e-03 0.081569961 1 11766 12.17730 4.756646 TRUE
## 83 82 6.659354e-03 0.081334289 1 11783 12.21306 4.756638 TRUE
## 84 83 6.620441e-03 0.081097895 1 11862 12.24914 4.756630 TRUE
## 85 84 6.581525e-03 0.080860772 1 12325 12.28554 4.756622 TRUE
## 86 85 6.542605e-03 0.080622914 1 12495 12.32227 4.756614 TRUE
## 87 86 6.503683e-03 0.080384315 1 12518 12.35933 4.756606 TRUE
## 88 87 6.464757e-03 0.080144968 1 12640 12.39673 4.756599 TRUE
## 89 88 6.425829e-03 0.079904866 1 12643 12.43446 4.756591 TRUE
## 90 89 6.386897e-03 0.079664002 1 12785 12.47255 4.756583 TRUE
## 91 90 6.347962e-03 0.079422370 1 12833 12.51098 4.756575 TRUE
## 92 91 6.309025e-03 0.079179963 1 12836 12.54978 4.756567 TRUE
## 93 92 6.270084e-03 0.078936773 1 13021 12.58894 4.756559 TRUE
## 94 93 6.231140e-03 0.078692793 1 13104 12.62846 4.756551 TRUE
## 95 94 6.192193e-03 0.078448015 1 13170 12.66836 4.756543 TRUE
## 96 95 6.153243e-03 0.078202433 1 13180 12.70864 4.756535 TRUE
## 97 96 6.114290e-03 0.077956038 1 13203 12.74931 4.756527 TRUE
## 98 97 6.075334e-03 0.077708823 1 13237 12.79037 4.756519 TRUE
## 99 98 6.036375e-03 0.077460780 1 13261 12.83183 4.756511 TRUE
## 100 99 5.997413e-03 0.077211901 1 13312 12.87370 4.756503 TRUE
## 101 100 5.958448e-03 0.076962177 1 13355 12.91597 4.756495 TRUE
## 102 101 5.919479e-03 0.076711602 1 13394 12.95867 4.756487 TRUE
## 103 102 5.880508e-03 0.076460165 1 13396 13.00180 4.756479 TRUE
## 104 103 5.841534e-03 0.076207860 1 13452 13.04535 4.756471 TRUE
## 105 104 5.802556e-03 0.075954676 1 13558 13.08935 4.756463 TRUE
## 106 105 5.763576e-03 0.075700605 1 13629 13.13380 4.756455 TRUE
## 107 106 5.724592e-03 0.075445639 1 13993 13.17870 4.756448 TRUE
## 108 107 5.685606e-03 0.075189768 1 14004 13.22407 4.756440 TRUE
## 109 108 5.646616e-03 0.074932982 1 14124 13.26990 4.756432 TRUE
## 110 109 5.607623e-03 0.074675273 1 14181 13.31622 4.756424 TRUE
## 111 110 5.568627e-03 0.074416631 1 14219 13.36303 4.756416 TRUE
## 112 111 5.529629e-03 0.074157046 1 14241 13.41033 4.756408 TRUE
## 113 112 5.490627e-03 0.073896508 1 14396 13.45814 4.756400 TRUE
## 114 113 5.451622e-03 0.073635007 1 14501 13.50646 4.756392 TRUE
## 115 114 5.412614e-03 0.073372532 1 14655 13.55531 4.756384 TRUE
## 116 115 5.373603e-03 0.073109074 1 14670 13.60469 4.756376 TRUE
## 117 116 5.334589e-03 0.072844621 1 14724 13.65462 4.756368 TRUE
## 118 117 5.295571e-03 0.072579163 1 14808 13.70510 4.756360 TRUE
## 119 118 5.256551e-03 0.072312688 1 14828 13.75614 4.756352 TRUE
## 120 119 5.217528e-03 0.072045186 1 14831 13.80776 4.756344 TRUE
## 121 120 5.178501e-03 0.071776644 1 14954 13.85996 4.756336 TRUE
## 122 121 5.139472e-03 0.071507051 1 15631 13.91276 4.756328 TRUE
## 123 122 5.100439e-03 0.071236395 1 15675 13.96617 4.756320 TRUE
## 124 123 5.061404e-03 0.070964665 1 15812 14.02020 4.756312 TRUE
## 125 124 5.022365e-03 0.070691846 1 16117 14.07486 4.756304 TRUE
## 126 125 4.983324e-03 0.070417928 1 16140 14.13016 4.756296 TRUE
## 127 126 4.944279e-03 0.070142897 1 16715 14.18612 4.756288 TRUE
## 128 127 4.905231e-03 0.069866739 1 16797 14.24275 4.756280 TRUE
## 129 128 4.866180e-03 0.069589442 1 16858 14.30007 4.756273 TRUE
## 130 129 4.827126e-03 0.069310991 1 16887 14.35808 4.756265 TRUE
## 131 130 4.788069e-03 0.069031373 1 17141 14.41681 4.756257 TRUE
## 132 131 4.749009e-03 0.068750574 1 17622 14.47626 4.756249 TRUE
## 133 132 4.709946e-03 0.068468579 1 17624 14.53645 4.756241 TRUE
## 134 133 4.670880e-03 0.068185372 1 17935 14.59740 4.756233 TRUE
## 135 134 4.631810e-03 0.067900940 1 18106 14.65912 4.756225 TRUE
## 136 135 4.592738e-03 0.067615266 1 18284 14.72163 4.756217 TRUE
## 137 136 4.553663e-03 0.067328335 1 18370 14.78495 4.756209 TRUE
## 138 137 4.514584e-03 0.067040130 1 18444 14.84910 4.756201 TRUE
## 139 138 4.475503e-03 0.066750635 1 18646 14.91408 4.756193 TRUE
## 140 139 4.436418e-03 0.066459834 1 18689 14.97993 4.756185 TRUE
## 141 140 4.397330e-03 0.066167708 1 18756 15.04665 4.756177 TRUE
## 142 141 4.358239e-03 0.065874240 1 19283 15.11428 4.756169 TRUE
## 143 142 4.319146e-03 0.065579413 1 19362 15.18283 4.756161 TRUE
## 144 143 4.280049e-03 0.065283208 1 19539 15.25231 4.756153 TRUE
## 145 144 4.240949e-03 0.064985605 1 19605 15.32276 4.756145 TRUE
## 146 145 4.201846e-03 0.064686587 1 19684 15.39420 4.756137 TRUE
## 147 146 4.162740e-03 0.064386132 1 19801 15.46664 4.756129 TRUE
## 148 147 4.123630e-03 0.064084221 1 19945 15.54012 4.756121 TRUE
## 149 148 4.084518e-03 0.063780832 1 20009 15.61465 4.756113 TRUE
## 150 149 4.045403e-03 0.063475946 1 20201 15.69027 4.756105 TRUE
## 151 150 4.006284e-03 0.063169540 1 20328 15.76699 4.756097 TRUE
## 152 151 3.967163e-03 0.062861592 1 20344 15.84486 4.756089 TRUE
## 153 152 3.928038e-03 0.062552079 1 20354 15.92388 4.756081 TRUE
## 154 153 3.888911e-03 0.062240977 1 20355 16.00410 4.756073 TRUE
## 155 154 3.849780e-03 0.061928264 1 20393 16.08555 4.756065 TRUE
## 156 155 3.810646e-03 0.061613914 1 20471 16.16825 4.756057 TRUE
## 157 156 3.771509e-03 0.061297901 1 20559 16.25224 4.756050 TRUE
## 158 157 3.732369e-03 0.060980202 1 20575 16.33756 4.756042 TRUE
## 159 158 3.693226e-03 0.060660787 1 20780 16.42423 4.756034 TRUE
## 160 159 3.654080e-03 0.060339632 1 20791 16.51230 4.756026 TRUE
## 161 160 3.614931e-03 0.060016706 1 20804 16.60180 4.756018 TRUE
## 162 161 3.575779e-03 0.059691983 1 20993 16.69276 4.756010 TRUE
## 163 162 3.536624e-03 0.059365432 1 21439 16.78525 4.756002 TRUE
## 164 163 3.497465e-03 0.059037022 1 21599 16.87928 4.755994 TRUE
## 165 164 3.458304e-03 0.058706724 1 21743 16.97492 4.755986 TRUE
## 166 165 3.419139e-03 0.058374504 1 22015 17.07219 4.755978 TRUE
## 167 166 3.379972e-03 0.058040330 1 22020 17.17116 4.755970 TRUE
## 168 167 3.340801e-03 0.057704167 1 22199 17.27188 4.755962 TRUE
## 169 168 3.301627e-03 0.057365982 1 22339 17.37438 4.755954 TRUE
## 170 169 3.262450e-03 0.057025736 1 22380 17.47873 4.755946 TRUE
## 171 170 3.223270e-03 0.056683395 1 22384 17.58499 4.755938 TRUE
## 172 171 3.184087e-03 0.056338919 1 22482 17.69320 4.755930 TRUE
## 173 172 3.144901e-03 0.055992269 1 22497 17.80344 4.755922 TRUE
## 174 173 3.105712e-03 0.055643404 1 22603 17.91577 4.755914 TRUE
## 175 174 3.066520e-03 0.055292283 1 22623 18.03025 4.755906 TRUE
## 176 175 3.027325e-03 0.054938862 1 22632 18.14695 4.755898 TRUE
## 177 176 2.988126e-03 0.054583096 1 22661 18.26595 4.755890 TRUE
## 178 177 2.948925e-03 0.054224940 1 22674 18.38732 4.755882 TRUE
## 179 178 2.909720e-03 0.053864345 1 22675 18.51114 4.755874 TRUE
## 180 179 2.870512e-03 0.053501262 1 22693 18.63749 4.755866 TRUE
## 181 180 2.831302e-03 0.053135641 1 22695 18.76648 4.755858 TRUE
## 182 181 2.792088e-03 0.052767429 1 22730 18.89817 4.755850 TRUE
## 183 182 2.752871e-03 0.052396570 1 22747 19.03268 4.755842 TRUE
## 184 183 2.713651e-03 0.052023008 1 22804 19.17010 4.755834 TRUE
## 185 184 2.674428e-03 0.051646685 1 22850 19.31054 4.755826 TRUE
## 186 185 2.635202e-03 0.051267540 1 22999 19.45412 4.755818 TRUE
## 187 186 2.595972e-03 0.050885510 1 23067 19.60094 4.755810 TRUE
## 188 187 2.556740e-03 0.050500528 1 23089 19.75115 4.755802 TRUE
## 189 188 2.517505e-03 0.050112528 1 23265 19.90485 4.755794 TRUE
## 190 189 2.478266e-03 0.049721439 1 23377 20.06221 4.755786 TRUE
## 191 190 2.439024e-03 0.049327186 1 23395 20.22335 4.755778 TRUE
## 192 191 2.399780e-03 0.048929694 1 23422 20.38844 4.755770 TRUE
## 193 192 2.360532e-03 0.048528883 1 23447 20.55764 4.755762 TRUE
## 194 193 2.321281e-03 0.048124669 1 23473 20.73113 4.755754 TRUE
## 195 194 2.282027e-03 0.047716968 1 23492 20.90908 4.755746 TRUE
## 196 195 2.242770e-03 0.047305687 1 23544 21.09170 4.755739 TRUE
## 197 196 2.203510e-03 0.046890734 1 23587 21.27918 4.755731 TRUE
## 198 197 2.164247e-03 0.046472009 1 23605 21.47176 4.755723 TRUE
## 199 198 2.124980e-03 0.046049411 1 23639 21.66966 4.755715 TRUE
## 200 199 2.085711e-03 0.045622830 1 23667 21.87313 4.755707 TRUE
## 201 200 2.046438e-03 0.045192155 1 23725 22.08245 4.755699 TRUE
## 202 201 2.007163e-03 0.044757267 1 23840 22.29789 4.755691 TRUE
## 203 202 1.967884e-03 0.044318042 1 23879 22.51977 4.755683 TRUE
## 204 203 1.928602e-03 0.043874350 1 23880 22.74840 4.755675 TRUE
## 205 204 1.889317e-03 0.043426054 1 23928 22.98414 4.755667 TRUE
## 206 205 1.850030e-03 0.042973010 1 23950 23.22737 4.755659 TRUE
## 207 206 1.810738e-03 0.042515066 1 24064 23.47848 4.755651 TRUE
## 208 207 1.771444e-03 0.042052062 1 24065 23.73792 4.755643 TRUE
## 209 208 1.732147e-03 0.041583829 1 24217 24.00616 4.755635 TRUE
## 210 209 1.692847e-03 0.041110188 1 24237 24.28369 4.755627 TRUE
## 211 210 1.653543e-03 0.040630950 1 24245 24.57108 4.755619 TRUE
## 212 211 1.614237e-03 0.040145915 1 24263 24.86893 4.755611 TRUE
## 213 212 1.574927e-03 0.039654870 1 24345 25.17787 4.755603 TRUE
## 214 213 1.535614e-03 0.039157588 1 24353 25.49862 4.755595 TRUE
## 215 214 1.496299e-03 0.038653830 1 24362 25.83195 4.755587 TRUE
## 216 215 1.456980e-03 0.038143338 1 24371 26.17870 4.755579 TRUE
## 217 216 1.417658e-03 0.037625838 1 24419 26.53980 4.755571 TRUE
## 218 217 1.378333e-03 0.037101038 1 24472 26.91627 4.755563 TRUE
## 219 218 1.339004e-03 0.036568622 1 24523 27.30923 4.755555 TRUE
## 220 219 1.299673e-03 0.036028254 1 24524 27.71992 4.755547 TRUE
## 221 220 1.260339e-03 0.035479569 1 24531 28.14971 4.755539 TRUE
## 222 221 1.221001e-03 0.034922177 1 24533 28.60014 4.755531 TRUE
## 223 222 1.181661e-03 0.034355652 1 24617 29.07290 4.755523 TRUE
## 224 223 1.142317e-03 0.033779535 1 24630 29.56991 4.755515 TRUE
## 225 224 1.102970e-03 0.033193328 1 24636 30.09331 4.755507 TRUE
## 226 225 1.063620e-03 0.032596485 1 24647 30.64552 4.755499 TRUE
## 227 226 1.024267e-03 0.031988411 1 24650 31.22930 4.755491 TRUE
## 228 227 9.849112e-04 0.031368454 1 24713 31.84776 4.755483 TRUE
## 229 228 9.455520e-04 0.030735893 1 24719 32.50449 4.755475 TRUE
## 230 229 9.061897e-04 0.030089935 1 24729 33.20359 4.755467 TRUE
## 231 230 8.668243e-04 0.029429696 1 24735 33.94983 4.755459 TRUE
## 232 231 8.274558e-04 0.028754194 1 24785 34.74876 4.755451 TRUE
## 233 232 7.880842e-04 0.028062326 1 24810 35.60688 4.755443 TRUE
## 234 233 7.487095e-04 0.027352850 1 24850 36.53189 4.755435 TRUE
## 235 234 7.093317e-04 0.026624358 1 24857 37.53295 4.755427 TRUE
## 236 235 6.699507e-04 0.025875245 1 24864 38.62109 4.755419 TRUE
## 237 236 6.305667e-04 0.025103664 1 24868 39.80970 4.755411 TRUE
## 238 237 5.911796e-04 0.024307476 1 24963 41.11529 4.755403 TRUE
## 239 238 5.517894e-04 0.023484178 1 24990 42.55836 4.755395 TRUE
## 240 239 5.123960e-04 0.022630813 1 25037 44.16490 4.755387 TRUE
## 241 240 4.729996e-04 0.021743839 1 25108 45.96829 4.755379 TRUE
## 242 241 4.336001e-04 0.020818961 1 25250 48.01231 4.755371 TRUE
## 243 242 3.941974e-04 0.019850883 1 25268 50.35573 4.755363 TRUE
## 244 243 3.547917e-04 0.018832944 1 25293 53.07961 4.755355 TRUE
## 245 244 3.153828e-04 0.017756569 1 25401 56.29942 4.755347 TRUE
## 246 245 2.759708e-04 0.016610405 1 25475 60.18661 4.755339 TRUE
## 247 246 2.365557e-04 0.015378853 1 25478 65.00897 4.755331 TRUE
## 248 247 1.971376e-04 0.014039461 1 25485 71.21376 4.755323 TRUE
## 249 248 1.577163e-04 0.012557771 1 25490 79.61941 4.755315 TRUE
## 250 249 1.182919e-04 0.010875778 1 25510 91.93657 4.755307 TRUE
## 251 250 7.886435e-05 0.008880385 1 25527 112.59885 4.755299 TRUE
## 252 251 3.943373e-05 0.006279628 1 25609 159.23881 4.755291 TRUE
Los graficos, la prueba de Rosner, y el flitro de Hampel han marcado a las 252 observaciones en cuestión como datos atipicos. Sin embargo, por la estrucutra que presentaron los datos, faltantes es necesario revisar su los datos atipicos no estan contenidos en un clase particular.
es_outlier <- ifelse(seq_along(df$Gravedad) %in% outlier_ind, 1, 0)
df_outlier <- as.data.frame(cbind(as.character(df$Gravedad),es_outlier))
colnames(df_outlier) <-c("Gravedad","outlier")
df_outlier$outlier <- as.numeric(df_outlier$outlier)
df_outlier %>%
group_by(Gravedad) %>%
summarise(
total = n(),
Casos = sum(outlier),
Proporcion = round(mean(outlier),2),
Procentaje = round(mean(outlier) * 100,3 ))
## # A tibble: 3 × 5
## Gravedad total Casos Proporcion Procentaje
## <chr> <int> <dbl> <dbl> <dbl>
## 1 Con heridos 9901 0 0 0
## 2 Con muertos 252 252 1 100
## 3 Solo daños 15457 0 0 0
Los resultados muestran que todos los datos atípicos están concentrados en la categoría “con muertos”. Esto sugiere que los valores observados en la variable Muertos probablemente reflejan la gravedad real de los accidentes en lugar de ser errores de digitación. Transformar estos datos en faltantes e imputarlos no es una estrategia adecuada, ya que podría distorsionar el análisis y subestimar la gravedad de ciertos accidentes. Por lo tanto, se ha decidido mantener intactos estos valores, preservando la integridad de los datos y asegurando que el análisis refleje fielmente la realidad de los hechos observados.
Procedemos de la misma manera que con la variable
Muertos.
df%>%
get_summary_stats(Heridos, type = "five_number")
## # A tibble: 1 × 7
## variable n min max q1 median q3
## <fct> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 Heridos 25610 0 42 0 0 1
boxplot(df$Heridos)
hist(df$Heridos)
Los graficos revelan la existencia de valores atipicos en la variable
Heridos. Por lo cual, antes de proseguir utilizaremos el
filtro de Hampel y el método de los percentiles para estudiar más a
profundidad estas observaciones.
lower_bound <- quantile(df$Heridos, 0.025)
upper_bound <- quantile(df$Heridos, 0.975)
outlier_ind <- which(df$Heridos < lower_bound | df$Heridos > upper_bound)
# Crear una columna que marque los outliers
df$Perc <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
# Ver el número de outliers
length(outlier_ind)
## [1] 303
Hora el flitro de Hampel
# Calcular los límites usando el filtro de Hampel
lower_bound <- median(df$Heridos, na.rm = TRUE) - 3 * mad(df$Heridos, constant = 1, na.rm = TRUE)
upper_bound <- median(df$Heridos, na.rm = TRUE) + 3 * mad(df$Heridos, constant = 1, na.rm = TRUE)
# Identificar los índices de los outliers
outlier_ind <- which(df$Heridos < lower_bound | df$Heridos > upper_bound)
# Crear una columna que marque los outliers
df$Hampel <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
# Ver el número de outliers
length(outlier_ind)
## [1] 9984
Revisemos las discrepansias entre los dos criterios:
table(df$Hampel, df$Perc)
##
## 0 1
## 0 15626 0
## 1 9681 303
Notamos que ambos criterios defieren considerablemente, por lo cual se aplica la prueba de Rosner:
test <- rosnerTest(df$Heridos, k = 1000)
## Warning in rosnerTest(df$Heridos, k = 1000): The true Type I error may be larger than assumed.
## Although the help file for 'rosnerTest' has a table with information
## on the estimated Type I error level,
## simulations were not run for k > 10 or k > floor(n/2).
test <- test$all.stats
outlier_ind <- test[test$Outlier == TRUE,]$Obs.Num
df$Rosner <- ifelse(1:nrow(df) %in% outlier_ind, 1, 0)
df %>%
group_by(Gravedad) %>%
summarise(
total = n(),
Casos_Hampel = sum(Hampel),
Casos_perc = sum(Perc),
Casos_rosenr = sum(Rosner),
Procentaje_Hampel = round((sum(Hampel)/9984) * 100,3 ),
Procentaje_perc = round((sum(Perc)/303) * 100,3 ),
Procentaje_Rosenr = round((sum(Rosner)/148) * 100,3 ))
## # A tibble: 3 × 8
## Gravedad total Casos_Hampel Casos_perc Casos_rosenr Procentaje_Hampel
## <fct> <int> <dbl> <dbl> <dbl> <dbl>
## 1 Con heridos 9901 9901 297 145 99.2
## 2 Con muertos 252 83 6 3 0.831
## 3 Solo daños 15457 0 0 0 0
## # ℹ 2 more variables: Procentaje_perc <dbl>, Procentaje_Rosenr <dbl>
Notamos que, tal como se reporte en la variable Muertos,
los datos atípicos están concentrados en la categoría “con heridos”.
Esto sugiere que los valores observados en la variable
Heridos probablemente reflejan la gravedad real de los
accidentes en lugar de ser errores de digitación. Por lo tanto, se ha
decidido mantener intactos estos valores.