library(readr) # lectura del csv
library(here) # rutas robustas relativas a la raíz del proyecto
library(dplyr) # manipulación de datos
library(ggplot2) # gráficos
library(kableExtra) # tablas con diseño
library(DT) # tabla interactiva paginada
cat("Librerías cargadas: readr, dplyr, ggplot2, kableExtra, DT")Librerías cargadas: readr, dplyr, ggplot2, kableExtra, DT
## DATASET ##
# Archivo: kansas_limpio.csv (Kansas Corporation Commission - registro de pozos)
# IMPORTANTE: ajusta esta ruta a la ubicación real del archivo en tu equipo.
ruta_archivo <- here("kansas_limpio.csv")
datos_crudos <- read_csv(ruta_archivo, show_col_types = FALSE)
# Construcción de la variable independiente:
# DIST_ESTE = distancia, en grados decimales de longitud, desde el pozo
# más oriental registrado en el estado (se usa como "borde oriental").
# Se suma 1 para evitar valores de 0, ya que este modelo logarítmico
# requiere aplicar logaritmo a X.
min_lon_abs <- min(abs(datos_crudos$lon), na.rm = TRUE)
datos_crudos$DIST_ESTE <- abs(datos_crudos$lon) - min_lon_abs + 1
# Se descartan pozos sin profundidad registrada o con profundidad no
# positiva (no tienen sentido físico y además impiden aplicar logaritmo a X).
datos <- datos_crudos %>%
filter(DEPTH_OF_WELL > 0, !is.na(DIST_ESTE), !is.na(DEPTH_OF_WELL))
## Estructura de los datos
str(datos[, c("DIST_ESTE", "DEPTH_OF_WELL")])tibble [41,971 × 2] (S3: tbl_df/tbl/data.frame)
$ DIST_ESTE : num [1:41971] 2.27 2.07 7.66 1.04 2.44 ...
$ DEPTH_OF_WELL: num [1:41971] 700 1125 2940 437 675 ...
Este documento es la segunda parte de un análisis geológico más amplio sobre los pozos de Kansas, en el que la profundidad de los pozos se estudia en función de su posición geográfica de este a oeste dentro del estado. Como esa relación no es la misma en todo el rango (ver Conjetura), el estudio completo se dividió en tres tramos, cada uno documentado por separado: un tramo oriental (modelo potencial), el tramo centro-oriental más amplio que se presenta aquí (modelo logarítmico) y el tramo occidental (modelo lineal).
Se definió la Distancia al Borde Oriental
(DIST_ESTE, en grados decimales de longitud) como variable
independiente / causa (x), ya que representa qué tan
lejos se encuentra un pozo, de este a oeste, respecto al punto más
oriental del estado.
La Profundidad del Pozo (DEPTH_OF_WELL,
en pies) actúa como variable dependiente / efecto (y),
pues la formación productora que se perfora cambia sistemáticamente
según la región geológica en la que se ubica el pozo.
max_x_total <- max(datos$DIST_ESTE)
min_x_total <- min(datos$DIST_ESTE)
max_y_total <- max(datos$DEPTH_OF_WELL)
min_y_total <- min(datos$DEPTH_OF_WELL)
resumen_general <- data.frame(
Variable = c("DIST_ESTE (X)", "DEPTH_OF_WELL (Y)"),
Minimo = round(c(min_x_total, min_y_total), 2),
Maximo = round(c(max_x_total, max_y_total), 2),
Rango = round(c(max_x_total - min_x_total, max_y_total - min_y_total), 2),
Media = round(c(mean(datos$DIST_ESTE), mean(datos$DEPTH_OF_WELL)), 2)
)
resumen_general %>%
kbl(caption = "Tabla N°1: Resumen General de las Variables (dataset completo, 3 tramos)") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE) %>%
column_spec(1:5, extra_css = "text-align:center;")| Variable | Minimo | Maximo | Rango | Media |
|---|---|---|---|---|
| DIST_ESTE (X) | 1.01 | 8.43 | 7.43 | 5.46 |
| DEPTH_OF_WELL (Y) | 1.00 | 9999.00 | 9998.00 | 3545.84 |
El dataset completo (41971 pozos) se dividió en tres tramos según
DIST_ESTE. Este documento trabaja con un tramo más
amplio que el del modelo potencial: abarca desde el borde
oriental hasta el punto en que la profundidad promedio deja de crecer y
comienza a descender (el “pico” de profundidad). En todo este tramo la
profundidad crece, pero cada vez más lento a medida que
aumenta la distancia — el comportamiento típico de un modelo
logarítmico.
limite_inf <- 0.9889444 # equivalente a 94.6° de longitud absoluta (borde oriental de Kansas)
limite_sup <- 6.9889444 # equivalente a 100.6° de longitud absoluta (pico de profundidad)
datos_tramo <- datos %>% filter(DIST_ESTE >= limite_inf, DIST_ESTE <= limite_sup)
cat("Pozos en el tramo centro-oriental (modelo logarítmico):", nrow(datos_tramo), "\n")Pozos en el tramo centro-oriental (modelo logarítmico): 28336
cat("Rango de DIST_ESTE en este tramo:", round(min(datos_tramo$DIST_ESTE),2), "-", round(max(datos_tramo$DIST_ESTE),2))Rango de DIST_ESTE en este tramo: 1.01 - 6.99
Al haber miles de pozos que comparten valores muy cercanos de
DIST_ESTE, trabajar con los datos crudos implica manejar
una nube saturada de puntos. Por ello se agrupan los pozos en
bandas de 0.2 grados de DIST_ESTE y se
calcula la media de profundidad dentro de cada banda,
obteniendo un único par (x̄, ȳ) por banda.
tabla_xy <- datos_tramo %>%
mutate(banda = round(DIST_ESTE / 0.2) * 0.2) %>%
group_by(banda) %>%
summarise(
n_pozos = n(),
x_medio = mean(DIST_ESTE),
y_medio = mean(DEPTH_OF_WELL),
.groups = "drop"
) %>%
arrange(banda) %>%
select(-banda)
cat("Total de pares (x̄, ȳ) obtenidos, uno por banda de 0.2°:", nrow(tabla_xy), "\n")Total de pares (x̄, ȳ) obtenidos, uno por banda de 0.2°: 31
datatable(
tabla_xy,
caption = htmltools::tags$caption(
style = "caption-side: top; text-align: left; font-size: 16px; font-weight: 700; color:#1F2A33;",
"Tabla N°2: Pares (x̄, ȳ) por banda de longitud — Tramo Centro-Oriental"
),
rownames = FALSE,
class = "display compact stripe hover",
options = list(pageLength = 10, dom = "ltip")
) %>%
formatRound(columns = c("x_medio", "y_medio"), digits = 3)par(mar = c(5, 5, 4, 2))
plot(
datos_tramo$DIST_ESTE, datos_tramo$DEPTH_OF_WELL,
col = adjustcolor("#E67E22", alpha.f = 0.35),
pch = 16, cex = 0.6,
xlab = "Distancia al Borde Oriental (X, grados)", ylab = "Profundidad del Pozo (Y, pies)",
main = "Gráfica N°1: Nube de puntos cruda — Tramo Centro-Oriental",
cex.main = 0.9, frame.plot = FALSE
)
grid(nx = NULL, ny = NULL, col = "#D7DBDD", lty = "dotted")
box()par(mar = c(5, 5, 4, 2))
plot(tabla_xy$x_medio, tabla_xy$y_medio, pch = 19, col = "#E67E22",
xlab = "X medio (Distancia al Borde Oriental)", ylab = "Y medio (Profundidad del Pozo)",
main = "Gráfica N°2: Nube de Puntos Promediada — Tramo Centro-Oriental",
cex.main = 0.9, frame.plot = FALSE)
grid(nx = NULL, ny = NULL, col = "#D7DBDD", lty = "dotted")
box()Al observar la nube de puntos promediada, la profundidad sigue creciendo a lo largo de todo el tramo, pero el ritmo de crecimiento se frena notoriamente a medida que aumenta la distancia: los incrementos son grandes al inicio (cerca del borde oriental) y cada vez más pequeños conforme el pozo se acerca al punto de profundidad máxima — un patrón de crecimiento rápido seguido de una meseta, característico de un modelo logarítmico. Se conjetura: \[y = a + b \cdot \ln(x)\]
modelo <- lm(y_medio ~ log(x_medio), data = tabla_xy)
a <- coef(modelo)[1]
b <- coef(modelo)[2]
cat("y =", round(a, 2), "+", round(b, 2), "* ln(x)")y = -305.78 + 2731.18 * ln(x)
Call:
lm(formula = y_medio ~ log(x_medio), data = tabla_xy)
Residuals:
Min 1Q Median 3Q Max
-620.44 -274.70 -145.08 82.67 1273.74
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) -305.8 219.1 -1.395 0.173
log(x_medio) 2731.2 159.9 17.077 <0.0000000000000002 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 474.9 on 29 degrees of freedom
Multiple R-squared: 0.9095, Adjusted R-squared: 0.9064
F-statistic: 291.6 on 1 and 29 DF, p-value: < 0.00000000000000022
par(mar = c(5, 5, 4, 2))
plot(tabla_xy$x_medio, tabla_xy$y_medio, col = "#E67E22", pch = 16,
xlab = "X (Distancia al Borde Oriental)", ylab = "Y (Profundidad del Pozo)",
main = "Gráfica N°3: Modelo Logarítmico vs. Realidad — Tramo Centro-Oriental",
cex.main = 0.9, frame.plot = FALSE)
grid(nx = NULL, ny = NULL, col = "#D7DBDD", lty = "dotted")
curve(a + b * log(x), add = TRUE, col = "#1F2A33", lwd = 3)
legend("topleft", legend = c("Datos (x̄, ȳ)", "Modelo Logarítmico"),
col = c("#E67E22", "#1F2A33"), pch = c(16, NA), lwd = c(NA, 3), bty = "n")
box()El coeficiente de correlación de Pearson, calculado en R mediante
cor(x, y), debe superar 0.7 o -0.7 para
aceptar el modelo. Para el modelo logarítmico (monótono, pero no lineal
en su escala original) se prueba dicho coeficiente sobre la escala en la
que el modelo sí es lineal: ln(x) frente a
y.
r <- cor.test(log(tabla_xy$x_medio), tabla_xy$y_medio)
tabla_pearson <- data.frame(
Modelo = "Logarítmico (Tramo Centro-Oriental)",
r = round(r$estimate, 4),
R2 = round(r$estimate^2, 4),
Supera_0.7 = abs(r$estimate) > 0.7,
p_valor_modelo = pf(summary(modelo)$fstatistic[1], summary(modelo)$fstatistic[2],
summary(modelo)$fstatistic[3], lower.tail = FALSE)
)
tabla_pearson %>%
kbl(caption = "Tabla N°3: Test de Bondad de Ajuste — Modelo Logarítmico") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE)| Modelo | r | R2 | Supera_0.7 | p_valor_modelo | |
|---|---|---|---|---|---|
| cor | Logarítmico (Tramo Centro-Oriental) | 0.9537 | 0.9095 | TRUE | 0 |
El modelo supera el umbral de |r| > 0.7 y el
estadístico F es significativo (p-valor < 0.05), por lo que
el modelo logarítmico se acepta para este tramo.
El modelo es válido únicamente dentro del rango de X para el que fue ajustado; no se recomienda extrapolar fuera de este rango.
DIST_ESTE (desplazada para partir de 1).x_est <- round(mean(range(tabla_xy$x_medio)), 2)
y_est <- a + b * log(x_est)
data.frame(
X_estimado = x_est,
Y_estimado = round(y_est, 1)
) %>%
kbl(caption = "Tabla N°4: Estimación Puntual de Profundidad — Tramo Centro-Oriental") %>%
kable_styling(bootstrap_options = c("striped", "hover", "condensed"), full_width = FALSE)| X_estimado | Y_estimado | |
|---|---|---|
| (Intercept) | 4 | 3480.4 |
ln(x)
vs. y).