# ==================================================================================
# PROYECTO FINAL: ANÁLISIS ESTADÍSTICO DE ACCIDENT LATITUDE
# ==================================================================================
# 1. CARGA DE LIBRERÍAS
library(readxl) # Para leer Excel
library(ggplot2) # Para gráficas
library(dplyr) # Para manejo de datos
##
## Attaching package: 'dplyr'
## The following objects are masked from 'package:stats':
##
## filter, lag
## The following objects are masked from 'package:base':
##
## intersect, setdiff, setequal, union
library(gt) # Para tablas profesionales
library(janitor) # Para totales
##
## Attaching package: 'janitor'
## The following objects are masked from 'package:stats':
##
## chisq.test, fisher.test
# 2. IMPORTACIÓN Y PROCESAMIENTO DE DATOS
# Importamos el archivo asegurando que el objeto 'database' exista
database <- read_excel("database.xlsx")
## Warning: Expecting numeric in C2189 / R2189C3: got 'Accident Year'
## Warning: Expecting numeric in C2215 / R2215C3: got 'Accident Year'
nombre_var <- "Accident Latitude"
ANCHO_CLASE <- 3.0
# Limpieza: Convertir a número y eliminar valores nulos
datos_raw <- as.numeric(as.character(database[[nombre_var]])) %>% na.omit()
LIMITE_MIN <- floor(min(datos_raw))
LIMITE_MAX <- ceiling(max(datos_raw))
variable_filtrada <- datos_raw[datos_raw >= LIMITE_MIN & datos_raw <= LIMITE_MAX]
n_total <- length(variable_filtrada)
# 3. CONSTRUCCIÓN DE TABLA DE FRECUENCIAS (Incluye ni, hi, Ni asc y Ni desc)
cortes <- seq(LIMITE_MIN, LIMITE_MAX + ANCHO_CLASE, by = ANCHO_CLASE)
tabla_resumen <- data.frame(
Intervalo = cut(variable_filtrada, breaks = cortes, include.lowest = TRUE, right = FALSE)
) %>%
count(Intervalo, name = "ni") %>%
mutate(
hi = ni / sum(ni), # Frecuencia relativa (Suma 1.00)
Ni_asc = cumsum(ni), # Frecuencia acumulada ascendente
Ni_desc = n_total - Ni_asc + ni # Frecuencia acumulada descendente
)
# 4. VISUALIZACIÓN DE LA TABLA
tabla_resumen %>%
adorn_totals("row", name = "TOTAL") %>%
gt() %>%
fmt_number(columns = hi, decimals = 4) %>% # Formato hi con decimales
tab_header(title = "Distribución de Frecuencias", subtitle = "Variable: Accident Latitude")
| Distribución de Frecuencias |
| Variable: Accident Latitude |
| Intervalo |
ni |
hi |
Ni_asc |
Ni_desc |
| [18,21) |
1 |
0.0004 |
1 |
2795 |
| [21,24) |
4 |
0.0014 |
5 |
2794 |
| [24,27) |
2 |
0.0007 |
7 |
2790 |
| [27,30) |
483 |
0.1728 |
490 |
2788 |
| [30,33) |
646 |
0.2311 |
1136 |
2305 |
| [33,36) |
466 |
0.1667 |
1602 |
1659 |
| [36,39) |
350 |
0.1252 |
1952 |
1193 |
| [39,42) |
505 |
0.1807 |
2457 |
843 |
| [42,45) |
172 |
0.0615 |
2629 |
338 |
| [45,48) |
126 |
0.0451 |
2755 |
166 |
| [48,51) |
29 |
0.0104 |
2784 |
40 |
| [63,66) |
3 |
0.0011 |
2787 |
11 |
| [66,69) |
3 |
0.0011 |
2790 |
8 |
| [69,72] |
5 |
0.0018 |
2795 |
5 |
| TOTAL |
2795 |
1.0000 |
24190 |
17735 |
# 5. GRÁFICAS (Histograma, Ojivas y Boxplot)
# Histograma
ggplot(tabla_resumen, aes(x = Intervalo, y = ni)) +
geom_col(fill = "#708090", color = "white") +
geom_text(aes(label = ni), vjust = -0.5, fontface = "bold") +
theme_minimal() +
labs(title = "Frecuencia de Accidentes por Latitud", x = "Rango Geográfico", y = "Número de Accidentes")

# Cruce de Ojivas
puntos_x <- seq(LIMITE_MIN, LIMITE_MIN + (nrow(tabla_resumen) * ANCHO_CLASE), by = ANCHO_CLASE)
df_ojiva <- data.frame(
X = rep(puntos_x, 2),
Y = c(c(0, tabla_resumen$Ni_asc), c(n_total, tabla_resumen$Ni_desc[-1], 0)),
Tipo = rep(c("Ascendente", "Descendente"), each = length(puntos_x))
)
ggplot(df_ojiva, aes(x = X, y = Y, color = Tipo, group = Tipo)) +
geom_line(linewidth = 1.2) + geom_point(shape = 16, size = 3) +
scale_color_manual(values = c("#6B8E23", "#BC8F8F")) +
theme_minimal() + labs(title = "Análisis de Frecuencia Acumulada", y = "Total Acumulado de Accidentes")

# Boxplot Horizontal
ggplot(data.frame(v = variable_filtrada), aes(x = "", y = v)) +
geom_boxplot(fill = "#8FBC8F", color = "#2F4F4F", outlier.color = "red", outlier.shape = 16) +
coord_flip() + theme_bw() + labs(title = "Dispersión Geográfica", y = "Grados de Latitud")

# 6. CONCLUSIÓN GENERAL
cat("\nCONCLUSIÓN GENERAL:\n")
##
## CONCLUSIÓN GENERAL:
cat("El análisis identifica concentraciones críticas en rangos latitudinales específicos.\n")
## El análisis identifica concentraciones críticas en rangos latitudinales específicos.
cat("La suma de hi es exactamente 1.00, validando la integridad de los 2,795 registros.\n")
## La suma de hi es exactamente 1.00, validando la integridad de los 2,795 registros.