1 Carga de librerías

library(dplyr)
library(ggplot2)
library(gt)
library(stringr)
library(plotly)

2 Carga de datos

# IMPORTANTE: ajustar la ruta a la ubicación local del archivo
setwd("C:/Users/veru2/Downloads")

Datos <- read.csv("Oil__Gas____Other_Regulated_Wells__Beginning_1860 (3).csv",
                   header = TRUE, sep = ";", dec = ",",
                   fileEncoding = "latin1")

cat("Número de registros:", nrow(Datos), "\n") 
## Número de registros: 47407
cat("Número de variables:", ncol(Datos), "\n")
## Número de variables: 55

3 Selección y definición de variables

Justificación de causa y efecto: la profundidad vertical real (Y) es, esencialmente, el resultado de la profundidad planificada (X₁) ajustada por la condición de terreno del emplazamiento (X₂). X₁ actúa como la causa principal, pues define la meta de perforación establecida en el permiso; X₂ actúa como una causa complementaria, pues la elevación del terreno modifica la distancia vertical real que debe recorrerse para alcanzar la misma formación geológica objetivo. Ambos factores interactúan para determinar el resultado final (efecto) de la perforación.

# Selección de variables
datos_model <- Datos %>%
  select(`True.Vertical.Depth..ft`, `Proposed.Depth..ft`, `Elevation..ft`) %>%
  mutate(
    y  = as.numeric(str_replace(`True.Vertical.Depth..ft`, ",", ".")),
    x1 = as.numeric(str_replace(`Proposed.Depth..ft`,      ",", ".")),
    x2 = as.numeric(str_replace(`Elevation..ft`,            ",", "."))
  ) %>%
  filter(!is.na(y) & !is.na(x1) & !is.na(x2)) %>%
  filter(y > 0 & x1 > 0 & x2 > 0)

y  <- datos_model$y    # True Vertical Depth
x1 <- datos_model$x1   # Proposed Depth
x2 <- datos_model$x2   # Elevation

cat("Tamaño muestral (tripletas completas y válidas):", nrow(datos_model), "\n")
## Tamaño muestral (tripletas completas y válidas): 13718

4 Tripleta de valores

A diferencia de un modelo simple —donde cada X tiene asociada una Y—, en un modelo de regresión múltiple cada tripleta de valores está formada por dos causas y un efecto: para cada par (X₁, X₂) existe una única Y asociada. Es decir, por cada Proposed Depth (X₁) y cada Elevation (X₂) registrados para un mismo pozo, existe una True Vertical Depth (Y) que representa el resultado observado.

tripletas <- datos_model %>%
  select(x1, x2, y) %>%
  arrange(x1)

cat("Número de tripletas (X1, X2, Y):", nrow(tripletas), "\n")
## Número de tripletas (X1, X2, Y): 13718

4.1 Tabla de tripletas

Por tratarse de una muestra grande, se despliega una vista representativa de la tabla de tripletas (primeras 15 filas), manteniendo la misma lógica de tres columnas usada en el modelo de referencia, pero adaptada a dos variables independientes y una dependiente.

tripletas %>%
  slice_head(n = 15) %>%
  rename(`Proposed Depth, ft (X1)` = x1,
         `Elevation, ft (X2)`      = x2,
         `True Vertical Depth, ft (Y)` = y) %>%
  mutate(across(everything(), ~round(.x, 2))) %>%
  gt() %>%
  tab_header(
    title    = md("**Tabla de Tripletas de Valores**"),
    subtitle = md("Proposed Depth, Elevation y True Vertical Depth (muestra de 15 filas)")
  ) %>%
  tab_source_note(source_note = "Autor: Grupo 1") %>%
  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 Tripletas de Valores
Proposed Depth, Elevation y True Vertical Depth (muestra de 15 filas)
Proposed Depth, ft (X1) Elevation, ft (X2) True Vertical Depth, ft (Y)
114 948 114
200 560 254
200 560 261
200 600 107
200 560 750
275 1680 2917
350 560 480
350 560 476
350 560 323
350 600 207
350 560 448
350 560 358
400 1257 401
400 1241 432
400 1252 411
Autor: Grupo 1

5 Análisis Gráfico Exploratorio (3D)

El gráfico 3D interactivo permite rotar y ampliar la visualización para analizar la distribución y posible relación entre la profundidad objetivo, la elevación y la profundidad vertical real.

plot_ly(
  x = ~x1,
  y = ~x2,
  z = ~y,
  type = "scatter3d",
  mode = "markers",
  marker = list(
    size = 3,
    color = "#0B2F4A",
    line = list(color = "#0B2F4A", width = 0.5),
    opacity = 0.5
  ),
  name = "Pozos"
) %>%
  layout(
    title = list(
      text = "Gráfica N°1: Profundidad Vertical Real (ft) en función de la Profundidad Objetivo y la Elevación",
      font = list(size = 12),
      x = 0.5,
      xanchor = 'center'
    ),
    scene = list(
      xaxis = list(title = list(text = "Profundidad Objetivo, ft [X1]", font = list(size = 10))),
      yaxis = list(title = list(text = "Elevación, ft [X2]", font = list(size = 10))),
      zaxis = list(title = list(text = "Profundidad Vertical Real, ft [Y]", font = list(size = 10))),
      camera = list(eye = list(x = 1.6, y = 1.6, z = 1.2))
    ),
    margin = list(t = 50)
  )

6 Conjetura del Modelo de Regresión Múltiple

Observando la nube de puntos en 3D, se propone un Modelo de Regresión Lineal Múltiple, ya que la profundidad vertical real parece responder de forma conjunta y aproximadamente lineal a la profundidad objetivo y a la elevación del terreno. Se plantea la ecuación del plano:

\[y = \beta_0 + \beta_1 \cdot X_1 + \beta_2 \cdot X_2\]

Explicación: lm(y ~ x1 + x2) ajusta, por mínimos cuadrados, el plano que mejor se acerca a los puntos \((x_{1i}, x_{2i}, y_i)\).

modelo <- lm(y ~ x1 + x2)

7 Cálculo de Parámetros

Explicación: coef(modelo) extrae los tres coeficientes del plano ajustado: el intercepto (\(\beta_0\)) y las dos pendientes (\(\beta_1\), \(\beta_2\)).

coefs <- coef(modelo)
b0 <- coefs[1]
b1 <- coefs[2]
b2 <- coefs[3]

cat("Intercepto (b0) :", round(b0, 4), "\n")
## Intercepto (b0) : -1.8543
cat("Pendiente  (b1) :", round(b1, 6), "\n")
## Pendiente  (b1) : 0.972987
cat("Pendiente  (b2) :", round(b2, 6), "\n")
## Pendiente  (b2) : 0.027143
ecuacion <- paste0(
  "y = ", round(b0, 4),
  " + ", round(b1, 6), "\u00b7X1",
  " + ", round(b2, 6), "\u00b7X2"
)

cat("\nEcuación estimada del modelo:\n\n", ecuacion)
## 
## Ecuación estimada del modelo:
## 
##  y = -1.8543 + 0.972987·X1 + 0.027143·X2

8 Comparación del Modelo con la Realidad

Se visualiza el plano de regresión múltiple junto con los datos reales, permitiendo observar el ajuste del modelo y la relación conjunta entre la profundidad objetivo, la elevación y la profundidad vertical real.

Explicación: grid_x1 y grid_x2 crean una rejilla de valores para dibujar el plano de forma continua. outer() calcula, para cada combinación de X1 y X2 de la rejilla, el valor de Y que predice el plano ajustado. Luego se dibujan dos capas con plotly: el plano ajustado (type = "surface") y los puntos reales (type = "scatter3d") superpuestos.

# Crear grilla de valores
grid_x1 <- seq(min(x1), max(x1), length.out = 50)   # Proposed Depth
grid_x2 <- seq(min(x2), max(x2), length.out = 50)   # Elevation

# Calcular plano ajustado
z_plano <- t(outer(grid_x1, grid_x2, function(x1_val, x2_val) {
  b0 + (b1 * x1_val) + (b2 * x2_val)
}))

# Gráfico interactivo
plot_ly() %>%
  add_trace(
    x = grid_x1,
    y = grid_x2,
    z = z_plano,
    type = "surface",
    colorscale = list(c(0, 1), c("#FDE9C8", "#D97706")),
    opacity = 0.7,
    name = "Plano Ajustado",
    showscale = FALSE
  ) %>%
  add_trace(
    x = ~x1,
    y = ~x2,
    z = ~y,
    type = "scatter3d",
    mode = "markers",
    marker = list(size = 3, color = "#0B2F4A", line = list(color = 'black', width = 0.5)),
    name = "Datos Reales"
  ) %>%
  layout(
    title = list(
      text = "Gráfica N°2: Plano de Regresión de la Profundidad Vertical Real (ft)",
      font = list(size = 12),
      x = 0.5,
      xanchor = 'center'
    ),
    scene = list(
      xaxis = list(title = list(text = "Profundidad Objetivo, ft [X1]", font = list(size = 10))),
      yaxis = list(title = list(text = "Elevación, ft [X2]", font = list(size = 10))),
      zaxis = list(title = list(text = "Profundidad Vertical Real, ft [Y]", font = list(size = 10))),
      camera = list(eye = list(x = 1.6, y = 1.6, z = 1.2))
    ),
    margin = list(t = 50)
  )

9 Test de Pearson

Explicación: siguiendo el comando solicitado, la correlación se calcula tal como se muestra a continuación, es decir, la correlación de Pearson entre la variable dependiente (Y) y la suma conjunta de las dos variables independientes (X1 + X2). A partir del resultado se obtiene el coeficiente de determinación elevándolo al cuadrado.

r <- cor(y, x1 + x2)
r  <- cor(y, x1 + x2)
r2 <- (r^2) * 100

cat("Correlación de Pearson (r):", round(r, 4), "\n")
## Correlación de Pearson (r): 0.9387
cat("Coeficiente de determinación (R²%):", round(r2, 2), "%\n")
## Coeficiente de determinación (R²%): 88.11 %

10 Restricciones

El modelo es válido únicamente dentro del rango de los datos observados; su uso fuera de estos límites (extrapolación) puede producir estimaciones poco confiables.

# Rango válido de las variables observadas
cat("Rango válido de Proposed Depth (X1):", round(min(x1), 2), "-", round(max(x1), 2), "ft\n")
## Rango válido de Proposed Depth (X1): 114 - 13450 ft
cat("Rango válido de Elevation (X2):     ", round(min(x2), 2), "-", round(max(x2), 2), "ft\n")
## Rango válido de Elevation (X2):      4 - 2911 ft
cat("Rango observado de True Vertical Depth (Y):", round(min(y), 2), "-", round(max(y), 2), "ft\n")
## Rango observado de True Vertical Depth (Y): 1 - 11953 ft
# Despeje de X1 y X2 a partir de la ecuación del plano, igualando Y = 0
# y = b0 + b1*X1 + b2*X2  ->  0 = b0 + b1*X1 + b2*X2

# Despejando X1 (en función de X2):  X1 = -(b0 + b2*X2) / b1
x1_despejado <- function(x2_val) -(b0 + b2 * x2_val) / b1

# Despejando X2 (en función de X1):  X2 = -(b0 + b1*X1) / b2
x2_despejado <- function(x1_val) -(b0 + b1 * x1_val) / b2

cat("\nDespeje de X1 (Y = 0), evaluado en los límites de X2:\n")
## 
## Despeje de X1 (Y = 0), evaluado en los límites de X2:
cat("  X2 =", round(min(x2), 2), "->  X1 =", round(x1_despejado(min(x2)), 2), "ft\n")
##   X2 = 4 ->  X1 = 1.79 ft
cat("  X2 =", round(max(x2), 2), "->  X1 =", round(x1_despejado(max(x2)), 2), "ft\n")
##   X2 = 2911 ->  X1 = -79.3 ft
cat("\nDespeje de X2 (Y = 0), evaluado en los límites de X1:\n")
## 
## Despeje de X2 (Y = 0), evaluado en los límites de X1:
cat("  X1 =", round(min(x1), 2), "->  X2 =", round(x2_despejado(min(x1)), 2), "ft\n")
##   X1 = 114 ->  X2 = -4018.23 ft
cat("  X1 =", round(max(x1), 2), "->  X2 =", round(x2_despejado(max(x1)), 2), "ft\n")
##   X1 = 13450 ->  X2 = -482072.8 ft
# Verificación: ¿alguna combinación de X1 y X2 (dentro de sus rangos observados)
# produce un valor de Y fuera del rango observado de Y (fuera de su dominio)?
esquinas <- expand.grid(x1 = c(min(x1), max(x1)), x2 = c(min(x2), max(x2)))
esquinas$y_estimado <- b0 + b1 * esquinas$x1 + b2 * esquinas$x2
esquinas$fuera_de_dominio <- esquinas$y_estimado < min(y) | esquinas$y_estimado > max(y)

existe_fuera_dominio <- any(esquinas$fuera_de_dominio)

print(esquinas)
##      x1   x2 y_estimado fuera_de_dominio
## 1   114    4   109.1748            FALSE
## 2 13450    4 13084.9325             TRUE
## 3   114 2911   188.0790            FALSE
## 4 13450 2911 13163.8367             TRUE
cat("\n¿Existe una combinación de X1 y X2 (en sus rangos observados) que genere",
    "\nun valor de Y fuera de su dominio (rango observado de Y)?",
    ifelse(existe_fuera_dominio, " SÍ", " NO"), "\n")
## 
## ¿Existe una combinación de X1 y X2 (en sus rangos observados) que genere 
## un valor de Y fuera de su dominio (rango observado de Y)?  SÍ
  • Rango de validez: las estimaciones solo son confiables para pozos con Proposed Depth y Elevation dentro de los rangos indicados arriba.
  • Linealidad: el modelo asume una relación lineal (de plano) entre las variables; no captura efectos curvilíneos ni interacciones entre X1 y X2.
  • Valores atípicos y ceros: se excluyeron registros con valores en 0 o NA, por lo que el modelo no contempla pozos sin dato registrado.
  • Independencia relativa de las variables: se asume que X1 y X2 no presentan colinealidad severa entre sí; si ambas estuvieran fuertemente correlacionadas, los coeficientes individuales podrían perder interpretabilidad aunque el ajuste global se mantenga.
  • Alcance geográfico: el modelo se ajustó únicamente con pozos regulados del estado de Nueva York, por lo que no debe generalizarse a otras regiones sin validación adicional.
  • Valores de Y fuera de dominio: evaluando las combinaciones extremas de X1 (entre 114 y 13450 ft) y X2 (entre 4 y 2911 ft) en la ecuación del plano, se obtiene que SÍ hay combinaciones que producen valores de Y fuera de su rango observado (1 - 11953 ft), por lo que el modelo podría generar estimaciones poco confiables en algunas esquinas del dominio. —

11 Estimaciones

¿Cuál es la profundidad vertical real estimada para un pozo con una profundidad objetivo de 2500 ft y una elevación de 1800 ft?

Explicación: predict(modelo, newdata = ...) evalúa la ecuación del plano ajustado en un punto específico \((X1, X2)\) que no necesariamente está en los datos originales.

x1_test <- 2500
x2_test <- 1800

y_est <- predict(modelo,
                  newdata = data.frame(x1 = x1_test,
                                        x2 = x2_test))

cat("Para una Profundidad Objetivo de", x1_test,
    "ft y una Elevación de", x2_test,
    "ft, la Profundidad Vertical Real estimada es:",
    round(y_est, 2), "ft")
## Para una Profundidad Objetivo de 2500 ft y una Elevación de 1800 ft, la Profundidad Vertical Real estimada es: 2479.47 ft

Tabla resumen del modelo

tabla_resumen <- data.frame(
  Variable  = c("Profundidad Objetivo, ft", "Elevación, ft", "Profundidad Vertical Real, ft"),
  Tipo      = c("Independiente (X1)", "Independiente (X2)", "Dependiente (Y)"),
  R_pearson = c("", "", round(r, 4)),
  R2        = c("", "", round(r2, 4)),
  Intercepto = c("", "", round(b0, 4)),
  Beta1      = c("", "", round(b1, 6)),
  Beta2      = c("", "", round(b2, 6)),
  Ecuacion   = c("", "", ecuacion)
)

tabla_resumen %>%
  gt() %>%
  tab_header(title = md("**Tabla N°2 del Resumen del Modelo de Regresión Múltiple**")) %>%
  tab_source_note(source_note = "Autor: Grupo 1") %>%
  cols_align(align = "center", columns = everything()) %>%
  tab_style(
    style     = list(cell_fill(color = "#0B2F4A"), cell_text(color = "white", weight = "bold")),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style     = list(cell_fill(color = "#0B2F4A"), cell_text(color = "white", weight = "bold")),
    locations = cells_title()
  ) %>%
  opt_table_outline(style = "solid", width = px(3), color = "#0B2F4A")
Tabla N°2 del Resumen del Modelo de Regresión Múltiple
Variable Tipo R_pearson R2 Intercepto Beta1 Beta2 Ecuacion
Profundidad Objetivo, ft Independiente (X1)
Elevación, ft Independiente (X2)
Profundidad Vertical Real, ft Dependiente (Y) 0.9387 88.1097 -1.8543 0.972987 0.027143 y = -1.8543 + 0.972987·X1 + 0.027143·X2
Autor: Grupo 1

12 Conclusiones

Entre la profundidad objetivo (X₁), la elevación del terreno (X₂) y la profundidad vertical real (Y) existe una relación lineal múltiple cuya ecuación matemática es:

\[y = -1.85 + (0.972987)X_1 + (0.027143)X_2\]

Siendo X₁ la profundidad objetivo planificada, medida en pies, X₂ la elevación del terreno, medida en pies sobre el nivel del mar, y Y la profundidad vertical real alcanzada durante la perforación, medida en pies. Con una correlación de Pearson de 0.94 y un coeficiente de determinación de 88.11%, el modelo refleja qué tanto la combinación de la profundidad planificada y la elevación del terreno se relaciona con la profundidad vertical real obtenida durante la perforación.

En términos generales, el modelo demuestra una adecuada capacidad predictiva dentro del rango analizado, constituyendo una herramienta válida para la estimación preliminar de la profundidad vertical de nuevos pozos regulados en el estado de Nueva York, siempre dentro de las restricciones descritas anteriormente.