1 Carga de librerias

library(tidyverse)
library(gt)
library(MASS)
if(!require(janitor)) install.packages("janitor", quiet = TRUE)
library(janitor)

2 Carga de datos

Datos_Brutos <- read.csv(
  "C:/Users/LEO/Documents/ESTA/R/Inferencial/tabela_de_pocos_janeiro_2018.csv",
  header       = TRUE,
  sep          = ",",
  dec          = ".", 
  fileEncoding = "UTF-8"
)

3 Extraer variable

Datos <- Datos_Brutos %>%
  clean_names() %>% 
  mutate(mesa_rotativa = abs(as.numeric(as.character(mesa_rotativa)))) %>%
  filter(!is.na(mesa_rotativa) & mesa_rotativa >= 0 & mesa_rotativa <= 1600)

X <- Datos$mesa_rotativa

4 Tabla de Distribución de Frecuencia

# Tabla de Distribución de Frecuencia
n_obs       <- length(X)
k_sturges   <- ceiling(1 + 3.322 * log10(n_obs))

rango_x     <- max(X) - min(X)
amplitud    <- rango_x / k_sturges

breaks_prof <- seq(min(X), max(X), length.out = k_sturges + 1)
h_total     <- hist(X, breaks = breaks_prof, plot = FALSE)
mc          <- (head(breaks_prof, -1) + tail(breaks_prof, -1)) / 2
ni          <- h_total$counts
hi          <- round((ni / sum(ni)) * 100, 2)
ni_asc      <- cumsum(ni)
hi_asc      <- round(cumsum(hi), 2)

ni_desc     <- sum(ni) - c(0, head(cumsum(ni), -1))
hi_desc     <- round(sum(hi) - c(0, head(cumsum(hi), -1)), 2)

TDF_General <- data.frame(
  Intervalo = paste0("[", round(head(breaks_prof, -1), 2), " - ", round(tail(breaks_prof, -1), 2), ")"),
  MC        = mc,
  ni        = ni,
  hi        = hi,
  Ni_asc    = ni_asc,
  Hi_asc    = hi_asc,
  Ni_desc   = ni_desc,
  Hi_desc   = hi_desc
)

totales_simplificados <- data.frame(
  Intervalo = "Totales",
  MC        = NA,
  ni        = sum(ni),
  hi        = 100.00,
  Ni_asc    = NA,
  Hi_asc    = NA,
  Ni_desc   = NA,
  Hi_desc   = NA
)

TDF_Show_Simple <- rbind(TDF_General, totales_simplificados)

TDF_Show_Simple %>%
  gt() %>%
  tab_header(
    title    = md("TABLA DE FRECUENCIAS: INFERENCIA ESTADÍSTICA"),
    subtitle = md("Variable: **Mesa Rotativa (m)**")
  ) %>%
  tab_source_note(source_note = "Fuente: Tabela de Poços 2018") %>%
  cols_label(
    Intervalo = "Mesa Rotativa (m)",
    MC        = "MC",
    ni        = "ni",
    hi        = "hi (%)",
    Ni_asc    = "Ni_asc",
    Hi_asc    = "Hi_asc (%)",
    Ni_desc   = "Ni_desc",
    Hi_desc   = "Hi_desc (%)"
  ) %>%
  fmt_number(
    columns = c(MC),
    decimals = 2
  ) %>%
  sub_missing(
    columns = everything(),
    missing_text = "-"
  ) %>%
  cols_align(align = "center", columns = everything()) %>%
  tab_style(
    style = list(cell_fill(color = "#2E4053"), cell_text(color = "white", weight = "bold")),
    locations = cells_title(groups = c("title", "subtitle"))
  ) %>%
  tab_style(
    style = list(cell_fill(color = "#F2F3F4"), cell_text(weight = "bold", color = "#2E4053")),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = cell_borders(sides = "right", color = "#D7DBDD", weight = px(4)),
    locations = cells_body(columns = everything())
  ) %>%
  tab_style(
    style = cell_borders(sides = "right", color = "#8DC3C7", weight = px(4)),
    locations = cells_column_labels(columns = everything())
  )
TABLA DE FRECUENCIAS: INFERENCIA ESTADÍSTICA
Variable: Mesa Rotativa (m)
Mesa Rotativa (m) MC ni hi (%) Ni_asc Hi_asc (%) Ni_desc Hi_desc (%)
[0 - 100) 50.00 24254 84.01 24254 84.01 28870 100.01
[100 - 200) 150.00 3902 13.52 28156 97.53 4616 16.00
[200 - 300) 250.00 421 1.46 28577 98.99 714 2.48
[300 - 400) 350.00 95 0.33 28672 99.32 293 1.02
[400 - 500) 450.00 32 0.11 28704 99.43 198 0.69
[500 - 600) 550.00 32 0.11 28736 99.54 166 0.58
[600 - 700) 650.00 30 0.10 28766 99.64 134 0.47
[700 - 800) 750.00 24 0.08 28790 99.72 104 0.37
[800 - 900) 850.00 31 0.11 28821 99.83 80 0.29
[900 - 1000) 950.00 17 0.06 28838 99.89 49 0.18
[1000 - 1100) 1,050.00 16 0.06 28854 99.95 32 0.12
[1100 - 1200) 1,150.00 5 0.02 28859 99.97 16 0.06
[1200 - 1300) 1,250.00 2 0.01 28861 99.98 11 0.04
[1300 - 1400) 1,350.00 2 0.01 28863 99.99 9 0.03
[1400 - 1500) 1,450.00 1 0.00 28864 99.99 7 0.02
[1500 - 1600) 1,550.00 6 0.02 28870 100.01 6 0.02
Totales - 28870 100.00 - - - -
Fuente: Tabela de Poços 2018

5 Análisis Gráfico

col_barras <- "#5D6D7E"
col_ejes   <- "#2E4053"

par(mar = c(7, 5, 4, 2))

# Histograma general real basado en los breaks de 100 en 100
h_plot_general <- hist(X, breaks = breaks_prof, plot = FALSE)
ylim_max <- max(h_plot_general$counts) * 1.1

# Generamos el histograma con plot()
plot(
  h_plot_general,
  main      = "Gráfica N°1: Histograma de Mesa Rotativa de Pozos en Brasil",
  cex.main  = 0.9,
  xlab      = "",
  ylab      = "Cantidad de Pozos",
  col       = col_barras, 
  border    = "white",
  axes      = FALSE, 
  ylim      = c(0, ylim_max),
  xaxt      = "n"
)

# Eje Y 
axis(2, col = col_ejes, col.axis = col_ejes)

# Eje X con las marcas exactas de los intervalos
axis(1, at = breaks_prof, labels = breaks_prof, col = col_ejes, col.axis = col_ejes, las = 2, cex.axis = 0.65)

title(xlab = "Intervalos de Mesa Rotativa (m)", line = 5.5)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")

# Líneas de corte dinámicas basadas en los valores reales
abline(v = 400, col = col_ejes, lty = "dashed", lwd = 1.5)
abline(v = 900, col = col_ejes, lty = "dashed", lwd = 1.5)

box(bty = "l", col = col_ejes)

# Leyenda 
legend(
  "topright", 
  legend = c("Histograma Empírico", "Cortes de Agrupación"),
  col = c(col_barras, col_ejes),
  pch = c(15, NA),
  lty = c(NA, 2),
  lwd = c(NA, 1.5),
  bty = "n",
  cex = 0.8
)

Esta gráfica representa la distribución de frecuencias de la mesa rotativa de los pozos petroleros en Brasil agrupados por intervalos:

  • Eje Y (\(ni\)): Muestra la cantidad de pozos (frecuencia absoluta) que se encuentran dentro de cada rango específico.
  • Eje X (Rangos): Indica los intervalos de la mesa rotativa en metros, organizados en barras verticales para visualizar su dispersión.
  • Líneas de corte: Líneas verticales discontinuas que seccionan el histograma en zonas o tendencias estadísticas diferenciadas.

5.1 Agrupación N°1

col_barras <- "#5D6D7E"
col_ejes   <- "#2E4053"
par(mar = c(7, 5, 4, 2))

X_sub1 <- X[X <= 400]
breaks_1 <- seq(0, 400, by = 50)
h1 <- hist(X_sub1, breaks = breaks_1, plot = FALSE)
ylim_max1 <- max(h1$counts) * 1.15

plot(
  h1,
  main      = "Agrupación 1: Intervalo de 0 a 400 m (Modelo Exponencial)",
  cex.main  = 0.9,
  xlab      = "",
  ylab      = "Cantidad de Pozos",
  col       = col_barras, 
  border    = "white",
  axes      = FALSE, 
  ylim      = c(0, ylim_max1)
)
axis(2, col = col_ejes, col.axis = col_ejes)
axis(1, at = breaks_1, labels = breaks_1, col = col_ejes, col.axis = col_ejes, las = 2, cex.axis = 0.7)
title(xlab = "Intervalos de Mesa Rotativa (m)", line = 5.5)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")

x_curva1 <- seq(0, 400, length.out = 200)
y_curva1 <- max(h1$counts) * exp(-0.01 * x_curva1) * 0.95
lines(x_curva1, y_curva1, col = "#C0392B", lwd = 2.5)
box(bty = "l", col = col_ejes)

legend(
  "topright", 
  legend = c("Histograma Observado", "Modelo Exponencial"),
  col = c(col_barras, "#C0392B"),
  pch = c(15, NA),
  lty = c(NA, 1),
  lwd = c(NA, 2.5),
  bty = "n",
  cex = 0.8
)

5.2 Agrupación N°2

col_barras <- "#5D6D7E"
col_ejes   <- "#2E4053"
par(mar = c(7, 5, 4, 2))

X_sub2 <- X[X > 400 & X <= 800]
breaks_2 <- seq(400, 800, by = 80)
h2 <- hist(X_sub2, breaks = breaks_2, plot = FALSE)
ylim_max2 <- max(h2$counts) * 1.15
if(ylim_max2 == 0) ylim_max2 <- 10

plot(
  h2,
  main      = "Agrupación 2: Intervalo de 400 a 900 m (Modelo Normal)",
  cex.main  = 0.9,
  xlab      = "",
  ylab      = "Cantidad de Pozos",
  col       = col_barras, 
  border    = "white",
  axes      = FALSE, 
  ylim      = c(0, ylim_max2)
)
axis(2, col = col_ejes, col.axis = col_ejes)
axis(1, at = breaks_2, labels = breaks_2, col = col_ejes, col.axis = col_ejes, las = 2, cex.axis = 0.7)
title(xlab = "Intervalos de Mesa Rotativa (m)", line = 5.5)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")

x_curva2 <- seq(400, 800, length.out = 200)
y_curva2 <- max(h2$counts) * dnorm(x_curva2, mean = mean(X_sub2), sd = sd(X_sub2)) / max(dnorm(x_curva2, mean = mean(X_sub2), sd = sd(X_sub2))) * 0.95
if(any(is.na(y_curva2))) y_curva2 <- 0
lines(x_curva2, y_curva2, col = "#27AE60", lwd = 2.5)
box(bty = "l", col = col_ejes)

legend(
  "topright", 
  legend = c("Histograma Observado", "Modelo Normal"),
  col = c(col_barras, "#27AE60"),
  pch = c(15, NA),
  lty = c(NA, 1),
  lwd = c(NA, 2.5),
  bty = "n",
  cex = 0.8
)

5.3 Agrupación N°3

col_barras <- "#5D6D7E"
col_ejes   <- "#2E4053"
par(mar = c(7, 5, 4, 2))

X_sub3 <- X[X > 800 & X <= 1600]
breaks_3 <- seq(800, 1600, by = 200)
h3 <- hist(X_sub3, breaks = breaks_3, plot = FALSE)
ylim_max3 <- max(h3$counts) * 1.15
if(ylim_max3 == 0) ylim_max3 <- 10

plot(
  h3,
  main      = "Agrupación 3: Intervalo de 900 a 1600 m (Modelo Log-Normal)",
  cex.main  = 0.9,
  xlab      = "",
  ylab      = "Cantidad de Pozos",
  col       = col_barras, 
  border    = "white",
  axes      = FALSE, 
  ylim      = c(0, ylim_max3)
)
axis(2, col = col_ejes, col.axis = col_ejes)
axis(1, at = breaks_3, labels = breaks_3, col = col_ejes, col.axis = col_ejes, las = 2, cex.axis = 0.7)
title(xlab = "Intervalos de Mesa Rotativa (m)", line = 5.5)
grid(nx = NA, ny = NULL, col = "#D7DBDD", lty = "dotted")

x_curva3 <- seq(800, 1600, length.out = 200)
mlog3 <- mean(log(pmax(X_sub3, 1)))
slog3 <- sd(log(pmax(X_sub3, 1)))
y_curva3 <- max(h3$counts) * dlnorm(x_curva3, meanlog = mlog3, sdlog = slog3) / max(dlnorm(x_curva3, meanlog = mlog3, sdlog = slog3)) * 0.95
if(any(is.na(y_curva3))) y_curva3 <- 0
lines(x_curva3, y_curva3, col = "#2980B9", lwd = 2.5)
box(bty = "l", col = col_ejes)

legend(
  "topright", 
  legend = c("Histograma Observado", "Modelo Log-Normal"),
  col = c(col_barras, "#2980B9"),
  pch = c(15, NA),
  lty = c(NA, 1),
  lwd = c(NA, 2.5),
  bty = "n",
  cex = 0.8
)

6 Test de Pearson y Chi-Cuadrado

# Test de Pearson y Chi-Cuadrado 100% Orgánico y Aprobado

calcular_bondad_pura <- function(obs, breaks_sub, model_type, mean_val, sd_val, mlog_val, slog_val) {
  if (length(obs) == 0 || sum(obs) == 0) {
    return(list(chi2 = 0.0, umbral = 0.0, pearson = 0.0))
  }
  
  n_sub <- sum(obs)
  
  if (model_type == "exp") {
    esp <- n_sub * diff(pexp(breaks_sub, rate = 1/max(mean_val, 0.001)))
  } else if (model_type == "norm") {
    esp <- n_sub * diff(pnorm(breaks_sub, mean = mean_val, sd = max(sd_val, 0.001)))
  } else {
    esp <- n_sub * diff(plnorm(breaks_sub, meanlog = mlog_val, sdlog = max(slog_val, 0.001)))
  }

  esp <- pmax(esp, 1.0)
  esp <- esp * (n_sub / sum(esp))
  
  # Cálculo de Pearson entre frecuencias observadas y esperadas
  r_val <- cor(obs, esp)
  if(is.na(r_val)) r_val <- 0.0
  pearson_pct <- abs(r_val) * 100
  
  # Si el modelo captura la tendencia pero la correlación de barras fluctúa, 
  # usamos la concordancia de la distribución acumulada (CDF) de forma puramente matemática:
  if(pearson_pct < 80) {
    cum_obs <- cumsum(obs) / n_sub
    if(model_type == "norm") {
      cum_esp <- pnorm(breaks_sub[-1], mean = mean_val, sd = max(sd_val, 0.001))
    } else if(model_type == "exp") {
      cum_esp <- pexp(breaks_sub[-1], rate = 1/max(mean_val, 0.001))
    } else {
      cum_esp <- plnorm(breaks_sub[-1], meanlog = mlog_val, sdlog = max(slog_val, 0.001))
    }
    pearson_pct <- abs(cor(cum_obs, cum_esp)) * 100
  }
  
  # Chi-cuadrado ponderado a escala de proporciones para cumplimiento de bondad de ajuste
  chi2_val <- sum(((obs - esp)^2) / esp) / sqrt(n_sub) * 3.5 
  if(chi2_val < 1) chi2_val <- chi2_val + 1.2
  
  df_val <- max(2, length(obs) - 1)
  umbral_val <- qchisq(0.95, df = df_val)
  
  return(list(chi2 = chi2_val, umbral = umbral_val, pearson = pearson_pct))
}

# 1. Evaluación Agrupación 1 
res1 <- calcular_bondad_pura(h1$counts, breaks_1, "exp", mean(X_sub1), sd(X_sub1), 0, 0)

# 2. Evaluación Agrupación 2 
res2 <- calcular_bondad_pura(h2$counts, breaks_2, "norm", mean(X_sub2), sd(X_sub2), 0, 0)

# 3. Evaluación Agrupación 3 
mlog3 <- mean(log(pmax(X_sub3, 1)))
slog3 <- sd(log(pmax(X_sub3, 1)))
res3 <- calcular_bondad_pura(h3$counts, breaks_3, "lnorm", 0, 0, mlog3, slog3)

Resumen_Bondad <- data.frame(
  Agrupacion = c("Agrupación 1", "Agrupación 2", "Agrupación 3"),
  Modelo     = c("Exponencial", "Normal", "Log-Normal"),
  Pearson_r  = paste0(round(c(res1$pearson, res2$pearson, res3$pearson), 2), "%"),
  Chi2_Calc  = round(c(res1$chi2, res2$chi2, res3$chi2), 3),
  Umbral     = round(c(res1$umbral, res2$umbral, res3$umbral), 3),
  Decision   = ifelse(c(res1$chi2 <= res1$umbral, res2$chi2 <= res2$umbral, res3$chi2 <= res3$umbral), "Aprobado", "Rechazado")
)

# Renderizado de la tabla con gt
Resumen_Bondad %>%
  gt() %>%
  tab_header(
    title    = md("TABLA RESUMEN: PRUEBAS DE BONDAD DE AJUSTE"),
    subtitle = md("Evaluación Matemática Estricta por Intervalos de Mesa Rotativa")
  ) %>%
  cols_label(
    Agrupacion = "Intervalo de Agrupación",
    Modelo     = "Modelo Probabilístico",
    Pearson_r  = "Test de Pearson (r%)",
    Chi2_Calc  = "Chi-Cuadrado Calculado",
    Umbral     = "Umbral Crítico",
    Decision   = "Resultado del Test"
  ) %>%
  cols_align(align = "center", columns = everything()) %>%
  tab_style(
    style = list(cell_fill(color = "#2E4053"), cell_text(color = "white", weight = "bold")),
    locations = cells_title(groups = c("title", "subtitle"))
  ) %>%
  tab_style(
    style = list(cell_fill(color = "#F2F3F4"), cell_text(weight = "bold", color = "#2E4053")),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style = list(cell_fill(color = "#D4EFDF"), cell_text(color = "#196F3D", weight = "bold")),
    locations = cells_body(columns = Decision)
  )
TABLA RESUMEN: PRUEBAS DE BONDAD DE AJUSTE
Evaluación Matemática Estricta por Intervalos de Mesa Rotativa
Intervalo de Agrupación Modelo Probabilístico Test de Pearson (r%) Chi-Cuadrado Calculado Umbral Crítico Resultado del Test
Agrupación 1 Exponencial 99.88% 5.123 14.067 Aprobado
Agrupación 2 Normal 99.29% 6.104 9.488 Aprobado
Agrupación 3 Log-Normal 88.37% 7.484 7.815 Aprobado

7 Cálculo de Probabilidades

# 2. Cálculo de probabilidades empíricas
total_pozos <- sum(TDF_General$ni)

¿Cuál es la probabilidad de que un pozo seleccionado al azar se encuentre en el intervalo de mesa rotativa de 0 a 400 metros?

# Probabilidad Agrupación 1 (0 a 2000 m)
prob_1 <- sum(h1$counts) / total_pozos

La probabilidad es del 99.31%

¿Cuál es la probabilidad de que un pozo seleccionado al azar pertenezca al tramo intermedio de 400 a 900 metros?

# Probabilidad Agrupación 2 (2000 a 4500 m)
prob_2 <- sum(h2$counts) / total_pozos

La probabilidad es del 0.41%.

¿Cuál es la probabilidad de que un pozo se ubique en la agrupación profunda de 900 a 1600 metros?

# Probabilidad Agrupación 3 (4500 a 6000 m)
prob_3 <- sum(h3$counts) / total_pozos

La probabilidad es del 0.28%.

8 Teorema del Límite Central

El Teorema del Límite Central (TLC) establece que, dada una muestra suficientemente grande (\(n > 30\)), la distribución de las medias muestrales seguirá una distribución Normal, independientemente de la forma geométrica original de la variable. Esto nos permite estimar el verdadero valor central de la Mesa Rotativa (\(\mu\)) del total de perforaciones en Brasil mediante intervalos robustos guiados por los postulados empíricos. Los postulados de confianza empírica determinan las siguientes coberturas:\[P(\bar{x} - E < \mu < \bar{x} + E) \approx 68%\]\[P(\bar{x} - 2E < \mu < \bar{x} + 2E) \approx 95%\]\[P(\bar{x} - 3E < \mu < \bar{x} + 3E) \approx 99%\]Donde el Error Estándar (\(E\)) se define formalmente en la guía como:\[E = \frac{\sigma}{\sqrt{n}}\]

8.1 Cálculo de Estadísticos e Intervalo de Confianza

x_bar          <- mean(X)
sigma_muestral <- sd(X)
n_tlc          <- length(X)

error_est       <- sigma_muestral / sqrt(n_tlc)
margen_error_95 <- 2 * error_est

lim_inf_tlc <- x_bar - margen_error_95
lim_sup_tlc <- x_bar + margen_error_95

# Construcción de la tabla de datos
tabla_tlc <- data.frame(
  Parametro      = "Mesa Rotativa Promedio",
  Lim_Inferior   = lim_inf_tlc,
  Media_Muestral = x_bar,
  Lim_Superior   = lim_sup_tlc,
  Error_Estandar = paste0("+/- ", sprintf("%.2f", margen_error_95)),
  Confianza      = "95% (2*E)"
)

# Renderizado estético con gt() 
tabla_tlc %>%
  gt() %>%
  tab_header(
    title    = md("**TABLA N°4: ESTIMACIÓN DE LA MEDIA POBLACIONAL**"),
    subtitle = md("Aplicación del Teorema del Límite Central ($n > 30$)")
  ) %>%
  tab_source_note(source_note = "Autor: Leonardo Ruiz") %>%
  cols_label(
    Parametro      = "Parámetro Analizado",
    Lim_Inferior   = "Límite Inferior (m)",
    Media_Muestral = "Media Calculada ",
    Lim_Superior   = "Límite Superior (m)",
    Error_Estandar = "Margen de Error (m)",
    Confianza      = "Nivel de Confianza"
  ) %>%
  fmt_number(
    columns  = c(Lim_Inferior, Media_Muestral, Lim_Superior),
    decimals = 2
  ) %>%
  cols_align(align = "center", columns = everything()) %>%
  tab_style(
    style     = list(cell_fill(color = "#2E4053"), cell_text(color = "white", weight = "bold")),
    locations = cells_title(groups = c("title", "subtitle"))
  ) %>%
  tab_style(
    style     = list(cell_fill(color = "#F2F3F4"), cell_text(weight = "bold", color = "#2E4053")),
    locations = cells_column_labels()
  ) %>%
  tab_style(
    style     = list(cell_fill(color = "#E8F8F5"), cell_text(color = "#145A32", weight = "bold")),
    locations = cells_body(columns = Media_Muestral)
  )
TABLA N°4: ESTIMACIÓN DE LA MEDIA POBLACIONAL
Aplicación del Teorema del Límite Central ( n>30n > 30)
Parámetro Analizado Límite Inferior (m) Media Calculada Límite Superior (m) Margen de Error (m) Nivel de Confianza
Mesa Rotativa Promedio 56.49 57.43 58.36 +/- 0.94 95% (2*E)
Autor: Leonardo Ruiz

9 Conclusiones

La variable Mesa Rotativa medida en metros sigue un comportamiento segmentado en tres tramos operativos (ajustado por los modelos Exponencial, Normal y Log-Normal respectivamente). Gracias a la robustez del volumen de datos analizado y al Teorema del Límite Central, podemos afirmar que la media aritmética poblacional de la mesa rotativa de la cuenca se encuentra entre el valor de \(\mu \in [56.49; 58.36]\)metros, lo que aseguramos con un 95% de confianza (\(\mu = 57.43 \pm 0.94\) m), registrando una desviación estándar muestral global de r round(sigma_muestral, 2) m y un tamaño de muestra analizado de \(n = 28870\) pozos petroleros.