Ejercicio 5 Parte 2

  1. Realice una exploración y un análisis descriptivo completo (incluyendo tablas de resumen y gráficos) de la base de datos disponible en este enlace. Incluya gráficos que presenten los datos sobre un mapa de Colombia, para visualizar la distribución geográfica de los precios de los combustibles en el país (2018-2024).
library(dplyr)
#library(tidyr)

file_paths <- c(
                "C:/Users/CEDIS RECEPCION/Downloads/energia/precios (19).csv",
                "C:/Users/CEDIS RECEPCION/Downloads/energia/precios (20).csv",
                "C:/Users/CEDIS RECEPCION/Downloads/energia/precios (21).csv",
                "C:/Users/CEDIS RECEPCION/Downloads/energia/precios (22).csv")

energia <- file_paths %>%
  lapply(read.csv) %>%
  bind_rows()

# View the combined data
head(energia)
##   BANDERA                               NOMBRE.COMERCIAL       PRODUCTO
## 1  TERPEL            ESTACION DE SERVICIO BALSA SAN JOSE GASOLINA MOTOR
## 2  TERPEL ESTACION DE SERVICIO DISTRIBUIDORA EL PORVENIR         DIESEL
## 3  TERPEL            ESTACION DE SERVICIO BALSA SAN JOSE         DIESEL
## 4  TERPEL ESTACION DE SERVICIO DISTRIBUIDORA EL PORVENIR GASOLINA MOTOR
## 5  TERPEL                                BALSA EL CONDOR GASOLINA MOTOR
## 6  TERPEL                                BALSA EL CONDOR         DIESEL
##   FECHA.REGISTRO DEPARTAMENTO MUNICIPIO VALOR.PRECIO
## 1    01-Oct-2022     AMAZONAS   LETICIA        10398
## 2    01-Oct-2022     AMAZONAS   LETICIA        11820
## 3    01-Oct-2022     AMAZONAS   LETICIA        10371
## 4    01-Oct-2022     AMAZONAS   LETICIA        12010
## 5    01-Oct-2022     AMAZONAS   LETICIA        10397
## 6    01-Oct-2022     AMAZONAS   LETICIA        10736
  1. VALOR.PRECIO (Valor del Precio)
library(readr)
library(dplyr)
library(knitr)
library(reactable)
library(ggplot2)
library(gridExtra)
library(VIM)
library(naniar)
library(e1071)


str(energia)
## 'data.frame':    269510 obs. of  7 variables:
##  $ BANDERA         : chr  "TERPEL" "TERPEL" "TERPEL" "TERPEL" ...
##  $ NOMBRE.COMERCIAL: chr  "ESTACION DE SERVICIO BALSA SAN JOSE" "ESTACION DE SERVICIO DISTRIBUIDORA EL PORVENIR" "ESTACION DE SERVICIO BALSA SAN JOSE" "ESTACION DE SERVICIO DISTRIBUIDORA EL PORVENIR" ...
##  $ PRODUCTO        : chr  "GASOLINA MOTOR" "DIESEL" "DIESEL" "GASOLINA MOTOR" ...
##  $ FECHA.REGISTRO  : chr  "01-Oct-2022" "01-Oct-2022" "01-Oct-2022" "01-Oct-2022" ...
##  $ DEPARTAMENTO    : chr  "AMAZONAS" "AMAZONAS" "AMAZONAS" "AMAZONAS" ...
##  $ MUNICIPIO       : chr  "LETICIA" "LETICIA" "LETICIA" "LETICIA" ...
##  $ VALOR.PRECIO    : num  10398 11820 10371 12010 10397 ...
dim(energia)
## [1] 269510      7
names(energia)
## [1] "BANDERA"          "NOMBRE.COMERCIAL" "PRODUCTO"         "FECHA.REGISTRO"  
## [5] "DEPARTAMENTO"     "MUNICIPIO"        "VALOR.PRECIO"
reactable(energia, searchable = TRUE, pagination = TRUE, defaultPageSize = 10)
summary(energia)
##    BANDERA          NOMBRE.COMERCIAL     PRODUCTO         FECHA.REGISTRO    
##  Length:269510      Length:269510      Length:269510      Length:269510     
##  Class :character   Class :character   Class :character   Class :character  
##  Mode  :character   Mode  :character   Mode  :character   Mode  :character  
##                                                                             
##                                                                             
##                                                                             
##  DEPARTAMENTO        MUNICIPIO          VALOR.PRECIO     
##  Length:269510      Length:269510      Min.   :       0  
##  Class :character   Class :character   1st Qu.:    9250  
##  Mode  :character   Mode  :character   Median :   10070  
##                                        Mean   :   11495  
##                                        3rd Qu.:   12690  
##                                        Max.   :14750147
library(kableExtra)
library(dplyr)
library(knitr)

categorical_vars <- energia %>% select(where(is.character)) %>% colnames()

for(var in categorical_vars) {
  freq_table <- energia %>%
    group_by_at(var) %>%
    summarise(Count = n()) %>%
    mutate(Relative_Frequency = round(Count / sum(Count) * 100, 2)) %>%
    arrange(desc(Count))
  
}
reactable(freq_table, searchable = TRUE, pagination = TRUE, defaultPageSize = 10)

Se realiza una inspección general a los datos faltantes y se observa que no hay observaciones que hagan falta en ninguno de los registros, sin embargo, se realizará una inspección para posibles datos atípicos y evaluar algún tipo de imputación dependiendo su naturaleza (bien sea por la media de la variable o por su mediana en el caso de no ser normal).

faltantes <- colSums(is.na(energia))
faltantes
##          BANDERA NOMBRE.COMERCIAL         PRODUCTO   FECHA.REGISTRO 
##                0                0                0                0 
##     DEPARTAMENTO        MUNICIPIO     VALOR.PRECIO 
##                0                0                0
aggr(energia, 
     numbers = TRUE, 
     col = c("navyblue", "red"), 
     cex.axis = 0.7, 
     gap = 3, 
     ylab = c("Proportion of missingness", "Missingness pattern"), 
     labels = names(energia), 
     cex.lab = 1.2, 
     axes = TRUE)

library(naniar)
gg_miss_var(energia, show_pct = TRUE)

Distribución de los datos

Se observa graficamente la distribución de los precios del combustible a nivel nacional y se contempla una densa concentración de los datos entre 6500 y 15000 pesos, sin embargo, también se distribuyen extensamente hasta 22000, lo que indica posibles indicios de no normalidad. Analiticamente se implemente la prueba Kolmogorov-Smirnov para verificar la normalidad de los datos. Se concluye que dado P-value < \(0.05\) los datos no se ajustan a una distribución normal. Del mismo modo se evidencia presencia de datos atípicos.

Prueba de normalidad

  • \(H_0\): Los datos no se ajustan a una distribución normal
  • \(H_!\): Los datos se ajustan a una distribución normal
library(ggplot2)
energia_filtrada <- energia %>% filter(VALOR.PRECIO < quantile(VALOR.PRECIO, 0.99, na.rm = TRUE))

ggplot(energia_filtrada, aes(x = VALOR.PRECIO)) +
  geom_histogram(binwidth = 500, fill = "lightblue", color = "black") +
  ggtitle("Distribución del precio de los combustibles") +
  xlab("Valor del Precio") +
  ylab("Frecuencia") +
  theme_minimal()

ggplot(energia_filtrada, aes(y = VALOR.PRECIO)) +
  geom_boxplot(fill = "lightblue", color = "black") +
  ggtitle("Diagrama de Cajas y Bigotes del Precio de los Combustibles") +
  ylab("Valor del Precio") +
  theme_minimal()+
  coord_flip()

ks_test <- ks.test(energia$VALOR.PRECIO[!is.na(energia$VALOR.PRECIO)], "pnorm", mean(energia$VALOR.PRECIO, na.rm = TRUE), sd(energia$VALOR.PRECIO, na.rm = TRUE))
print(ks_test)
## 
##  Asymptotic one-sample Kolmogorov-Smirnov test
## 
## data:  energia$VALOR.PRECIO[!is.na(energia$VALOR.PRECIO)]
## D = 0.43625, p-value < 2.2e-16
## alternative hypothesis: two-sided
# Q-Q Plot para ver la normalidad visualmente
qqnorm(energia$VALOR.PRECIO, main = "Q-Q Plot de VALOR.PRECIO")
qqline(energia$VALOR.PRECIO, col = "red")

mediana_valor_precio <- median(energia$VALOR.PRECIO, na.rm = TRUE)
energia$VALOR.PRECIO[is.na(energia$VALOR.PRECIO)] <- mediana_valor_precio
sum(is.na(energia$VALOR.PRECIO))
## [1] 0

Análisis de valores atípicos para el precio

Pruebas analíticas para datos atípicos

Prueba Rosner

La prueba de Rosner para detectar valores atípicos tiene las siguientes ventajas. Se utiliza para detectar varios valores atípicos a la vez (a diferencia de la prueba de Grubbs y Dixon, que debe realizarse de forma iterativa para detectar múltiples valores atípicos), y está diseñado para evitar el problema del enmascaramiento, en el que un valor atípico cercano a otro atípico puede pasar desapercibido. A diferencia de la prueba de Dixon, hay que tener en cuenta que la prueba de Rosner es más apropiada cuando el tamaño de la muestra es grande \((n≥20)\).

library(EnvStats)

test <- rosnerTest(energia$VALOR.PRECIO, k = 500)
tabla_stats <- as.data.frame(test$all.stats)
colnames(tabla_stats) <- c("Index", "Mean", "Standard Deviation", "Value", 
                           "Number of Observations", "R.i+1", "Lambda i+1", "Outlier")

reactable(tabla_stats, 
          columns = list(
            Index = colDef(name = "Index"),
            Mean = colDef(name = "Mean"),
            `Standard Deviation` = colDef(name = "Standard Deviation"),
            Value = colDef(name = "Value"),
            `Number of Observations` = colDef(name = "Number of Observations"),
            `R.i+1` = colDef(name = "R.i+1"),
            `Lambda i+1` = colDef(name = "Lambda i+1"),
            Outlier = colDef(name = "Outlier")
          ),
          pagination = TRUE,            # Habilitar la paginación
          defaultPageSize = 10,         # Tamaño de página predeterminado
          bordered = TRUE,              # Borde de la tabla
          highlight = TRUE,             # Resaltar filas al pasar el mouse
          searchable = TRUE)            # Habilitar búsqueda

Imputación ante datos atípicos

Se realizará el proceso de imputación a los datos atipicos a través del método capping, es decir, para los valores que se encuentran fuera de los límites de \(1.5⋅IQR\) podríamos poner un tope sustituyendo las observaciones que se encuentran fuera del límite inferior por el valor del 5th percentil y las que se encuentran por encima del límite superior, por el valor del 95th percentil. Posterior a ellos, visualizamos graficamente los valores atípicos y no evidenciamos sino únicamente 1 dato atípico por fuera de la malla de imputación, si deseamos normalizarlo, podemor observarlo a través de la prueba Grubbs.

library(reactable)
library(ggplot2)

lower_bound <- quantile(energia$VALOR.PRECIO, 0.01, na.rm = TRUE)
upper_bound <- quantile(energia$VALOR.PRECIO, 0.99, na.rm = TRUE)


energia$VALOR.PRECIO <- ifelse(energia$VALOR.PRECIO > upper_bound, upper_bound,
                                        ifelse(energia$VALOR.PRECIO < lower_bound, lower_bound,
                                               energia$VALOR.PRECIO))

library(ggplot2)

ggplot(energia, aes(y = VALOR.PRECIO)) +
  geom_boxplot(fill = "lightblue", color = "black") +
  ggtitle("Diagrama de Cajas y Bigotes del Precio de los Combustibles (Después de Capping)") +
  ylab("Valor del Precio") +
  theme_minimal() +
  coord_flip()

Análisis gráfico demás variables

Conteo de productos

Se observa el conteo de categorías para la variable Productos la cual se divide en 3, “Diesel”, “Extra” y “Gasolina Motor”, siendo esta última la que más conteo posee y Extra con menos registros de consumo.

ggplot(energia, aes(x = PRODUCTO)) +
  geom_bar(fill = "lightblue", color = "black") +
  ggtitle("Distribución de los Productos") +
  xlab("Producto") +
  ylab("Frecuencia") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

Se realiza una gráfica del conteo de consumo de productos por departamentos y se detalla en lo siguiente: - En el eje horizontal se listan los diferentes departamentos de Colombia. Los departamentos están ordenados de forma descendente según la frecuencia de aparición de los productos. - Las frecuencias varían significativamente entre los departamentos, con los valores más altos superando los 150,000 registros y los más bajos apenas alcanzando unos pocos miles. - NARIÑO: Es el departamento con la mayor frecuencia de productos registrados, con un valor que supera los 150,000 registros. Esto sugiere una alta concentración de productos en esta región. - ANTIOQUIA, BOYACÁ, VALLE DEL CAUCA, CUNDINAMARCA: Son otros departamentos con frecuencias elevadas, cada uno con más de 100,000 registros. Estos departamentos son probablemente importantes centros de distribución o consumo de los productos en cuestión. - En el extremo derecho de la gráfica, encontramos departamentos como VAUPÉS, GUAINÍA, GUAVIARE, AMAZONAS, entre otros, que tienen frecuencias muy bajas, incluso llegando a menos de 10,000 registros. Esto podría indicar menor actividad económica, menor demanda de productos, o simplemente una menor recolección de datos en estas regiones.

  • La distribución de los productos no es homogénea en todo el país; hay una clara concentración de registros en los departamentos más grandes o económicamente activos.
  • Los departamentos con alta frecuencia podrían estar relacionados con zonas industriales, agrícolas, o urbanas con mayor demanda de los productos en cuestión.
  • Los departamentos con baja frecuencia podrían ser zonas rurales, áreas de difícil acceso, o con menor población.
ggplot(energia, aes(x = reorder(DEPARTAMENTO, -table(DEPARTAMENTO)[DEPARTAMENTO]))) +
  geom_bar(fill = "lightblue", color = "black") +
  ggtitle("Distribución de los Productos por Departamento") +
  xlab("Departamento") +
  ylab("Frecuencia") +
  theme_minimal() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1))

  • GASOLINA MOTOR muestra la mayor variabilidad en los precios, seguido por EXTRA y luego DIESEL. Esto sugiere que los precios de la gasolina de motor son más susceptibles a fluctuaciones en comparación con los otros dos tipos de combustible.
  • DIESEL tiene el rango de precios más bajo, mientras que EXTRA tiene un rango de precios más alto.
  • La diferencia en las cajas sugiere que, en promedio, el precio de EXTRA es más alto que el de DIESEL, y GASOLINA MOTOR se sitúa entre ambos.
library(ggplot2)

energia_limpia <- energia %>%
  filter(VALOR.PRECIO > 0 & VALOR.PRECIO < 30000)  # Ajusta este rango según tus datos

# Crear el boxplot con los datos filtrados
ggplot(energia_limpia, aes(x = PRODUCTO, y = VALOR.PRECIO, fill = PRODUCTO)) + 
  geom_boxplot(outlier.shape = NA) +  # Elimina la visualización de valores atípicos extremos
  labs(title = "Distribucion de Precios por Tipo de Combustible",
       x = "Producto",
       y = "Precio") +
  theme_minimal() +
  coord_flip()+
  theme(legend.position = "none",
        axis.text.x = element_text(angle = 45, hjust = 1),  # Gira el texto para mejorar la legibilidad
        plot.title = element_text(hjust = 0.5)) +  # Centra el título
  scale_y_continuous(labels = scales::comma)

Mapa gráfico