library(dplyr)
library(gt)
# NOTA: el archivo CSV debe estar en la misma carpeta que este .Rmd
# (por defecto, al hacer Knit, R usa esa carpeta como directorio de trabajo)
lineas <- readLines("Oil__Gas____Other_Regulated_Wells__Beginning_1860 (1).csv",
encoding = "latin1", warn = FALSE)
Encoding(lineas) <- "latin1"
lineas <- iconv(lineas, from = "latin1", to = "UTF-8")
datos <- read.csv(text = lineas, sep = ",", header = TRUE,
stringsAsFactors = FALSE)
cat("Número de registros:", nrow(datos), "\n")
## Número de registros: 47396
cat("Número de variables:", ncol(datos), "\n")
## Número de variables: 52
Extracto del dataset
datos %>%
head(5) %>%
gt() %>%
tab_header(
title = md("**Extracto del Dataset**"),
subtitle = md("Primeras 5 filas, todas las columnas del dataset original")
) %>%
tab_source_note(source_note = "Autor: Grupo 1") %>%
cols_align(align = "center", columns = everything()) %>%
tab_style(
style = list(cell_fill(color = col_encabezado), cell_text(color = "white", weight = "bold")),
locations = cells_title()
) %>%
tab_style(
style = list(cell_fill(color = col_encabezado), cell_text(color = "white", weight = "bold")),
locations = cells_column_labels()
) %>%
tab_style(
style = list(cell_fill(color = col_fila_alt)),
locations = cells_body(rows = seq(1, 5, 2))
) %>%
tab_style(
style = cell_borders(sides = "all", color = col_borde, weight = px(1)),
locations = list(cells_body(), cells_column_labels())
) %>%
opt_table_outline(style = "solid", width = px(3), color = col_borde) %>%
tab_options(
table.border.top.color = col_borde,
table.border.bottom.color = col_borde,
table.border.top.style = "solid",
table.border.bottom.style = "solid",
column_labels.border.top.color = col_borde,
column_labels.border.bottom.color = col_borde,
column_labels.border.bottom.width = px(2),
heading.border.bottom.color = col_borde,
heading.border.bottom.width = px(2),
table.font.size = px(12),
data_row.padding = px(6),
column_labels.background.color = col_encabezado,
container.overflow.x = TRUE,
table.width = pct(100)
)
| Extracto del Dataset | |||||||||||||||||||||||||||||||||||||||||||||||||||
| Primeras 5 filas, todas las columnas del dataset original | |||||||||||||||||||||||||||||||||||||||||||||||||||
| API.Well.Number | County.Code | API.Hole.Number | Sidetrack | Completion | Well.Name | Company.Name | Operator.Number | Well.Type | Map.Symbol | Well.Status | Status.Date | Permit.Application.Date | Permit.Issued.Date | Date.Spudded | Date.of.Total.Depth | Date.Well.Completed | Date.Well.Plugged | Date.Well.Confidentiality.Ends | Confidentiality.Code | Town | Quad | Quad.Section | Producing.Field | Producing.Formation | Financial.Security | Slant | County | Region | State.Lease | Proposed.Depth..ft | Surface.Longitude | Surface.Latitude | Bottom.Hole.Longitude | Bottom.Hole.Latitude | True.Vertical.Depth..ft | Measured.Depth..ft | Kickoff..ft | Drilled.Depth..ft | Elevation..ft | Original.Well.Type | Permit.Fee | Objective.Formation | Depth.Fee | Spacing | Spacing.Acres | Integration | Hearing.Date | Date.Last.Modified | DEC.Database.Link | Location.1 | Georeference |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 31003670100000 | 3 | 67010 | 0 | 0 | Voided Permit | 9998 | NL | O | VP | Pre-1989 Well (N/A) | False | Vertical | Statewide | 9 | NA | 0 | NA | NA | NA | NA | 0 | 0 | 0 | 0 | NA | NL | 0 | 0 | NA | 06/28/1995 12:00:00 AM | http://extapps.dec.ny.gov/cfmx/extapps/GasOil/search/wells/index.cfm?api=31003670100000 | ||||||||||||||||||||
| 31003672540000 | 3 | 67254 | 0 | 0 | Voided Permit | 9998 | NL | O | VP | Pre-1989 Well (N/A) | A | False | Vertical | Statewide | 9 | NA | 0 | NA | NA | NA | NA | 0 | 0 | 0 | 0 | NA | NL | 0 | 0 | NA | 07/05/1995 12:00:00 AM | http://extapps.dec.ny.gov/cfmx/extapps/GasOil/search/wells/index.cfm?api=31003672540000 | |||||||||||||||||||
| 31003673010000 | 3 | 67301 | 0 | 0 | 9998 | NL | O | UN | Pre-1989 Well (N/A) | False | Vertical | Statewide | 9 | NA | 0 | NA | NA | NA | NA | 0 | 0 | 0 | 0 | NA | NL | 0 | 0 | NA | 12/20/2019 03:27:41 PM | http://extapps.dec.ny.gov/cfmx/extapps/GasOil/search/wells/index.cfm?api=31003673010000 | |||||||||||||||||||||
| 31003686440000 | 3 | 68644 | 0 | 0 | Voided Permit | 9998 | NL | O | VP | Pre-1989 Well (N/A) | A | False | Vertical | Statewide | 9 | NA | 0 | NA | NA | NA | NA | 0 | 0 | 0 | 0 | NA | NL | 0 | 0 | NA | 08/15/1995 12:00:00 AM | http://extapps.dec.ny.gov/cfmx/extapps/GasOil/search/wells/index.cfm?api=31003686440000 | |||||||||||||||||||
| 31003694660000 | 3 | 69466 | 0 | 0 | Bradford 48 | Bradley Producing Company | 9673 | OD | OWP | PA | Pre-1989 Well (N/A) | Clarksville | Bolivar | B | False | Vertical | Allegany | 9 | NA | 0 | -78.19359 | 42.08821 | -78.19359 | 42.08821 | 0 | 0 | 0 | 0 | NA | NL | 0 | 0 | NA | 03/01/2000 12:00:00 AM | http://extapps.dec.ny.gov/cfmx/extapps/GasOil/search/wells/index.cfm?api=31003694660000 | (42.08821, -78.19359) | POINT (-78.19359 42.08821) | ||||||||||||||
| Autor: Grupo 1 | |||||||||||||||||||||||||||||||||||||||||||||||||||
Proposed Depth, ft (profundidad propuesta en el
permiso).Measured Depth, ft (profundidad medida real del pozo).Justificación causa-efecto:La profundidad propuesta (Proposed Depth) corresponde a la profundidad planificada en el permiso de perforación, mientras que la profundidad medida (Measured Depth) es la alcanzada al finalizar el pozo. Dado que la profundidad propuesta orienta la planificación técnica de la perforación, influye directamente en la profundidad final obtenida, estableciendo una relación de causa (X) → efecto (Y). pozo.
# Detección automática de columnas (los nombres pueden variar entre el CSV
# de muestra y el CSV local: puntos extra, mayúsculas/minúsculas, etc.)
col_x <- names(datos)[grepl("proposed", names(datos), ignore.case = TRUE) &
grepl("depth", names(datos), ignore.case = TRUE)][1]
col_y <- names(datos)[grepl("measured", names(datos), ignore.case = TRUE) &
grepl("depth", names(datos), ignore.case = TRUE)][1]
if (is.na(col_x) || is.na(col_y)) {
stop("No se encontraron las columnas de Proposed Depth / Measured Depth. ",
"Nombres disponibles: ", paste(names(datos), collapse = ", "))
}
x_raw <- suppressWarnings(as.numeric(as.character(datos[[col_x]])))
y_raw <- suppressWarnings(as.numeric(as.character(datos[[col_y]])))
cat("Registros con Proposed Depth:", sum(!is.na(x_raw) & x_raw > 0), "\n")
## Registros con Proposed Depth: 16507
cat("Registros con Measured Depth:", sum(!is.na(y_raw) & y_raw > 0), "\n")
## Registros con Measured Depth: 32765
Se conservan únicamente los pares donde ambas variables son mayores que 0, ya que un valor de 0 o vacío significa que ese pozo no llegó a esa etapa (por ejemplo, tiene permiso pero nunca se perforó, o se perforó pero no se registró la profundidad propuesta).
df_raw <- data.frame(x = x_raw, y = y_raw) %>%
filter(!is.na(x), !is.na(y), x > 0, y > 0)
cat("Tamaño muestral (pares completos, Proposed Depth > 0 y Measured Depth > 0):",
nrow(df_raw), "\n")
## Tamaño muestral (pares completos, Proposed Depth > 0 y Measured Depth > 0): 14047
Nota: no se despliega la tabla completa; a continuación solo se muestran las primeras filas.
head(df_raw, 10) %>%
rename(`Proposed Depth, ft (X)` = x,
`Measured Depth, ft (Y)` = y) %>%
gt() %>%
tab_header(
title = md("**Tabla de Pares de Valores (primeras filas)**"),
subtitle = md("Proposed Depth y Measured Depth")
) %>%
tab_source_note(source_note = "Autor: Grupo 1") %>%
cols_align(align = "center", columns = everything()) %>%
tab_style(
style = list(cell_fill(color = col_encabezado), cell_text(color = "white", weight = "bold")),
locations = cells_title()
) %>%
tab_style(
style = list(cell_fill(color = col_encabezado), cell_text(color = "white", weight = "bold")),
locations = cells_column_labels()
) %>%
tab_style(
style = list(cell_fill(color = col_fila_alt)),
locations = cells_body(rows = seq(1, 10, 2))
) %>%
opt_table_outline(style = "solid", width = px(3), color = col_borde) %>%
tab_options(
table.border.top.color = col_borde,
table.border.bottom.color = col_borde,
table.border.top.style = "solid",
table.border.bottom.style = "solid",
column_labels.border.top.color = col_borde,
column_labels.border.bottom.color = col_borde,
column_labels.border.bottom.width = px(2),
heading.border.bottom.color = col_borde,
heading.border.bottom.width = px(2),
table_body.hlines.color = "#CBD5DE",
table_body.border.bottom.color = col_borde,
table.font.size = px(14),
data_row.padding = px(6),
table_body.border.top.style = "solid",
column_labels.background.color = col_encabezado
)
| Tabla de Pares de Valores (primeras filas) | |
| Proposed Depth y Measured Depth | |
| Proposed Depth, ft (X) | Measured Depth, ft (Y) |
|---|---|
| 1465 | 1465 |
| 1400 | 1400 |
| 700 | 1000 |
| 1250 | 1220 |
| 2300 | 2352 |
| 1300 | 1400 |
| 2300 | 2136 |
| 1500 | 1332 |
| 3600 | 3906 |
| 1950 | 1898 |
| Autor: Grupo 1 | |
plot(df_raw$x, df_raw$y,
pch = 20,
col = rgb(0.04, 0.18, 0.29, 0.15),
xlab = "Proposed Depth, ft (X)",
ylab = "Measured Depth, ft (Y)",
main = "Gráfica original: Proposed Depth en comparación con Measured Depth")
La nube de puntos muestra una tendencia creciente que sugiere una relación exponencial entre la profundidad propuesta (X) y la profundidad medida (Y). Debido a la dispersión y la presencia de valores atípicos, se realiza un tratamiento previo de los datos para mejorar el ajuste del modelo.
a) Único X (agrupación por valor exacto de X): Cuando varios registros presentan el mismo valor de Proposed Depth (X), se calcula la media de Measured Depth (Y) para obtener un único par representativo. Este procedimiento agrupa únicamente valores idénticos de X, sin crear intervalos artificiales.
b) Único Y: No aplica, ya que el análisis considera a Measured Depth (Y) como variable dependiente de Proposed Depth (X), por lo que no es necesario agrupar por valores de Y.
c) Segmentar por partes: No aplica, porque los datos no presentan cambios de comportamiento que justifiquen dividir el rango de Proposed Depth (X) en segmentos para realizar ajustes independientes.
# c) Omisión de outliers — filtro de coherencia física
df_raw <- df_raw %>% mutate(razon = y / x)
n_antes <- nrow(df_raw)
df_raw <- df_raw %>% filter(razon > 0.5, razon < 2) %>% select(-razon)
n_despues <- nrow(df_raw)
cat("Pares antes del filtro de coherencia física:", n_antes, "\n")
## Pares antes del filtro de coherencia física: 14047
cat("Pares tras el filtro de coherencia física:", n_despues, "\n")
## Pares tras el filtro de coherencia física: 13893
cat("Descartados por razón no física (outliers):", n_antes - n_despues, "\n\n")
## Descartados por razón no física (outliers): 154
# a) Único X — agrupación por valor exacto de X (media de Y repetidos)
pares <- df_raw %>%
group_by(x) %>%
summarise(y = mean(y, na.rm = TRUE), .groups = "drop") %>%
arrange(x)
cat("Pares únicos para el modelo (tras agrupar por X):", nrow(pares), "\n")
## Pares únicos para el modelo (tras agrupar por X): 2360
plot(pares$x, pares$y,
pch = 20,
col = rgb(0.04, 0.18, 0.29, 0.35),
xlab = "Proposed Depth, ft (X)",
ylab = "Measured Depth, ft (Y)",
main = "Gráfica tras tratamiento")
Tras el tratamiento, la nube de puntos conserva la misma forma genera. Se confirma visualmente la tendencia de crecimiento acelerado propia de una relación exponencial, por lo que se mantiene la conjetura:
\[y = a \cdot e^{bx}\]
Estrategia de ajuste — reducción del eje Y con logaritmo: el modelo exponencial no es lineal en sus parámetros, por lo que se linealiza aplicando logaritmo natural a Y:
\[\ln(y) = \ln(a) + bx\]
Esta es una recta en las variables \((x,
\ln y)\): intercepto \(\ln(a)\),
pendiente \(b\). El eje Y se reduce a
\(\ln(y)\) antes de ajustar el modelo
con lm(); luego se recupera \(a\) con exp().
pares$log_y <- log(pares$y)
plot(pares$x, pares$log_y,
pch = 20,
col = rgb(0.04, 0.18, 0.29, 0.35),
xlab = "Proposed Depth, ft (X)",
ylab = "ln(Measured Depth, ft) — eje Y reducido",
main = "Linealización: ln(Y) en comparación con X")
m_exp <- lm(log_y ~ x, data = pares)
sum_reg <- summary(m_exp)
coefs <- coef(m_exp)
intercepto <- coefs[1]
pendiente <- coefs[2]
a <- exp(intercepto)
b <- pendiente
cat("Intercepto en espacio log [ln(a)] :", round(intercepto, 6), "\n")
## Intercepto en espacio log [ln(a)] : 7.024228
cat("Pendiente (b) :", round(b, 8), "\n")
## Pendiente (b) : 0.00026612
cat("Parámetro a = exp(intercepto) :", round(a, 4), "\n")
## Parámetro a = exp(intercepto) : 1123.527
cat("\nEcuación del modelo exponencial:\n")
##
## Ecuación del modelo exponencial:
cat("y =", round(a, 4), "* e^(", round(b, 8), "x )\n")
## y = 1123.527 * e^( 0.00026612 x )
x_grid <- seq(min(pares$x), max(pares$x), length.out = 400)
log_y_grid <- predict(m_exp, newdata = data.frame(x = x_grid))
y_grid <- exp(log_y_grid)
plot(pares$x, pares$y,
pch = 20,
col = rgb(0.04, 0.18, 0.29, 0.15),
xlab = "Proposed Depth, ft (X)",
ylab = "Measured Depth, ft (Y)",
main = "Superposición: Modelo Exponencial y Datos Reales")
lines(x_grid, y_grid, col = col_curva, lwd = 3)
legend("topleft",
legend = c("Datos reales", "Modelo exponencial"),
col = c(col_puntos, col_curva),
pch = c(20, NA),
lty = c(NA, 1),
lwd = c(NA, 3),
bty = "n")
La curva del modelo sigue de cerca la tendencia central de la nube de puntos real, lo que respalda visualmente la elección del modelo exponencial.
Explicación: como el modelo se ajustó linealizado (sobre \(\ln y\)), el test de Pearson correcto para este modelo se calcula entre X y \(\ln(Y)\), que es donde la relación es realmente lineal.
r <- cor(pares$x, pares$log_y)
r2 <- sum_reg$r.squared * 100
cat("Correlación de Pearson (r), entre X y ln(Y):", round(r, 4), "\n")
## Correlación de Pearson (r), entre X y ln(Y): 0.9093
cat("Coeficiente de determinación (R²%):", round(r2, 2), "%\n")
## Coeficiente de determinación (R²%): 82.69 %
El coeficiente de determinación (R²) indica qué
porcentaje de la variación en \(\ln(\text{Measured Depth})\) es explicado
por Proposed Depth.
El modelo exponencial estimado es válido únicamente bajo las siguientes restricciones:
x_estimar1 <- round(min(pares$x), 2)
y_estimada1 <- exp(predict(m_exp, newdata = data.frame(x = x_estimar1)))
cat("Estimación para X =", x_estimar1, "ft:\n")
## Estimación para X = 56 ft:
cat("Measured Depth estimado:", round(y_estimada1, 2), "ft\n\n")
## Measured Depth estimado: 1140.4 ft
x_estimar2 <- round(max(pares$x), 2)
y_estimada2 <- exp(predict(m_exp, newdata = data.frame(x = x_estimar2)))
cat("Estimación para X =", x_estimar2, "ft:\n")
## Estimación para X = 13450 ft:
cat("Measured Depth estimado:", round(y_estimada2, 2), "ft\n\n")
## Measured Depth estimado: 40274.72 ft
# Ejemplo puntual solicitado en el documento de referencia
x_estimar3 <- 1500
y_estimada3 <- exp(predict(m_exp, newdata = data.frame(x = x_estimar3)))
cat("Estimación para X =", x_estimar3, "ft:\n")
## Estimación para X = 1500 ft:
cat("Measured Depth estimado:", round(y_estimada3, 2), "ft\n")
## Measured Depth estimado: 1674.72 ft
Ecuacion <- paste0("y = ", round(a, 4), " * e^(", round(b, 8), " x )")
Tabla_resumen <- data.frame(
`Variable Independiente` = "Proposed Depth, ft",
`Variable Dependiente` = "Measured Depth, ft",
`Test Pearson (X en comparación con ln Y)` = round(r, 4),
`Coeficiente de determinación` = round(r2, 2),
`Ecuación del modelo` = Ecuacion,
check.names = FALSE
)
Tabla_resumen %>%
gt() %>%
tab_header(
title = md("**Tabla N°1**"),
subtitle = md("**Resumen del modelo de regresión exponencial**")
) %>%
tab_source_note(source_note = md("Autor: Grupo 1")) %>%
cols_align(align = "center", columns = everything()) %>%
tab_style(
style = list(cell_fill(color = col_encabezado), cell_text(color = "white", weight = "bold")),
locations = cells_title()
) %>%
tab_style(
style = list(cell_fill(color = col_encabezado), cell_text(color = "white", weight = "bold")),
locations = cells_column_labels()
) %>%
tab_style(
style = list(cell_fill(color = col_fila_alt)),
locations = cells_body(rows = 1)
) %>%
opt_table_outline(style = "solid", width = px(3), color = col_borde) %>%
tab_options(
table.border.top.color = col_borde,
table.border.bottom.color = col_borde,
table.border.top.style = "solid",
table.border.bottom.style = "solid",
column_labels.border.top.color = col_borde,
column_labels.border.bottom.color = col_borde,
column_labels.border.bottom.width = px(2),
heading.border.bottom.color = col_borde,
heading.border.bottom.width = px(2),
table_body.hlines.color = "#CBD5DE",
table_body.border.bottom.color = col_borde,
table.font.size = px(14),
data_row.padding = px(6)
)
| Tabla N°1 | ||||
| Resumen del modelo de regresión exponencial | ||||
| Variable Independiente | Variable Dependiente | Test Pearson (X en comparación con ln Y) | Coeficiente de determinación | Ecuación del modelo |
|---|---|---|---|---|
| Proposed Depth, ft | Measured Depth, ft | 0.9093 | 82.69 | y = 1123.5266 * e^(0.00026612 x ) |
| Autor: Grupo 1 | ||||
Entre la profundidad propuesta
(Proposed Depth, X) y la profundidad
medida (Measured Depth, Y) existe una relación
exponencial, ajustada mediante linealización logarítmica, cuya ecuación
es:
\[y = 1123.5266 \cdot e^{0.0002661 \, x}\]
Con una correlación de Pearson (entre X y \(\ln Y\)) de 0.91 y un coeficiente de determinación de 82.69%, el modelo respalda la hipótesis de que la profundidad real alcanzada durante la perforación crece de forma multiplicativa —no aditiva— respecto de la profundidad planificada en el permiso: mientras más profundo se planea perforar, mayor es, proporcionalmente, la profundidad extra que termina alcanzándose en la práctica. El modelo debe interpretarse dentro de las restricciones señaladas en la Sección 10, especialmente el rango de validez de X.