Modelo de Regresión Potencial
library(readxl)
library(dplyr)
library(gt)
datos <- read_excel("dataset_mundial_petro.xlsx")
cat("Número de registros:", nrow(datos), "\n")
## Número de registros: 8334
cat("Número de variables:", ncol(datos), "\n")
## Número de variables: 23
La variable Discovery year (año de descubrimiento) actúa como variable independiente o causa (X), ya que el año en que se descubre un yacimiento antecede necesariamente a su puesta en producción. La variable Production start year (año de inicio de producción) actúa como variable dependiente o efecto (Y), ya que depende del tiempo de desarrollo posterior al descubrimiento.
Ambas variables son siempre positivas (años calendario), condición necesaria para un modelo potencial \(y = a \cdot x^{b}\), ya que requiere calcular \(\ln(x)\) y \(\ln(y)\).
Production start year viene como texto porque incluye
valores como “2025 (expected)”; se extrae el año numérico de esos
casos.
extraer_anio <- function(v) as.numeric(sub("^(\\d{4}).*", "\\1", as.character(v)))
x_raw <- as.numeric(datos$`Discovery year`)
y_raw <- extraer_anio(datos$`Production start year`)
cat("Registros con Discovery year:", sum(!is.na(x_raw)), "\n")
## Registros con Discovery year: 4935
cat("Registros con Production start year:", sum(!is.na(y_raw)), "\n")
## Registros con Production start year: 2233
cat("Pares completos (ambos con dato):", sum(!is.na(x_raw) & !is.na(y_raw)), "\n")
## Pares completos (ambos con dato): 1889
cat("X sin Y:", sum(!is.na(x_raw) & is.na(y_raw)), "\n")
## X sin Y: 3046
cat("Y sin X:", sum(is.na(x_raw) & !is.na(y_raw)), "\n")
## Y sin X: 344
Se presenta un extracto (primeros 20 registros) tal como fueron extraídos del dataset, antes de cualquier depuración.
df_pares <- data.frame(x = x_raw, y = y_raw)
df_pares %>%
head(20) %>%
rename(`Año de Descubrimiento (X)` = x,
`Año de Inicio de Producción (Y)` = y) %>%
gt() %>%
tab_header(
title = md("**Tabla de Pares de Valores**"),
subtitle = md("Valores originales sin depurar")
) %>%
tab_source_note(source_note = "Autor: Grupo 5") %>%
cols_align(align = "center", columns = everything()) %>%
tab_options(
table.border.top.color = "black",
table.border.bottom.color = "black",
table.border.top.style = "solid",
table.border.bottom.style = "solid",
column_labels.font.weight = "bold",
column_labels.border.top.color = "black",
column_labels.border.bottom.color = "black",
column_labels.border.bottom.width = px(2),
heading.border.bottom.color = "black",
heading.border.bottom.width = px(2),
table_body.hlines.color = "grey",
table_body.border.bottom.color = "black"
)
| Tabla de Pares de Valores | |
| Valores originales sin depurar | |
| Año de Descubrimiento (X) | Año de Inicio de Producción (Y) |
|---|---|
| 1949 | 1951 |
| 2001 | 2009 |
| 1966 | 1969 |
| 1975 | 1979 |
| 1984 | 1987 |
| 1986 | 1998 |
| 1981 | 1981 |
| 2004 | 2005 |
| NA | NA |
| NA | NA |
| 1981 | 1985 |
| 1986 | 2002 |
| 1982 | 1987 |
| 2007 | NA |
| 1965 | 1965 |
| 2000 | 2010 |
| 2013 | 2020 |
| 2001 | NA |
| 1979 | 1983 |
| 1999 | 2021 |
| Autor: Grupo 5 | |
plot(df_pares$x, df_pares$y,
pch = 20,
col = rgb(0.1, 0.4, 0.5, 0.4),
xlab = "Año de Descubrimiento (X)",
ylab = "Año de Inicio de Producción (Y)",
main = "Relación entre Año de Descubrimiento y Año de Inicio de Producción (Datos Originales)")
Debido a la dispersión y a los múltiples valores de Y repetidos para un mismo X, se procede a aplicar una estrategia de tratamiento de datos antes de proponer un modelo.
A diferencia de un modelo polinómico, un modelo potencial trabaja en escala logarítmica (\(\ln x\), \(\ln y\)), donde cualquier valor artificial (como rellenar con la media global) distorsiona fuertemente la relación: si muchos años X distintos no tienen dato real de Y y todos se completan con el mismo valor, se genera una banda plana de puntos falsos que rompe la tendencia y hunde la correlación. Por eso, en este modelo no se rellenan los faltantes: se descartan directamente los registros que no tengan ambos valores.
df_pares <- df_pares %>% filter(!is.na(x), !is.na(y))
cat("Pares completos reales (ambos datos presentes):", nrow(df_pares), "\n")
## Pares completos reales (ambos datos presentes): 1889
Cuando un mismo año de descubrimiento (X) tiene múltiples años de
inicio de producción (Y), se calcula la media
aritmética de todos esos Y para obtener un único par
representativo (un único X, un único Y). Se conserva además el número de
registros originales (n) que dieron origen a cada promedio,
dato necesario para la depuración posterior.
pares <- df_pares %>%
filter(!is.na(x), !is.na(y)) %>%
group_by(x) %>%
summarise(y = mean(y, na.rm = TRUE), n = n(), .groups = "drop") %>%
arrange(x)
cat("Pares únicos (un X, un Y) para el modelo:", nrow(pares), "\n")
## Pares únicos (un X, un Y) para el modelo: 98
cat("Rango de años:", min(pares$x), "-", max(pares$x), "\n")
## Rango de años: 1905 - 2023
Al analizar los datos agrupados se identificaron valores atípicos (pares con años de producción muy alejados de la tendencia central) y años con un solo registro original (que no aportan representatividad, pues su valor de Y no proviene de un promedio). La estrategia adoptada consiste en:
n > 1), para garantizar
representatividad.media_y <- mean(pares$y)
sd_y <- sd(pares$y)
lim_sup <- media_y + 2 * sd_y
lim_inf <- media_y - 2 * sd_y
cat("Media de Y:", round(media_y, 4), "\n")
## Media de Y: 1986.281
cat("Desv. estándar de Y:", round(sd_y, 4), "\n")
## Desv. estándar de Y: 30.3537
cat("Límite superior:", round(lim_sup, 4), "\n")
## Límite superior: 2046.988
cat("Límite inferior:", round(lim_inf, 4), "\n")
## Límite inferior: 1925.574
pares_dep <- pares %>%
filter(y >= lim_inf & y <= lim_sup) %>%
filter(n > 1) %>%
filter(x > 0, y > 0) # el modelo potencial exige X, Y positivos
cat("\nPares antes de depuración:", nrow(pares), "\n")
##
## Pares antes de depuración: 98
cat("Pares después de depuración:", nrow(pares_dep), "\n")
## Pares después de depuración: 84
cat("Pares eliminados (atípicos, un único registro, o no positivos):",
nrow(pares) - nrow(pares_dep), "\n")
## Pares eliminados (atípicos, un único registro, o no positivos): 14
pares_dep %>%
select(x, y) %>%
rename(`Año de Descubrimiento (X)` = x,
`Año de Inicio de Producción (Y)` = y) %>%
mutate(`Año de Inicio de Producción (Y)` = round(`Año de Inicio de Producción (Y)`, 4)) %>%
gt() %>%
tab_header(
title = md("**Tabla de Pares Depurados**"),
subtitle = md("Año de Descubrimiento y Año de Inicio de Producción")
) %>%
tab_source_note(source_note = "Autor: Grupo 5") %>%
cols_align(align = "center", columns = everything()) %>%
tab_options(
table.border.top.color = "black",
table.border.bottom.color = "black",
table.border.top.style = "solid",
table.border.bottom.style = "solid",
column_labels.font.weight = "bold",
column_labels.border.top.color = "black",
column_labels.border.bottom.color = "black",
column_labels.border.bottom.width = px(2),
heading.border.bottom.color = "black",
heading.border.bottom.width = px(2),
table_body.hlines.color = "grey",
table_body.border.bottom.color = "black"
)
| Tabla de Pares Depurados | |
| Año de Descubrimiento y Año de Inicio de Producción | |
| Año de Descubrimiento (X) | Año de Inicio de Producción (Y) |
|---|---|
| 1927 | 1940.500 |
| 1928 | 1944.500 |
| 1932 | 1935.500 |
| 1937 | 1963.500 |
| 1938 | 1966.000 |
| 1941 | 1949.500 |
| 1944 | 1944.000 |
| 1945 | 1947.000 |
| 1946 | 1973.333 |
| 1948 | 1951.250 |
| 1949 | 1955.143 |
| 1951 | 1966.571 |
| 1952 | 1958.857 |
| 1953 | 1964.000 |
| 1954 | 1966.444 |
| 1955 | 1977.077 |
| 1956 | 1973.143 |
| 1957 | 1968.833 |
| 1958 | 1975.188 |
| 1959 | 1972.625 |
| 1960 | 1980.923 |
| 1961 | 1982.133 |
| 1962 | 1974.850 |
| 1963 | 1972.909 |
| 1964 | 1977.529 |
| 1965 | 1984.879 |
| 1966 | 1980.667 |
| 1967 | 1989.281 |
| 1968 | 1986.303 |
| 1969 | 1990.536 |
| 1970 | 1986.762 |
| 1971 | 1992.086 |
| 1972 | 1988.590 |
| 1973 | 1996.821 |
| 1974 | 1996.902 |
| 1975 | 1993.756 |
| 1976 | 1998.350 |
| 1977 | 1997.767 |
| 1978 | 1995.826 |
| 1979 | 1998.600 |
| 1980 | 1995.500 |
| 1981 | 1993.963 |
| 1982 | 1998.605 |
| 1983 | 1999.939 |
| 1984 | 1998.903 |
| 1985 | 2002.500 |
| 1986 | 2000.735 |
| 1987 | 2000.710 |
| 1988 | 2001.148 |
| 1989 | 2005.100 |
| 1990 | 2005.739 |
| 1991 | 2002.036 |
| 1992 | 2007.576 |
| 1993 | 2004.667 |
| 1994 | 2005.000 |
| 1995 | 2003.846 |
| 1996 | 2004.482 |
| 1997 | 2005.500 |
| 1998 | 2004.697 |
| 1999 | 2007.708 |
| 2000 | 2010.471 |
| 2001 | 2008.811 |
| 2002 | 2012.040 |
| 2003 | 2013.704 |
| 2004 | 2013.963 |
| 2005 | 2015.524 |
| 2006 | 2015.708 |
| 2007 | 2016.160 |
| 2008 | 2015.512 |
| 2009 | 2017.667 |
| 2010 | 2019.686 |
| 2011 | 2020.103 |
| 2012 | 2023.000 |
| 2013 | 2022.808 |
| 2014 | 2021.023 |
| 2015 | 2020.250 |
| 2016 | 2021.929 |
| 2017 | 2023.095 |
| 2018 | 2023.786 |
| 2019 | 2022.680 |
| 2020 | 2025.067 |
| 2021 | 2022.500 |
| 2022 | 2027.600 |
| 2023 | 2023.667 |
| Autor: Grupo 5 | |
plot(pares_dep$x, pares_dep$y,
pch = 20,
col = rgb(0.1, 0.4, 0.5, 0.6),
xlab = "Año de Descubrimiento (X)",
ylab = "Año de Inicio de Producción (Y)",
main = "Relación entre Año de Descubrimiento y Año de Inicio de Producción (Datos Depurados)")
Observando la gráfica de los datos depurados, se propone un Modelo de Regresión Potencial, ya que ambas variables son estrictamente positivas y la tendencia muestra un crecimiento sostenido de Y a medida que X aumenta, sin cambios de dirección. Este modelo tiene la forma:
\[y = a \cdot x^{b}\]
El modelo potencial no es lineal en X, pero se linealiza aplicando logaritmo natural a ambos lados:
\[\ln(y) = \ln(a) + b \cdot \ln(x)\]
Esta expresión sí es lineal en \(\ln(x)\), por lo que R puede estimar \(\ln(a)\) y \(b\) mediante mínimos cuadrados con
lm, y luego se recupera \(a =
e^{\ln(a)}\).
m_potencial <- lm(log(y) ~ log(x), data = pares_dep)
coefs <- coef(m_potencial)
ln_a <- coefs[1]
b <- coefs[2]
a <- exp(ln_a)
cat("ln(a) :", round(ln_a, 6), "\n")
## ln(a) : 0.871664
cat("a :", round(a, 8), "\n")
## a : 2.390887
cat("b :", round(b, 6), "\n")
## b : 0.886026
cat("\nEcuación del modelo:\n")
##
## Ecuación del modelo:
cat("y =", format(a, scientific = TRUE, digits = 6), "* x^(", round(b, 6), ")\n")
## y = 2.39089e+00 * x^( 0.886026 )
Se realiza la superposición del modelo ajustado sobre los datos reales para evaluar visualmente qué tan bien representa la curva potencial el comportamiento observado.
x_grid <- seq(min(pares_dep$x), max(pares_dep$x), length.out = 400)
y_grid <- a * x_grid^b
plot(pares_dep$x, pares_dep$y,
pch = 20,
col = rgb(0.1, 0.4, 0.5, 0.6),
xlab = "Año de Descubrimiento (X)",
ylab = "Año de Inicio de Producción (Y)",
main = "Superposición: Modelo Potencial y Datos Reales")
lines(x_grid, y_grid, col = "firebrick3", lwd = 3)
legend("topleft",
legend = c("Datos reales", "Modelo potencial"),
col = c(rgb(0.1, 0.4, 0.5, 0.6), "firebrick3"),
pch = c(20, NA),
lty = c(NA, 1),
lwd = c(NA, 3),
bty = "n")
r <- cor(pares_dep$x, pares_dep$y)
cat("Correlación de Pearson (r):", round(r, 4), "\n")
## Correlación de Pearson (r): 0.9699
El modelo potencial se ajusta realmente sobre \(\ln(x)\) y \(\ln(y)\), por lo que también se reporta la correlación en esa escala, que es la que sustenta directamente el ajuste por mínimos cuadrados.
r_log <- cor(log(pares_dep$x), log(pares_dep$y))
cat("Correlación de Pearson en escala log-log (r):", round(r_log, 4), "\n")
## Correlación de Pearson en escala log-log (r): 0.9696
Como el modelo se linealiza en escala logarítmica, el
R² obtenido de m_potencial corresponde a
la bondad de ajuste sobre \(\ln(x)\) y
\(\ln(y)\), no sobre la escala
original:
r2 <- summary(m_potencial)$r.squared
cat("R² (escala log-log):", round(r2, 4), "\n")
## R² (escala log-log): 0.9401
El dominio de la variable independiente X (año de descubrimiento) corresponde a números enteros positivos: \(X \in \mathbb{Z}^{+}\), condición que exige el modelo potencial (no está definido para \(X \le 0\)). El dominio de la variable dependiente Y (año de inicio de producción) corresponde también a años calendario positivos, y por realismo histórico se acota entre 1859 (primer pozo petrolero comercial documentado) y 2100.
Como el modelo es potencial con b > 0 (crecimiento monótono), Y aumenta de forma continua conforme X aumenta, sin cambios de dirección. Por lo tanto, basta con despejar X a partir de los límites de Y para conocer el rango válido:
\[x = \left(\frac{y}{a}\right)^{1/b}\]
y_min_dominio <- 1859
y_max_dominio <- 2100
x_min_valido <- (y_min_dominio / a)^(1 / b)
x_max_valido <- (y_max_dominio / a)^(1 / b)
cat("El modelo se mantiene dentro del dominio de Y [", y_min_dominio, ",", y_max_dominio, "]\n")
## El modelo se mantiene dentro del dominio de Y [ 1859 , 2100 ]
cat("para valores de X comprendidos entre:", round(x_min_valido, 0), "y", round(x_max_valido, 0), "\n")
## para valores de X comprendidos entre: 1830 y 2100
Conclusión de la sección: el modelo sí presenta restricciones. Es válido únicamente para años de descubrimiento comprendidos entre 1830 y 2100. Fuera de este intervalo, la curva potencial produce años de inicio de producción fuera del rango histórico/realista considerado.
Aprovechando la ecuación del modelo potencial, se realizan estimaciones dentro del rango válido determinado en la sección anterior.
anio_estimar <- 2015
produccion_estimada <- a * anio_estimar^b
cat("Estimación para un yacimiento descubierto en", anio_estimar, ":\n")
## Estimación para un yacimiento descubierto en 2015 :
cat("Año estimado de inicio de producción:", round(produccion_estimada, 1), "\n")
## Año estimado de inicio de producción: 2024.1
cat("¿Dentro del dominio válido? :", anio_estimar >= x_min_valido & anio_estimar <= x_max_valido, "\n\n")
## ¿Dentro del dominio válido? : TRUE
anio_estimar2 <- 2020
produccion_estimada2 <- a * anio_estimar2^b
cat("Estimación para un yacimiento descubierto en", anio_estimar2, ":\n")
## Estimación para un yacimiento descubierto en 2020 :
cat("Año estimado de inicio de producción:", round(produccion_estimada2, 1), "\n")
## Año estimado de inicio de producción: 2028.6
cat("¿Dentro del dominio válido? :", anio_estimar2 >= x_min_valido & anio_estimar2 <= x_max_valido, "\n")
## ¿Dentro del dominio válido? : TRUE
Se presenta a continuación la tabla resumen del modelo, como base para la conclusión.
Tabla_resumen <- data.frame(
`Variable Independiente` = "Año de Descubrimiento",
`Variable Dependiente` = "Año de Inicio de Producción",
`Test Pearson` = round(r, 4),
`Test Pearson (log-log)` = round(r_log, 4),
`Ecuación del modelo` = ec,
`Rango válido de X` = paste0("[", round(x_min_valido, 0), ", ", round(x_max_valido, 0), "]"),
check.names = FALSE
)
Tabla_resumen %>%
gt() %>%
tab_header(
title = md("**Tabla N°1**"),
subtitle = md("**Resumen del modelo de regresión potencial**")
) %>%
tab_source_note(source_note = md("Autor: Grupo 5")) %>%
cols_align(align = "center", columns = everything()) %>%
tab_options(
table.border.top.color = "black",
table.border.bottom.color = "black",
table.border.top.style = "solid",
table.border.bottom.style = "solid",
column_labels.font.weight = "bold",
column_labels.border.top.color = "black",
column_labels.border.bottom.color = "black",
column_labels.border.bottom.width = px(2),
heading.border.bottom.color = "black",
heading.border.bottom.width = px(2),
table_body.hlines.color = "grey",
table_body.border.bottom.color = "black"
)
| Tabla N°1 | |||||
| Resumen del modelo de regresión potencial | |||||
| Variable Independiente | Variable Dependiente | Test Pearson | Test Pearson (log-log) | Ecuación del modelo | Rango válido de X |
|---|---|---|---|---|---|
| Año de Descubrimiento | Año de Inicio de Producción | 0.9699 | 0.9696 | y = 2.39089e+00 * x^(0.886026) | [1830, 2100] |
| Autor: Grupo 5 | |||||
Entre el año de descubrimiento (X) y el año de inicio de producción (Y) existe una relación potencial, cuya ecuación es:
y = 2.39089e+00 * x^(0.886026)
Siendo X el año de descubrimiento del yacimiento y Y el año estimado de inicio de producción. La correlación de Pearson en escala log-log es de 0.9696, lo que indica un ajuste fuerte del modelo. El modelo presenta restricciones: es válido únicamente para años de descubrimiento comprendidos entre 1830 y 2100, ya que fuera de ese intervalo el modelo produce años de inicio de producción fuera del rango histórico/realista considerado.