1 Librerías

library(readr)      # lectura del csv
library(dplyr)       # manipulación de datos
library(ggplot2)      # gráficos
library(gt)          # tablas con diseño premium
library(stringr)      # manejo de texto
library(DT)           # tabla interactiva paginada

cat("Librerías cargadas: readr, dplyr, ggplot2, gt, stringr, DT")
Librerías cargadas: readr, dplyr, ggplot2, gt, stringr, DT

2 Carga de Datos

## DATASET ##
# Archivo con las variables AVG_PRODUCTION y CUMULATIVE_PRODUCTION.
# IMPORTANTE: ajusta esta ruta a la ubicación real del archivo en tu equipo.
ruta_archivo <- "oil_and_gas_leases_data.csv.csv"

datos <- read_csv(ruta_archivo, show_col_types = FALSE)

# Rellenamiento de celdas faltantes (NA) con la mediana de cada variable numérica de interés
if (any(is.na(datos$AVG_PRODUCTION))) {
  datos$AVG_PRODUCTION[is.na(datos$AVG_PRODUCTION)] <- median(datos$AVG_PRODUCTION, na.rm = TRUE)
}
if (any(is.na(datos$CUMULATIVE_PRODUCTION))) {
  datos$CUMULATIVE_PRODUCTION[is.na(datos$CUMULATIVE_PRODUCTION)] <- median(datos$CUMULATIVE_PRODUCTION, na.rm = TRUE)
}

# Se descartan pozos con valores no positivos (no tienen sentido físico y
# además impiden aplicar logaritmos si se necesitaran como respaldo)
datos <- datos %>%
  filter(AVG_PRODUCTION > 0, CUMULATIVE_PRODUCTION > 0)

## Estructura de los datos
str(datos[, c("AVG_PRODUCTION", "CUMULATIVE_PRODUCTION")])
tibble [47,757 × 2] (S3: tbl_df/tbl/data.frame)
 $ AVG_PRODUCTION       : num [1:47757] 859 5001 1758 377 24322 ...
 $ CUMULATIVE_PRODUCTION: num [1:47757] 47225 275063 82624 7544 681006 ...

3 Selección de Variables

Según la Tabla de Variables del proyecto, se eligió el siguiente par por ser conceptualmente directamente proporcional: un pozo con mayor producción promedio (ritmo de extracción) tiende a acumular, en total, una mayor cantidad de hidrocarburos.

Se definió la Producción Promedio Anual (AVG_PRODUCTION, cuantitativa continua, proporción, medida en barriles/año) como variable independiente / causa (x), ya que representa el ritmo al que un pozo extrae hidrocarburos.

La Producción Acumulada (CUMULATIVE_PRODUCTION, cuantitativa continua, proporción, medida en barriles) actúa como variable dependiente / efecto (y), pues refleja la cantidad total de hidrocarburos extraídos a lo largo de la vida del pozo.

Ambas variables cumplen la condición buscada: al aumentar x, y también aumenta de forma sostenida, lo que se comprueba en las secciones siguientes.

4 Tabla de Pares de Valores

4.1 Mediana de la variable Y por percentil de X

El dataset depurado contiene 47757 pozos, con valores de Producción Promedio (x) muy dispersos y sin repetirse exactamente entre pozos. Trabajar con los 47757 pares crudos genera una nube saturada y ruidosa (se muestra completa en la siguiente sección). Por ello, para el ajuste del modelo se ordenan los pozos según su Producción Promedio y se agrupan en 25 percentiles (grupos de igual cantidad de pozos), calculando la mediana (en vez de la media, para reducir el efecto de pozos atípicos con producciones extremas) de ambas variables dentro de cada grupo. Esto entrega un único par (x̃, ỹ) por percentil.

tabla_xy <- datos %>%
  mutate(percentil = ntile(AVG_PRODUCTION, 25)) %>%
  group_by(percentil) %>%
  summarise(
    n_pozos   = n(),
    x_mediana = median(AVG_PRODUCTION),
    y_mediana = median(CUMULATIVE_PRODUCTION),
    .groups = "drop"
  ) %>%
  arrange(percentil)

cat("Total de pares (x̃, ỹ) obtenidos, uno por percentil:", nrow(tabla_xy), "\n")
Total de pares (x̃, ỹ) obtenidos, uno por percentil: 25 
datatable(
  tabla_xy,
  caption = htmltools::tags$caption(
    style = "caption-side: top; text-align: left; font-size: 16px; font-weight: 700; color:#1F2A33;",
    "Tabla N°1: Pares (x̃, ỹ) — Mediana de Producción Acumulada por Percentil de Producción Promedio"
  ),
  rownames = FALSE,
  class = "display compact stripe hover",
  options = list(
    pageLength = 10,
    dom = "ltip",
    columnDefs = list(list(className = "dt-center", targets = "_all"))
  )
) %>%
  formatRound(columns = c("x_mediana", "y_mediana"), digits = 2)

4.2 Máximos, mínimos y resumen general

max_x <- max(tabla_xy$x_mediana)
min_x <- min(tabla_xy$x_mediana)
max_y <- max(tabla_xy$y_mediana)
min_y <- min(tabla_xy$y_mediana)

resumen_general <- data.frame(
  Variable = c("AVG_PRODUCTION (X)", "CUMULATIVE_PRODUCTION (Y)"),
  Minimo   = round(c(min_x, min_y), 2),
  Maximo   = round(c(max_x, max_y), 2),
  Rango    = round(c(max_x - min_x, max_y - min_y), 2),
  Mediana  = round(c(median(tabla_xy$x_mediana), median(tabla_xy$y_mediana)), 2)
)

resumen_general %>%
  gt() %>%
  tab_header(
    title = md("**Tabla N°2: Resumen General de las Variables (pares x̃, ỹ)**")
  ) %>%
  tab_source_note(source_note = "Autor: Valeska Araujo") %>%
  cols_align(align = "center", everything())
Tabla N°2: Resumen General de las Variables (pares x̃, ỹ)
Variable Minimo Maximo Rango Mediana
AVG_PRODUCTION (X) 68.76 34508.29 34439.53 2581.99
CUMULATIVE_PRODUCTION (Y) 588.22 624961.00 624372.78 53176.69
Autor: Valeska Araujo

5 Gráfica de Dispersión

5.1 Todos los valores (nube completa, 47757 pozos)

Se grafican todos los pozos del dataset, sin agrupar ni resumir, para visualizar la nube completa de puntos.

par(mar = c(5, 5, 4, 2))
plot(datos$AVG_PRODUCTION, datos$CUMULATIVE_PRODUCTION,
     pch = 16, cex = 0.35,
     col = adjustcolor("#2E86AB", alpha.f = 0.15),
     xlab = "X (Producción Promedio Anual)", ylab = "Y (Producción Acumulada)",
     main = "Gráfica N°1: Nube de Puntos — Todos los Valores",
     cex.main = 0.9, frame.plot = FALSE)
grid(nx = NULL, ny = NULL, col = "#D7DBDD", lty = "dotted")
box()

5.2 Pares (x̃, ỹ) por percentil

Con los datos ya resumidos por percentil (mediana), la tendencia ascendente se aprecia con mayor claridad, sin el ruido de los pozos atípicos.

par(mar = c(5, 5, 4, 2))
plot(tabla_xy$x_mediana, tabla_xy$y_mediana, pch = 19, col = "#2E86AB",
     xlab = "X̃ (Mediana Producción Promedio Anual)", ylab = "Ỹ (Mediana Producción Acumulada)",
     main = "Gráfica N°2: Nube de Puntos — Pares (x̃, ỹ)",
     cex.main = 0.9, frame.plot = FALSE)
grid(nx = NULL, ny = NULL, col = "#D7DBDD", lty = "dotted")
box()

6 Conjetura

Al observar ambas nubes de puntos, se aprecia una tendencia ascendente y prácticamente recta: a medida que aumenta la Producción Promedio Anual, la Producción Acumulada crece de forma sostenida y proporcional en todo el rango de X, sin cambios bruscos de patrón que obliguen a segmentar el análisis por partes.

Por lo tanto, se conjetura un modelo lineal simple, directamente proporcional: \[y = a + bx\]

con pendiente \(b > 0\) (relación directamente proporcional / ascendente).

7 Cálculo de Parámetros

El modelo se ajusta sobre los pares (x̃, ỹ) por percentil (Tabla N°1), ya que usar los 47757 pozos crudos sin resumir le da peso excesivo a los pozos atípicos con producciones extremas.

modelo <- lm(y_mediana ~ x_mediana, data = tabla_xy)
a <- coef(modelo)[1]
b <- coef(modelo)[2]
cat("Modelo ajustado: y =", round(a, 2), "+", round(b, 2), "* x\n")
Modelo ajustado: y = 2469.65 + 20.27 * x
summary(modelo)

Call:
lm(formula = y_mediana ~ x_mediana, data = tabla_xy)

Residuals:
    Min      1Q  Median      3Q     Max 
-128348   -5288   -4339   -2687  158138 

Coefficients:
             Estimate Std. Error t value            Pr(>|t|)    
(Intercept)  2469.653  11046.462   0.224               0.825    
x_mediana      20.275      1.092  18.564 0.00000000000000244 ***
---
Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1

Residual standard error: 44380 on 23 degrees of freedom
Multiple R-squared:  0.9374,    Adjusted R-squared:  0.9347 
F-statistic: 344.6 on 1 and 23 DF,  p-value: 0.000000000000002438

8 Sobreponer Modelo con la Realidad

par(mar = c(5, 5, 4, 2))
plot(tabla_xy$x_mediana, tabla_xy$y_mediana, col = "#2E86AB", pch = 16,
     xlab = "X̃ (Mediana Producción Promedio Anual)", ylab = "Ỹ (Mediana Producción Acumulada)",
     main = "Gráfica N°3: Sobreponer Modelo con la Realidad — Pares (x̃, ỹ)",
     cex.main = 0.9, frame.plot = FALSE)
grid(nx = NULL, ny = NULL, col = "#D7DBDD", lty = "dotted")
abline(modelo, col = "#1F2A33", lwd = 3)
legend("topleft", legend = c("Datos (x̃, ỹ)", "Modelo Lineal"),
       col = c("#2E86AB", "#1F2A33"), pch = c(16, NA), lwd = c(NA, 3), bty = "n")
box()

La recta sigue de cerca la dirección de los puntos, ajustándose casi perfectamente a los pares (x̃, ỹ) y confirmando una relación lineal ascendente.

9 Test de Bondad (Pearson)

El coeficiente de correlación de Pearson, calculado mediante cor(x, y), debe superar 0.7 (en valor absoluto) para aceptar el modelo lineal, dado que toma valores entre -1 y 1. Se evalúa tanto sobre los pares (x̃, ỹ) usados para ajustar el modelo, como sobre los pozos crudos (todos los valores), para verificar consistencia.

r_medianas <- cor.test(tabla_xy$x_mediana, tabla_xy$y_mediana)
r_todos    <- cor.test(datos$AVG_PRODUCTION, datos$CUMULATIVE_PRODUCTION)

tabla_pearson <- data.frame(
  Conjunto = c("Pares (x̃, ỹ) por percentil", "Todos los valores (pozos crudos)"),
  r        = round(c(r_medianas$estimate, r_todos$estimate), 4),
  R2       = round(c(r_medianas$estimate^2, r_todos$estimate^2), 4),
  Supera_0.7 = c(abs(r_medianas$estimate) > 0.7, abs(r_todos$estimate) > 0.7)
)

tabla_pearson %>%
  gt() %>%
  tab_header(
    title = md("**Tabla N°3: Test de Bondad de Ajuste**"),
    subtitle = "Umbral |r| > 0.7"
  ) %>%
  tab_source_note(source_note = "Autor: Valeska Araujo") %>%
  cols_align(align = "center", everything())
Tabla N°3: Test de Bondad de Ajuste
Umbral |r| > 0.7
Conjunto r R2 Supera_0.7
Pares (x̃, ỹ) por percentil 0.9682 0.9374 TRUE
Todos los valores (pozos crudos) 0.5449 0.2969 FALSE
Autor: Valeska Araujo

Sobre los pares (x̃, ỹ), \(r =\) 0.968 (\(R^2 =\) 0.937), muy por encima del umbral de 0.7, por lo que el modelo lineal se acepta para describir la tendencia central de la relación. Sobre los pozos crudos el coeficiente es más bajo (0.545), lo cual es esperado: al no resumir por percentil, la dispersión natural de miles de pozos individuales reduce el ajuste lineal, aunque la dirección de la recta (pendiente positiva) sigue siendo consistente con la tendencia observada.

10 Restricciones

El modelo es válido únicamente dentro del rango de X observado, aproximadamente entre 69 y 34,508 barriles/año de Producción Promedio; no se recomienda extrapolar fuera de ese rango, ya que el comportamiento de pozos con ritmos de producción muy distintos a los observados no está garantizado por los datos.

11 Estimación

x_est <- round(median(tabla_xy$x_mediana), 1)
y_est <- a + b * x_est

data.frame(
  X_estimado = x_est,
  Y_estimado = round(y_est, 1)
) %>%
  gt() %>%
  tab_header(
    title = md("**Tabla N°4: Estimación Puntual de Producción Acumulada**")
  ) %>%
  tab_source_note(source_note = "Autor: Valeska Araujo") %>%
  cols_align(align = "center", everything())
Tabla N°4: Estimación Puntual de Producción Acumulada
X_estimado Y_estimado
2582 54818.9
Autor: Valeska Araujo

Para un pozo con una producción promedio de 2,582 barriles/año, el modelo estima una producción acumulada de aproximadamente 54,818.9 barriles.

12 Conclusiones

  • Entre la Producción Promedio Anual de un pozo (X) y su Producción Acumulada (Y) existe una relación directamente proporcional: a mayor ritmo promedio de extracción, mayor producción acumulada.
  • El modelo ajustado sobre las medianas por percentil es \(y = 2469.65 + 20.27x\), con \(r = 0.968\) y \(R^2 = 0.937\), ambos muy por encima del umbral de aceptación (0.7).
  • Al trazar la recta sobre todos los valores del dataset (sin resumir), la línea sigue la dirección general de la nube completa de puntos, confirmando que el patrón ascendente no es un artefacto del resumen por percentiles.
  • El uso de la mediana (en vez de la media) para resumir cada percentil reduce la influencia de pozos atípicos con producciones extremas, dando un ajuste más robusto.
  • En conjunto, esto valida a la Producción Promedio Anual como un buen predictor lineal de la Producción Acumulada de un pozo petrolero.