library(readxl)
library(dplyr)
library(tidyr)
library(gt)
library(ggplot2)
library(scales)
library(forcats)
library(MASS) # Fundamental para el ajuste de distribuciones (fitdistr)
datos <- read_excel("dataset_mundial_petro.xlsx")
cat("Número de registros:", nrow(datos), "\n")
## Número de registros: 49212
cat("Número de variables:", ncol(datos), "\n")
## Número de variables: 32
La variable Longitude indica la coordenada geográfica de longitud de cada yacimiento. Es una variable cuantitativa continua, cuyos valores van desde coordenadas negativas (Hemisferio Occidental) hasta positivas (Hemisferio Oriental). Por su naturaleza bimodal ligada al hemisferio, se le aplica un tratamiento analítico segmentado.
n_total <- nrow(datos)
Variable <- na.omit(as.numeric(datos$Longitude))
n <- length(Variable)
cat("Número de registros (n):", n, "\n")
## Número de registros (n): 7537
cat("Valor mínimo:", round(min(Variable), 3), "\n")
## Valor mínimo: -152.129
cat("Valor máximo:", round(max(Variable), 3), "\n")
## Valor máximo: 174.361
n_occidental <- sum(Variable <= 0)
n_oriental <- sum(Variable > 0)
cat("Registros en Hemisferio Occidental (<= 0°):", n_occidental,
"(", round(n_occidental / n * 100, 2), "%)\n")
## Registros en Hemisferio Occidental (<= 0°): 5290 ( 70.19 %)
cat("Registros en Hemisferio Oriental (> 0°):", n_oriental,
"(", round(n_oriental / n * 100, 2), "%)\n")
## Registros en Hemisferio Oriental (> 0°): 2247 ( 29.81 %)
Se aplica la Regla de Sturges para determinar el número óptimo de intervalos de clase, ajustando los límites a múltiplos de 10 para facilitar la lectura.
BASE <- 10
min_int <- floor(min(Variable) / BASE) * BASE
max_int <- ceiling(max(Variable) / BASE) * BASE
k_sug <- floor(1 + 3.322 * log10(n))
Rango_int <- max_int - min_int
Amplitud_int <- ceiling((Rango_int / k_sug) / 10) * 10
if (Amplitud_int == 0) Amplitud_int <- 10
cortes_int <- seq(from = min_int, by = Amplitud_int, length.out = k_sug + 1)
if (max(cortes_int) < max(Variable)) cortes_int <- c(cortes_int, max(cortes_int) + Amplitud_int)
while (length(cortes_int) > 2 && cortes_int[length(cortes_int) - 1] >= max(Variable)) {
cortes_int <- cortes_int[-length(cortes_int)]
}
k <- length(cortes_int) - 1
inter_int <- cut(Variable, breaks = cortes_int, include.lowest = TRUE, right = FALSE)
ni_int <- as.vector(table(inter_int))
conteo <- data.frame(
Li = cortes_int[1:k],
Ls = cortes_int[2:(k + 1)],
MC = (cortes_int[1:k] + cortes_int[2:(k + 1)]) / 2,
ni = ni_int
) %>%
mutate(
hi = round(ni / n, 4),
hi_pct = round(ni / n * 100, 2)
)
cat("Total de intervalos de clase:", k, "\n")
## Total de intervalos de clase: 12
cat("Amplitud de clase:", Amplitud_int, "\n")
## Amplitud de clase: 30
cat("Intervalo más frecuente: [", conteo$Li[which.max(conteo$ni)], ",",
conteo$Ls[which.max(conteo$ni)], ") con", max(conteo$ni), "registros\n")
## Intervalo más frecuente: [ -130 , -100 ) con 2689 registros
fila_total <- tibble(
Li = NA, Ls = NA, MC = NA,
ni = sum(conteo$ni),
hi = sum(conteo$hi),
hi_pct = sum(conteo$hi_pct)
)
tdf_final <- bind_rows(conteo, fila_total)
tdf_final %>%
gt() %>%
tab_header(
title = md("**Tabla N° 1**"),
subtitle = md("Distribución de yacimientos según Longitud Geográfica")
) %>%
cols_label(
Li = "Lím. Inf (°)",
Ls = "Lím. Sup (°)",
MC = "Marca de Clase",
ni = "Frecuencia (ni)",
hi = "Proporción (hi)",
hi_pct = "Porcentaje (hi%)"
) %>%
fmt_number(columns = MC, decimals = 1) %>%
fmt_number(columns = hi, decimals = 4) %>%
fmt_number(columns = hi_pct, decimals = 2) %>%
sub_missing(columns = c(Li, Ls, MC), missing_text = "TOTAL") %>%
tab_source_note(source_note = "Autor: Grupo 5") %>%
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 N° 1 | |||||
| Distribución de yacimientos según Longitud Geográfica | |||||
| Lím. Inf (°) | Lím. Sup (°) | Marca de Clase | Frecuencia (ni) | Proporción (hi) | Porcentaje (hi%) |
|---|---|---|---|---|---|
| -160 | -130 | −145.0 | 37 | 0.0049 | 0.49 |
| -130 | -100 | −115.0 | 2689 | 0.3568 | 35.68 |
| -100 | -70 | −85.0 | 2018 | 0.2677 | 26.77 |
| -70 | -40 | −55.0 | 403 | 0.0535 | 5.35 |
| -40 | -10 | −25.0 | 51 | 0.0068 | 0.68 |
| -10 | 20 | 5.0 | 1130 | 0.1499 | 14.99 |
| 20 | 50 | 35.0 | 431 | 0.0572 | 5.72 |
| 50 | 80 | 65.0 | 384 | 0.0509 | 5.09 |
| 80 | 110 | 95.0 | 183 | 0.0243 | 2.43 |
| 110 | 140 | 125.0 | 178 | 0.0236 | 2.36 |
| 140 | 170 | 155.0 | 26 | 0.0034 | 0.34 |
| 170 | 200 | 185.0 | 7 | 0.0009 | 0.09 |
| TOTAL | TOTAL | TOTAL | 7537 | 0.9999 | 99.99 |
| Autor: Grupo 5 | |||||
colores <- colorRampPalette(c("#2E86C1", "#AED6F1"))(k)
ggplot(conteo, aes(x = factor(MC), y = ni, fill = factor(MC))) +
geom_col(width = 0.85, color = "white") +
geom_text(aes(label = ni), vjust = -0.4, size = 3, fontface = "bold") +
scale_fill_manual(values = colores) +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
labs(
title = "Gráfica N°1: Frecuencia Absoluta por Intervalo de Longitud",
x = "Marca de Clase — Longitud (°)",
y = "Frecuencia (ni)",
caption = paste0("n = ", format(n, big.mark = ","), " | Fuente: GOGET")
) +
theme_minimal() +
theme(legend.position = "none",
plot.title = element_text(face = "bold"),
axis.title = element_text(face = "bold"),
axis.text.x = element_text(angle = 45, hjust = 1))
ggplot(conteo, aes(x = factor(MC), y = hi_pct, fill = factor(MC))) +
geom_col(width = 0.85, color = "white") +
geom_text(aes(label = paste0(hi_pct, "%")), vjust = -0.4, size = 3, fontface = "bold") +
scale_fill_manual(values = colores) +
scale_y_continuous(expand = expansion(mult = c(0, 0.15))) +
labs(
title = "Gráfica N°2: Frecuencia Relativa (Pi) por Intervalo de Longitud",
x = "Marca de Clase — Longitud (°)",
y = "Frecuencia Relativa (%)",
caption = paste0("n = ", format(n, big.mark = ","), " | Fuente: GOGET")
) +
theme_minimal() +
theme(legend.position = "none",
plot.title = element_text(face = "bold"),
axis.title = element_text(face = "bold"),
axis.text.x = element_text(angle = 45, hjust = 1))
La distribución de la Longitud no responde a un patrón único: los yacimientos del Hemisferio Occidental se concentran de forma simétrica en torno a un valor central (compatible con un modelo Normal), mientras que los del Hemisferio Oriental muestran una fuerte asimetría positiva por la concentración de cuencas desde Medio Oriente hasta Asia central (compatible con un modelo Log-Normal). Por ello se conjetura un modelo híbrido segmentado por hemisferio.
z1 <- Variable[Variable <= 0]
mu1 <- mean(z1, na.rm = TRUE)
sd1 <- sd(z1, na.rm = TRUE)
h1 <- hist(z1, breaks = 15, plot = FALSE)
df_z1 <- data.frame(x = h1$mids, y = (h1$counts / length(z1)) * 100)
cat("Media (mu):", round(mu1, 3), " | Desv. Estándar (sd):", round(sd1, 3), "\n")
## Media (mu): -94.92 | Desv. Estándar (sd): 21.253
ggplot(df_z1, aes(x = x, y = y)) +
geom_bar(stat = "identity", fill = "#AED6F1", color = "white", width = diff(h1$breaks)[1]) +
stat_function(fun = function(x) dnorm(x, mean = mu1, sd = sd1) * 100 * diff(h1$breaks)[1],
color = "#2E4053", linewidth = 1.5) +
labs(title = "Gráfica N°3: Ajuste Normal — Hemisferio Occidental (Longitudes ≤ 0°)",
x = "Longitud (°)", y = "Densidad Porcentual (%)",
caption = "Fuente: GOGET") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold"))
z2 <- Variable[Variable > 0]
fit2 <- fitdistr(z2, "lognormal")
mu_log2 <- fit2$estimate[1]
sd_log2 <- fit2$estimate[2]
h2 <- hist(z2, breaks = 15, plot = FALSE)
df_z2 <- data.frame(x = h2$mids, y = (h2$counts / length(z2)) * 100)
cat("Parámetro meanlog:", round(mu_log2, 4), " | Parámetro sdlog:", round(sd_log2, 4), "\n")
## Parámetro meanlog: 2.9174 | Parámetro sdlog: 1.4847
ggplot(df_z2, aes(x = x, y = y)) +
geom_bar(stat = "identity", fill = "#2E86C1", color = "white", width = diff(h2$breaks)[1]) +
stat_function(fun = function(x) dlnorm(x, meanlog = mu_log2, sdlog = sd_log2) * 100 * diff(h2$breaks)[1],
color = "#C0392B", linewidth = 1.5) +
labs(title = "Gráfica N°4: Ajuste Log-Normal — Hemisferio Oriental (Longitudes > 0°)",
x = "Longitud (°)", y = "Densidad Porcentual (%)",
caption = "Fuente: GOGET") +
theme_minimal(base_size = 12) +
theme(plot.title = element_text(face = "bold"))
# Occidental: se trabaja con proporciones (Fo, Fe), no conteos absolutos
Fo1 <- h1$counts / sum(h1$counts)
Fe1 <- dnorm(h1$mids, mu1, sd1)
Fe1 <- Fe1 / sum(Fe1)
r_pearson1 <- cor(Fo1, Fe1) * 100
cat("Correlación de Pearson Occidental (%):", round(r_pearson1, 4), "\n")
## Correlación de Pearson Occidental (%): 78.6819
plot(Fo1, Fe1,
main = "Gráfica N°5: Correlación Modelo Observado y Esperado — Occidental",
xlab = "Frecuencia Observada (hi)", ylab = "Frecuencia Esperada (hi modelo)",
pch = 19, col = "#2E4053")
abline(lm(Fe1 ~ 0 + Fo1), col = "red", lwd = 2)
legend("topleft", legend = paste0("r = ", round(r_pearson1, 2), "%"), bty = "n")
# Oriental: se trabaja con proporciones (Fo, Fe), no conteos absolutos
Fo2 <- h2$counts / sum(h2$counts)
Fe2 <- dlnorm(h2$mids, mu_log2, sd_log2)
Fe2 <- Fe2 / sum(Fe2)
r_pearson2 <- cor(Fo2, Fe2) * 100
cat("Correlación de Pearson Oriental (%):", round(r_pearson2, 4), "\n")
## Correlación de Pearson Oriental (%): 92.8629
plot(Fo2, Fe2,
main = "Gráfica N°6: Correlación Modelo Observado y Esperado — Oriental",
xlab = "Frecuencia Observada (hi)", ylab = "Frecuencia Esperada (hi modelo)",
pch = 19, col = "#2E86C1")
abline(lm(Fe2 ~ 0 + Fo2), col = "red", lwd = 2)
legend("topleft", legend = paste0("r = ", round(r_pearson2, 2), "%"), bty = "n")
# Occidental
chi2_calc1 <- sum(((Fo1 - Fe1)^2) / Fe1)
gl1 <- length(Fo1) - 2
chi2_crit1 <- qchisq(0.95, gl1)
cat("Chi-Cuadrado Occidental:", round(chi2_calc1, 4), "\n")
## Chi-Cuadrado Occidental: 12.8889
cat("Valor Crítico Occidental:", round(chi2_crit1, 4), "\n")
## Valor Crítico Occidental: 23.6848
cat("¿El modelo Normal es aceptado?:", chi2_calc1 < chi2_crit1, "\n")
## ¿El modelo Normal es aceptado?: TRUE
# Oriental
chi2_calc2 <- sum(((Fo2 - Fe2)^2) / Fe2)
gl2 <- length(Fo2) - 2
chi2_crit2 <- qchisq(0.95, gl2)
cat("Chi-Cuadrado Oriental:", round(chi2_calc2, 4), "\n")
## Chi-Cuadrado Oriental: 0.5928
cat("Valor Crítico Oriental:", round(chi2_crit2, 4), "\n")
## Valor Crítico Oriental: 26.2962
cat("¿El modelo Log-Normal es aceptado?:", chi2_calc2 < chi2_crit2, "\n")
## ¿El modelo Log-Normal es aceptado?: TRUE
resumen_ajuste <- data.frame(
Segmento = c("Hemisferio Occidental", "Hemisferio Oriental"),
Modelo = c("Normal", "Log-Normal"),
`Test Pearson (%)` = round(c(r_pearson1, r_pearson2), 2),
`Chi Cuadrado` = round(c(chi2_calc1, chi2_calc2), 4),
`Umbral de Aceptación` = round(c(chi2_crit1, chi2_crit2), 4),
check.names = FALSE
) %>%
mutate(Resultado = ifelse(`Chi Cuadrado` < `Umbral de Aceptación`,
"Modelo Aceptado", "Modelo Rechazado"))
resumen_ajuste %>%
gt() %>%
tab_header(
title = md("**Tabla N°2: Resumen del Test de Bondad al Modelo Híbrido**")
) %>%
tab_source_note(source_note = "Autor: Grupo 5") %>%
cols_align(align = "center", columns = everything()) %>%
tab_options(
table.border.top.color = "black",
table.border.bottom.color = "black",
column_labels.border.top.color = "black",
column_labels.border.bottom.color = "black",
column_labels.border.bottom.width = px(2),
table_body.border.bottom.color = "black"
)
| Tabla N°2: Resumen del Test de Bondad al Modelo Híbrido | |||||
| Segmento | Modelo | Test Pearson (%) | Chi Cuadrado | Umbral de Aceptación | Resultado |
|---|---|---|---|---|---|
| Hemisferio Occidental | Normal | 78.68 | 12.8889 | 23.6848 | Modelo Aceptado |
| Hemisferio Oriental | Log-Normal | 92.86 | 0.5928 | 26.2962 | Modelo Aceptado |
| Autor: Grupo 5 | |||||
A partir del modelo Log-Normal validado para el Hemisferio Oriental, se calcula la probabilidad teórica de que un yacimiento se ubique en la franja geoestratégica de Medio Oriente (entre los meridianos 40° y 60° Este).
prob_medio_oriente <- (plnorm(60, mu_log2, sd_log2) - plnorm(40, mu_log2, sd_log2)) * 100
cat("Probabilidad de ubicarse entre 40° y 60° de longitud (Medio Oriente):",
round(prob_medio_oriente, 2), "%\n")
## Probabilidad de ubicarse entre 40° y 60° de longitud (Medio Oriente): 8.77 %
pozos_occidental <- n_occidental
cat("Pozos ubicados en el Hemisferio Occidental:", pozos_occidental,
"(", round(pozos_occidental / n * 100, 2), "%)\n")
## Pozos ubicados en el Hemisferio Occidental: 5290 ( 70.19 %)
Por el Teorema del Límite Central (TLC), se calcula el intervalo de confianza al 95% para la media poblacional de la Longitud a nivel mundial (Z = 1.96).
x_bar <- mean(Variable, na.rm = TRUE)
sigma <- sd(Variable, na.rm = TRUE)
z <- qnorm(0.975)
margen <- z * (sigma / sqrt(n))
ic_inf <- x_bar - margen
ic_sup <- x_bar + margen
cat("Media muestral (centro de masa longitudinal):", round(x_bar, 3), "\n")
## Media muestral (centro de masa longitudinal): -54.653
cat("Intervalo de confianza al 95%: (", round(ic_inf, 3), "° ,", round(ic_sup, 3), "° )\n")
## Intervalo de confianza al 95%: ( -56.186 ° , -53.12 ° )
La variable Longitud exhibe un comportamiento bimodal ligado al hemisferio: el Hemisferio Occidental (70.19% de los registros) se ajusta a un modelo Normal (μ = -94.92°, σ = 21.25°) con una correlación de Pearson del 78.68% y un Chi-cuadrado de 12.8889 frente a un valor crítico de 23.6848 (modelo aceptado). El Hemisferio Oriental (29.81% de los registros) se ajusta a un modelo Log-Normal con una correlación de Pearson del 92.86% y un Chi-cuadrado de 0.5928 frente a un valor crítico de 26.2962 (modelo aceptado). Bajo el modelo Log-Normal, la probabilidad de que un yacimiento se ubique en la franja de Medio Oriente (40°–60° Este) es del 8.77%. Finalmente, el intervalo de confianza al 95% para la media poblacional de la Longitud se ubica entre -56.186° y -53.12°, lo que valida la conjetura de una hiper-concentración geológica segmentada por hemisferio.