Cargar datos

setwd("C:/Users/s05e17/Downloads")

file_carbon <- "clean_precios_carbon.csv"
file_gas_natural <- "clean_precios_gas_natural.csv"
file_gasolina <- "clean_precios_gasolina.csv"
file_petroleo <- "clean_precios_petroleo.csv"
file_ipc <- "IPC.csv"

Leer archivos CSV

carbon_raw <- read_csv(file_carbon, show_col_types = FALSE)
gas_natural_raw <- read_csv(file_gas_natural, show_col_types = FALSE)
gasolina_raw <- read_csv(file_gasolina, show_col_types = FALSE)
petroleo_raw <- read_csv(file_petroleo, show_col_types = FALSE)
ipc_raw <- read_csv(file_ipc, show_col_types = FALSE)

Mostrar primeras filas para inspección

list(carbon = head(carbon_raw), gas_natural = head(gas_natural_raw), gasolina = head(gasolina_raw), petroleo = head(petroleo_raw), ipc = head(ipc_raw))
## $carbon
## # A tibble: 6 × 2
##   fecha      precio_carbon
##   <date>             <dbl>
## 1 2000-01-01          56.8
## 2 2000-01-02          84.1
## 3 2000-01-03          70.7
## 4 2000-01-05          79.7
## 5 2000-01-06          91.5
## 6 2000-01-07          69.8
## 
## $gas_natural
## # A tibble: 6 × 2
##   fecha      precio_gas_natural
##   <date>                  <dbl>
## 1 2000-01-01              134. 
## 2 2000-01-02              103. 
## 3 2000-01-03               72.7
## 4 2000-01-04              102. 
## 5 2000-01-05              134. 
## 6 2000-01-06               78.6
## 
## $gasolina
## # A tibble: 6 × 2
##   fecha      precio_gasolina
##   <date>               <dbl>
## 1 2000-01-01            85.2
## 2 2000-01-02            58.8
## 3 2000-01-03            62.4
## 4 2000-01-04            48.6
## 5 2000-01-05            43.8
## 6 2000-01-06            41.9
## 
## $petroleo
## # A tibble: 6 × 2
##   fecha      precio_petroleo
##   <date>               <dbl>
## 1 2000-01-01            77.7
## 2 2000-01-02           108. 
## 3 2000-01-03           119. 
## 4 2000-01-04           106. 
## 5 2000-01-05           115. 
## 6 2000-01-06           101. 
## 
## $ipc
## # A tibble: 6 × 2
##   fecha        ipc
##   <date>     <dbl>
## 1 1954-07-31  0.03
## 2 1954-08-31  0.03
## 3 1954-09-30  0.03
## 4 1954-10-31  0.03
## 5 1954-11-30  0.03
## 6 1954-12-31  0.03

#1.1 Exploración inicial

explore_df <- function(df){
df %>%
summarize(n_obs = n(),
first_date = min(.[[1]], na.rm = TRUE),
last_date = max(.[[1]], na.rm = TRUE),
vars = paste(names(.), collapse = ", "),
types = paste(sapply(., class), collapse = ", "))
}


explore_list <- list(
carbon = explore_df(carbon_raw),
gas_natural = explore_df(gas_natural_raw),
gasolina = explore_df(gasolina_raw),
petroleo = explore_df(petroleo_raw),
ipc = explore_df(ipc_raw)
)


bind_rows(explore_list, .id = "dataset")
## # A tibble: 5 × 6
##   dataset     n_obs first_date last_date  vars                      types       
##   <chr>       <int> <date>     <date>     <chr>                     <chr>       
## 1 carbon       8579 2000-01-01 2024-01-01 fecha, precio_carbon      Date, numer…
## 2 gas_natural  8579 2000-01-01 2024-01-01 fecha, precio_gas_natural Date, numer…
## 3 gasolina     8579 2000-01-01 2024-01-01 fecha, precio_gasolina    Date, numer…
## 4 petroleo     8579 2000-01-01 2024-01-01 fecha, precio_petroleo    Date, numer…
## 5 ipc           847 1954-07-31 2025-01-31 fecha, ipc                Date, numer…

Nuestra interpetación:

En relación con las variables que utilizaremosara el ejercicio, se observa que las bases correspondientes a carbón, gas natural, gasolina y petróleo cuentan con el mismo número de registros (8579), comparten el mismo rango temporal —desde el 1 de enero de 2000 hasta el 1 de enero de 2024— y presentan las mismas variables: fecha y precio de cada producto. Por otro lado, la base de datos del IPC contiene 847 observaciones, con un rango de fechas diferente, que abarca desde el 31 de julio de 1954 hasta el 31 de enero de 2025. Sus variables son fecha e ipc. Finalmente, todas las bases comparten el mismo tipo de datos: una variable en formato fecha y las demás de tipo numérico.

1.2

1.3

# Función que recibe dataframe, nombre columna fecha y precio
fill_dates <- function(df, date_col = NULL, price_col = NULL){
# Acepta dataframes donde la primera columna es fecha si no se especifica
if(is.null(date_col)) date_col <- names(df)[1]
if(is.null(price_col)) price_col <- names(df)[2]


df2 <- df %>%
rename(.date = all_of(date_col), .price = all_of(price_col)) %>%
mutate(.date = as_date(.date))


full_dates <- tibble(.date = seq.Date(min(df2$.date, na.rm=TRUE), max(df2$.date, na.rm=TRUE), by = "day"))
out <- full_dates %>% left_join(df2, by = ".date")


# Renombrar de vuelta a original
out <- out %>% rename(!!date_col := .date, !!price_col := .price)
return(out)
}


# Aplicar a cada dataset (ajustar nombres de columnas si es necesario)
carbon <- fill_dates(carbon_raw)
gas_natural <- fill_dates(gas_natural_raw)
gasolina <- fill_dates(gasolina_raw)
petroleo <- fill_dates(petroleo_raw)



# Asegurar que IPC tenga fecha tipo Date. Intentamos detectar columna fecha.
ipc <- ipc_raw %>%
rename_with(~tolower(.))


# intentar detectar columna fecha en IPC
possible_date_ipc <- names(ipc)[sapply(ipc, function(x) any(grepl("\\d{4}-\\d{2}|/", as.character(x))))][1]

if (!is.null(possible_date_ipc)) {
  ipc <- ipc %>%
    rename(.date = all_of(possible_date_ipc)) %>%
    mutate(.date = as_date(.date))
  names(ipc)[names(ipc) == '.date'] <- possible_date_ipc
}


# Mostrar rangos después de completar
tibble(dataset = c('carbon','gas_natural','gasolina','petroleo'),
n_obs = c(nrow(carbon), nrow(gas_natural), nrow(gasolina), nrow(petroleo)),
start = c(min(carbon[[1]], na.rm=TRUE), min(gas_natural[[1]], na.rm=TRUE), min(gasolina[[1]], na.rm=TRUE), min(petroleo[[1]], na.rm=TRUE)),
end = c(max(carbon[[1]], na.rm=TRUE), max(gas_natural[[1]], na.rm=TRUE), max(gasolina[[1]], na.rm=TRUE), max(petroleo[[1]], na.rm=TRUE)))
## # A tibble: 4 × 4
##   dataset     n_obs start      end       
##   <chr>       <int> <date>     <date>    
## 1 carbon       8767 2000-01-01 2024-01-01
## 2 gas_natural  8767 2000-01-01 2024-01-01
## 3 gasolina     8767 2000-01-01 2024-01-01
## 4 petroleo     8767 2000-01-01 2024-01-01

1.4 Unión datasets

# Normalizar nombres: asumimos columnas [fecha, precio]
rename_to_standard <- function(df, new_price_name){
df %>% rename(date = 1, !!new_price_name := 2)
}


carbon_s <- rename_to_standard(carbon, "precio_carbon")
gas_natural_s <- rename_to_standard(gas_natural, "precio_gas_natural")
gasolina_s <- rename_to_standard(gasolina, "precio_gasolina")
petroleo_s <- rename_to_standard(petroleo, "precio_petroleo")


# Hacer full join por date
daily_all <- carbon_s %>%
full_join(gas_natural_s, by = "date") %>%
full_join(gasolina_s, by = "date") %>%
full_join(petroleo_s, by = "date") %>%
arrange(date)


# Inspección
glimpse(daily_all)
## Rows: 8,767
## Columns: 5
## $ date               <date> 2000-01-01, 2000-01-02, 2000-01-03, 2000-01-04, 20…
## $ precio_carbon      <dbl> 56.80856, 84.06858, 70.66739, NA, 79.72284, 91.5099…
## $ precio_gas_natural <dbl> 134.10288, 102.80182, 72.73675, 101.51064, 133.7802…
## $ precio_gasolina    <dbl> 85.22463, 58.80204, 62.35808, 48.59105, 43.80961, 4…
## $ precio_petroleo    <dbl> 77.70500, 108.36269, 118.78963, 105.69747, 115.3072…

1.5 Creación columnas mes y año

daily_all <- daily_all %>%
mutate(year = year(date), month = month(date), ym = as.yearmon(date))


head(daily_all)
## # A tibble: 6 × 8
##   date       precio_carbon precio_gas_natural precio_gasolina precio_petroleo
##   <date>             <dbl>              <dbl>           <dbl>           <dbl>
## 1 2000-01-01          56.8              134.             85.2            77.7
## 2 2000-01-02          84.1              103.             58.8           108. 
## 3 2000-01-03          70.7               72.7            62.4           119. 
## 4 2000-01-04          NA                102.             48.6           106. 
## 5 2000-01-05          79.7              134.             43.8           115. 
## 6 2000-01-06          91.5               78.6            41.9           101. 
## # ℹ 3 more variables: year <dbl>, month <dbl>, ym <yearmon>

1.6 Revisión valores faltantes por columna y sustitución por promedio mes/año

# Porcentaje de NA por columna
na_summary <- daily_all %>%
summarize(across(starts_with("precio"), ~mean(is.na(.))*100)) %>%
pivot_longer(everything(), names_to = "variable", values_to = "pct_na")
na_summary
## # A tibble: 4 × 2
##   variable           pct_na
##   <chr>               <dbl>
## 1 precio_carbon        2.14
## 2 precio_gas_natural   2.14
## 3 precio_gasolina      2.14
## 4 precio_petroleo      2.14
# Sustituir NAs por promedio del mes-año (group_by year, month)
monthly_means <- daily_all %>%
group_by(year, month) %>%
summarize(across(starts_with("precio"), ~mean(., na.rm = TRUE)), .groups = "drop")

# Unir los promedios y rellenar NAs
daily_all <- daily_all %>%
  left_join(monthly_means, by = c("year","month"), suffix = c("", "_monthly_mean")) %>%
  mutate(
    precio_carbon   = coalesce(precio_carbon, precio_carbon_monthly_mean),
    precio_gas_natural = coalesce(precio_gas_natural, precio_gas_natural_monthly_mean),
    precio_gasolina = coalesce(precio_gasolina, precio_gasolina_monthly_mean),
    precio_petroleo = coalesce(precio_petroleo, precio_petroleo_monthly_mean)
  ) %>%
  select(-ends_with("_monthly_mean"))
  
  # Verificar que no queden NAs en precios (salvo IPC o filas fuera de rango)
daily_all %>%
  summarise(across(starts_with("precio"), ~sum(is.na(.))))
## # A tibble: 1 × 4
##   precio_carbon precio_gas_natural precio_gasolina precio_petroleo
##           <int>              <int>           <int>           <int>
## 1             0                  0               0               0

1.7 Agregar a valores promedio por mes y año, filtrar Enero 2000 a Enero 2024

monthly_all <- daily_all %>%
  mutate(date = as.Date(as.yearmon(paste(year, month, sep = "-")))) %>%
  group_by(year, month, date) %>%
  summarise(across(starts_with("precio"), ~mean(., na.rm = TRUE)), .groups = "drop") %>%
  arrange(date)


# Filtrar periodo entre 2000-01 y 2024-01 inclusive
monthly_all_filtered <- monthly_all %>% filter(date >= as.Date("2000-01-01") & date <= as.Date("2024-01-31"))

nrow(monthly_all_filtered)
## [1] 289
# Preparar IPC: convertir a year-month y unir con monthly_all_filtered

# Intentaremos detectar nombre de la columna con índice y fecha
# Asumimos que ipc_raw tiene una columna de fecha y otra con el índice (llamada IPC o similar)
ipc <- ipc_raw %>% rename_with(~str_to_lower(.))
# buscar columna fecha y columna indice
date_col_ipc <- names(ipc)[sapply(ipc, function(x) any(!is.na(as.Date(as.character(x), format = "%Y-%m-%d")), na.rm = TRUE))][1]
if(is.null(date_col_ipc) || is.na(date_col_ipc)){
# buscar columna que contenga la palabra 'date' o 'fecha' o parezca año
date_col_ipc <- names(ipc)[grepl("fecha|date|anno|año|ano|mes", names(ipc), ignore.case = TRUE)][1]
}
# Elegir columna IPC (cualquier columna numérica)
ipc_value_col <- names(ipc)[sapply(ipc, is.numeric)][1]

# Crear columnas year & month en ipc
ipc2 <- ipc %>%
mutate(across(all_of(date_col_ipc), ~ as_date(.))) %>%
rename(ipc_date = all_of(date_col_ipc), ipc = all_of(ipc_value_col)) %>%
mutate(year = year(ipc_date), month = month(ipc_date)) %>%
select(year, month, ipc)


head(ipc2)
## # A tibble: 6 × 3
##    year month   ipc
##   <dbl> <dbl> <dbl>
## 1  1954     7  0.03
## 2  1954     8  0.03
## 3  1954     9  0.03
## 4  1954    10  0.03
## 5  1954    11  0.03
## 6  1954    12  0.03
# Unir
monthly_all_ipc <- monthly_all_filtered %>% left_join(ipc2, by = c("year","month"))

# Verificar NAs en ipc
sum(is.na(monthly_all_ipc$ipc))
## [1] 0

1.8

# precio_nominal: vector numérico
# year_base, month_base: integers
# ipc_col: name of ipc column in monthly data (numeric)


transform_to_real <- function(df_monthly, price_col, year_base, month_base, ipc_col = "ipc"){
# Build base ipc value
base_ipc <- df_monthly %>% filter(year == year_base, month == month_base) %>% pull(!!sym(ipc_col))
if(length(base_ipc) == 0 || is.na(base_ipc)) stop("IPC base no encontrado para el año-mes base especificado")

# new column name
new_name <- paste0(price_col, "_real_base_", year_base, sprintf("_%02d", month_base))

df_monthly %>% mutate(!!new_name := (!!sym(price_col)) * (base_ipc / (!!sym(ipc_col))))
}

# Ejemplo de aplicación para todos los bienes con base en Enero 2015 (por ejemplo)
year_base_example <- 2015
month_base_example <- 1


monthly_real <- monthly_all_ipc
for(col in names(monthly_real)[grepl("^precio", names(monthly_real))]){
monthly_real <- transform_to_real(monthly_real, col, year_base_example, month_base_example, ipc_col = "ipc")
}

# Ver primeras filas
head(monthly_real)
## # A tibble: 6 × 12
##    year month date       precio_carbon precio_gas_natural precio_gasolina
##   <dbl> <dbl> <date>             <dbl>              <dbl>           <dbl>
## 1  2000     1 2000-01-01          77.1               101.            61.6
## 2  2000     2 2000-02-01          80.8               104.            71.3
## 3  2000     3 2000-03-01          76.2               112.            66.9
## 4  2000     4 2000-04-01          74.7               106.            64.7
## 5  2000     5 2000-05-01          77.6               111.            65.2
## 6  2000     6 2000-06-01          78.3               107.            66.2
## # ℹ 6 more variables: precio_petroleo <dbl>, ipc <dbl>,
## #   precio_carbon_real_base_2015_01 <dbl>,
## #   precio_gas_natural_real_base_2015_01 <dbl>,
## #   precio_gasolina_real_base_2015_01 <dbl>,
## #   precio_petroleo_real_base_2015_01 <dbl>

1.9

# Crear la misma transformación con otra base, p.ej. 2023-12
monthly_real_alt <- monthly_all_ipc
for(col in names(monthly_real_alt)[grepl("^precio", names(monthly_real_alt))]){
monthly_real_alt <- transform_to_real(monthly_real_alt, col, 2023, 12, ipc_col = "ipc")
}

# Comprobar relación entre columnas reales con distintas bases (deberían ser escala multiplicativa entre sí)
# Tomar un bien p.ej precio_petroleo_real_base_2015_01 y precio_petroleo_real_base_2023_12 si existen
real_cols_2015 <- names(monthly_real)[grepl("_real_base_2015_01", names(monthly_real))]
real_cols_2023 <- names(monthly_real_alt)[grepl("_real_base_2023_12", names(monthly_real_alt))]

# Mostrar razón promedio entre las series reales según base (para un bien arbitrario si existe)
if(length(real_cols_2015) > 0 && length(real_cols_2023) > 0){
# elegir primer bien
b1_2015 <- monthly_real[[real_cols_2015[1]]]
b1_2023 <- monthly_real_alt[[real_cols_2023[1]]]
tibble(mean_ratio = mean(b1_2015 / b1_2023, na.rm = TRUE))
} else {
tibble(info = "No se encontraron columnas reales con los sufijos esperados")
}
## # A tibble: 1 × 1
##   mean_ratio
##        <dbl>
## 1      0.603

1.10

write_csv(monthly_real, "consolidado_ejercicio_1610.csv")

2.1

library(dplyr)
library(tidyr)
library(stringr)

# Función para generar tabla de estadísticas descriptivas
stats_table <- function(data, cols) {
  data %>%
    select(all_of(cols)) %>%
    pivot_longer(everything(), names_to = "variable", values_to = "valor") %>%
    separate(variable, into = c("tipo", "combustible"), sep = "_", extra = "merge") %>%
    group_by(combustible) %>%
    summarise(
      
      n_obs = sum(!is.na(valor)),
      
      media = mean(valor, na.rm = TRUE),
      
      minimo = min(valor, na.rm = TRUE),
      
      maximo = max(valor, na.rm = TRUE),
      
      desv_est = sd(valor, na.rm = TRUE),
      
      .groups = "drop"
    ) %>%
    arrange(combustible)
}
nominal_cols <- c("precio_carbon", "precio_gas_natural", "precio_gasolina", "precio_petroleo")

real_cols <- c("precio_carbon_real_base_2015_01",
               "precio_gas_natural_real_base_2015_01",
               "precio_gasolina_real_base_2015_01",
               "precio_petroleo_real_base_2015_01")
stats_nominal <- stats_table(monthly_real, nominal_cols)
stats_real <- stats_table(monthly_real, real_cols)
stats_nominal
## # A tibble: 4 × 6
##   combustible n_obs media minimo maximo desv_est
##   <chr>       <int> <dbl>  <dbl>  <dbl>    <dbl>
## 1 carbon        289  97.0   74.2   123.    12.7 
## 2 gas_natural   289 118.    98.6   138.     8.37
## 3 gasolina      289 109.    61.6   166.    25.8 
## 4 petroleo      289 108.    91.2   130.     7.98
stats_real
## # A tibble: 4 × 6
##   combustible                   n_obs media minimo maximo desv_est
##   <chr>                         <int> <dbl>  <dbl>  <dbl>    <dbl>
## 1 carbon_real_base_2015_01        289  107.   60.8   163.    19.8 
## 2 gas_natural_real_base_2015_01   289  134.   59.0   221.    33.6 
## 3 gasolina_real_base_2015_01      289  117.   90.8   144.     8.55
## 4 petroleo_real_base_2015_01      289  122.   63.2   198.    29.7
stats_nominal <- stats_nominal %>% mutate(tipo = "Nominal")
stats_real <- stats_real %>% mutate(tipo = "Real")

tabla_final <- bind_rows(stats_nominal, stats_real) %>%
  relocate(tipo, .before = combustible)

tabla_final
## # A tibble: 8 × 7
##   tipo    combustible                   n_obs media minimo maximo desv_est
##   <chr>   <chr>                         <int> <dbl>  <dbl>  <dbl>    <dbl>
## 1 Nominal carbon                          289  97.0   74.2   123.    12.7 
## 2 Nominal gas_natural                     289 118.    98.6   138.     8.37
## 3 Nominal gasolina                        289 109.    61.6   166.    25.8 
## 4 Nominal petroleo                        289 108.    91.2   130.     7.98
## 5 Real    carbon_real_base_2015_01        289 107.    60.8   163.    19.8 
## 6 Real    gas_natural_real_base_2015_01   289 134.    59.0   221.    33.6 
## 7 Real    gasolina_real_base_2015_01      289 117.    90.8   144.     8.55
## 8 Real    petroleo_real_base_2015_01      289 122.    63.2   198.    29.7

2.2

# --- Gráfico de dispersión de precios reales de carbón vs gasolina ---

# Año que deseas graficar
plot_year <- 2023

# Encontrar los nombres de las columnas de precios reales
carbon_real_col <- names(monthly_real_alt)[grepl("precio_carbon.*_real_base_", names(monthly_real_alt))][1]
gasolina_real_col <- names(monthly_real_alt)[grepl("precio_gasolina.*_real_base_", names(monthly_real_alt))][1]

# Filtrar los datos del año seleccionado
plot_df <- monthly_real_alt %>%
  filter(year == plot_year) %>%
  select(all_of(c(carbon_real_col, gasolina_real_col))) %>%
  drop_na()

# Cargar la librería ggplot2
library(ggplot2)

if (!exists("plot_df")) stop("plot_df no existe. Ejecuta el bloque que crea plot_df antes.")
plot_df2 <- plot_df %>% 
select(1:2) %>%  
rename(x = 1, y = 2)
plot_df2 <- plot_df2 %>% 
  mutate(
    x = as.numeric(as.character(x)),
    y = as.numeric(as.character(y))
  )
cat("nrow(plot_df2) =", nrow(plot_df2), " ---- clases: x =", class(plot_df2$x), " y =", class(plot_df2$y), "\n")
## nrow(plot_df2) = 12  ---- clases: x = numeric  y = numeric
p <- ggplot(plot_df2, aes(x = x, y = y)) +
  geom_point(color = "blue") +
  geom_smooth(method = "lm", se = TRUE, color = "gold") +
  labs(
    title = paste("Relacion entre precios reales de carbon y gasolina -", plot_year),
    x = "Precio real carbon",
    y = "Precio real gasolina"
  ) +
  theme_minimal()

print(p)
## `geom_smooth()` using formula = 'y ~ x'

2.3 Modelo de regresión lineal entre precios reales de carbón y gasolina

Verificamos que exista el data frame con los datos del punto anterior

if (!exists(“plot_df2”)) stop(“Debes ejecutar el bloque 2.2 antes de correr el 2.3”)

Ajustar modelo lineal: precio gasolina (y) ~ precio carbón (x)

modelo_23 <- lm(y ~ x, data = plot_df2)

Mostrar resumen del modelo

summary(modelo_23)

— Visualización y tabla resumen en HTML —

library(broom) library(kableExtra)

Extraer coeficientes de la regresión

coeficientes_23 <- tidy(modelo_23)

Crear tabla HTML bonita

coeficientes_23 %>% kable(format = “html”, digits = 5, caption = “Coeficientes del modelo lineal (Precio real gasolina ~ Precio real carbón)”) %>% kable_styling(full_width = FALSE, bootstrap_options = c(“striped”, “hover”, “condensed”))

— Interpretación adicional con estadísticos clave —

r2 <- summary(modelo_23)\(r.squared p_value <- coeficientes_23\)p.value[2] pendiente <- coeficientes_23$estimate[2]

cat(“*Interpretación:**“) cat(”La pendiente estimada es de”, round(pendiente, 5), “, lo que indica que por cada unidad que aumenta el precio real del carbón,”, “el precio real de la gasolina cambia en promedio en esa magnitud.”) cat(“El coeficiente de determinación R² es de”, round(r2, 3), “, lo que indica que el modelo explica aproximadamente el”, round(r2 * 100, 1), “% de la variabilidad del precio real de la gasolina.”) cat(“El valor-p asociado a la pendiente es de”, signif(p_value, 4), ifelse(p_value < 0.05, “, por lo tanto existe una relación estadísticamente significativa entre ambas variables.”, “, lo que sugiere que la relación no es significativa a un nivel del 5%.”), “”)

— Añadimos línea de regresión al gráfico anterior —

p + geom_smooth(method = “lm”, se = TRUE, color = “red”) + labs( title = paste(“Relación y regresión entre precios reales de carbón y gasolina -”, plot_year), subtitle = paste(“Pendiente:”, round(pendiente, 4), ” | R²:“, round(r2, 3)) )