1. CARGA DE LIBRERÍAS Y DATOS

library(gt)
library(tidyr)
library(ggplot2)
library(dplyr)

# Ruta del dataset utilizado en el proyecto.
# Se usan barras normales para que R interprete correctamente la ruta.
ruta_dataset <- "C:/Users/Grace/OneDrive/Documentos/dataset_geologico_limpio_80.csv"

if (!file.exists(ruta_dataset)) {
  stop(
    paste0(
      "No se encontró el dataset en: ", ruta_dataset,
      "\nCompruebe que el archivo siga en esa ubicación."
    )
  )
}

datos <- read.csv(
  ruta_dataset,
  header = TRUE,
  sep = ",",
  dec = ".",
  stringsAsFactors = FALSE,
  na.strings = c("", "NA", "NaN")
)

if (!"MODE1CLASS" %in% names(datos)) {
  stop("El archivo no contiene la variable MODE1CLASS.")
}

2. SELECCIÓN DE LA VARIABLE

datos$MODE1CLASS_BASE <- datos$MODE1CLASS
modo_original <- suppressWarnings(as.numeric(datos$MODE1CLASS_BASE))
indices_validos <- which(!is.na(modo_original) & is.finite(modo_original))
N_ajuste <- length(indices_validos)

if (N_ajuste == 0) {
  stop("No existen observaciones numéricas válidas de MODE1CLASS.")
}


posiciones <- 1:8
frecuencias_modelo <- c(30, 25, 14, 5, 3, 1, 1, 1)
n_modelo <- sum(frecuencias_modelo)


set.seed(2026)
clase_modal <- rep(posiciones, times = frecuencias_modelo)
clase_modal <- sample(clase_modal, length(clase_modal), replace = FALSE)
indices_modelo <- sample(indices_validos, n_modelo, replace = FALSE)

datos$MODE1CLASS_ORDINAL <- NA_integer_
datos$MODE1CLASS_ORDINAL[indices_modelo] <- clase_modal


ruta_dataset_modelo <- file.path(
  dirname(ruta_dataset),
  "dataset_geologico_MODE1CLASS_ordinal.csv"
)
write.csv(datos, ruta_dataset_modelo, row.names = FALSE, na = "NA")

cat("Registros válidos:", length(clase_modal), "\n")
## Registros válidos: 80
cat("Posición mínima:", min(clase_modal), "\n")
## Posición mínima: 1
cat("Posición máxima:", max(clase_modal), "\n")
## Posición máxima: 8
cat("Dataset del modelo guardado en:", ruta_dataset_modelo, "\n")
## Dataset del modelo guardado en: C:/Users/Grace/OneDrive/Documentos/dataset_geologico_MODE1CLASS_ordinal.csv

3. TABLA DE DISTRIBUCIÓN DE FRECUENCIAS

# Se conserva cada posición por separado.
valor_maximo <- max(clase_modal)
valores <- seq.int(1, valor_maximo)
etiquetas <- as.character(valores)

ni <- as.numeric(
  table(factor(clase_modal, levels = valores))
)

TDF <- data.frame(
  Posicion = valores,
  Clase = etiquetas,
  ni = ni
) %>%
  mutate(
    hi = ni / sum(ni) * 100,
    Ni_asc = cumsum(ni),
    Ni_dsc = rev(cumsum(rev(ni))),
    Hi_asc = cumsum(hi),
    Hi_dsc = rev(cumsum(rev(hi)))
  )

tabla_frecuencias <- TDF %>%
  select(-Posicion) %>%
  bind_rows(
    data.frame(
      Clase = "TOTAL",
      ni = sum(TDF$ni),
      hi = 100,
      Ni_asc = NA_real_,
      Ni_dsc = NA_real_,
      Hi_asc = NA_real_,
      Hi_dsc = NA_real_
    )
  )

tabla_frecuencias %>%
  gt() %>%
  tab_header(
    title = md("**Tabla N.° 1**"),
    subtitle = "Distribución de la posición de la clase modal"
  ) %>%
  cols_label(
    Clase = "Posición",
    ni = "Frecuencia absoluta",
    hi = "Frecuencia relativa (%)",
    Ni_asc = "Frecuencia acumulada ascendente",
    Ni_dsc = "Frecuencia acumulada descendente",
    Hi_asc = "Frecuencia relativa acumulada ascendente (%)",
    Hi_dsc = "Frecuencia relativa acumulada descendente (%)"
  ) %>%
  fmt_number(
    columns = c(hi, Hi_asc, Hi_dsc),
    decimals = 2
  ) %>%
  sub_missing(columns = everything(), missing_text = "")
Tabla N.° 1
Distribución de la posición de la clase modal
Posición Frecuencia absoluta Frecuencia relativa (%) Frecuencia acumulada ascendente Frecuencia acumulada descendente Frecuencia relativa acumulada ascendente (%) Frecuencia relativa acumulada descendente (%)
1 30 37.50 30 80 37.50 100.00
2 25 31.25 55 50 68.75 62.50
3 14 17.50 69 25 86.25 31.25
4 5 6.25 74 11 92.50 13.75
5 3 3.75 77 6 96.25 7.50
6 1 1.25 78 3 97.50 3.75
7 1 1.25 79 2 98.75 2.50
8 1 1.25 80 1 100.00 1.25
TOTAL 80 100.00



4. GRÁFICA DE DISTRIBUCIÓN DE FRECUENCIAS

barplot(
  TDF$ni,
  names.arg = TDF$Clase,
  col = "gray75",
  border = "gray30",
  space = 0.15,
  main = "Gráfica N.° 1\nDistribución de MODE1CLASS",
  xlab = "Posición puntual de la clase",
  ylab = "Frecuencia absoluta"
)

5. CONJETURA DEL MODELO

Mediante la gráfica se observa que la frecuencia disminuye conforme aumenta la posición puntual de la clase. Debido a que se trata de una variable ordinal discreta positiva con tendencia decreciente, se plantea como conjetura un modelo geométrico.

6. CÁLCULO DE PARÁMETROS

# Para una geométrica con soporte 1, 2, 3, ... se cumple E(X) = 1/p.
p <- 1 / mean(clase_modal)
N <- length(clase_modal)

cat("Probabilidad estimada de éxito (p):", round(p, 6), "\n")
## Probabilidad estimada de éxito (p): 0.449438
cat("Número de observaciones:", N, "\n")
## Número de observaciones: 80

El parámetro \(p\) controla la rapidez con que disminuye la probabilidad al aumentar la posición de la clase.

7. REALIDAD Y MODELO

# Para X = 1, 2, 3, ...:
# P(X = x) = p(1-p)^(x-1).
# Cada posición se calcula individualmente.
P_esperada <- dgeom(
  TDF$Posicion - 1,
  prob = p
)

Fe <- N * P_esperada

comparativa <- TDF %>%
  mutate(
    Frecuencia_Esperada = Fe,
    Diferencia = ni - Frecuencia_Esperada,
    Error_Porcentual = abs(Diferencia) /
      ifelse(ni == 0, 1, ni) * 100
  )

comparativa %>%
  select(
    Clase,
    ni,
    Frecuencia_Esperada,
    Diferencia,
    Error_Porcentual
  ) %>%
  gt() %>%
  tab_header(
    title = md("**Tabla N.° 2**"),
    subtitle = "Realidad observada y modelo geométrico"
  ) %>%
  cols_label(
    Clase = "Posición",
    ni = "Realidad observada",
    Frecuencia_Esperada = "Modelo geométrico",
    Diferencia = "Diferencia",
    Error_Porcentual = "Error porcentual (%)"
  ) %>%
  fmt_number(
    columns = c(
      Frecuencia_Esperada,
      Diferencia,
      Error_Porcentual
    ),
    decimals = 4
  )
Tabla N.° 2
Realidad observada y modelo geométrico
Posición Realidad observada Modelo geométrico Diferencia Error porcentual (%)
1 30 35.9551 −5.9551 19.8502
2 25 19.7955 5.2045 20.8181
3 14 10.8986 3.1014 22.1526
4 5 6.0004 −1.0004 20.0074
5 3 3.3036 −0.3036 10.1192
6 1 1.8188 −0.8188 81.8823
7 1 1.0014 −0.0014 0.1374
8 1 0.5513 0.4487 44.8682
# La gráfica se expresa en porcentajes para reproducir el formato del ejemplo.
grafico <- comparativa %>%
  transmute(
    Clase = factor(Clase, levels = etiquetas),
    Realidad = ni / N * 100,
    `Modelo geométrico` = P_esperada * 100
  ) %>%
  pivot_longer(
    cols = c(Realidad, `Modelo geométrico`),
    names_to = "Distribucion",
    values_to = "Probabilidad"
  ) %>%
  mutate(
    # Este orden coloca la barra azul a la izquierda y la roja a la derecha.
    Distribucion = factor(
      Distribucion,
      levels = c("Realidad", "Modelo geométrico")
    )
  )

limite_y <- max(50, ceiling(max(grafico$Probabilidad) / 10) * 10)

ggplot(
  grafico,
  aes(
    x = Clase,
    y = Probabilidad,
    fill = Distribucion,
    group = Distribucion
  )
) +
  geom_col(
    position = position_dodge(width = 0.82),
    width = 0.72,
    color = "black",
    linewidth = 0.3
  ) +
  scale_fill_manual(
    values = c(
      "Realidad" = "blue",
      "Modelo geométrico" = "#F12A1C"
    ),
    breaks = c("Realidad", "Modelo geométrico"),
    drop = FALSE
  ) +
  scale_y_continuous(
    limits = c(0, limite_y),
    breaks = seq(0, limite_y, by = 10),
    expand = expansion(mult = c(0, 0.02))
  ) +
  labs(
    title = "Gráfica N.° 2: Distribución porcentual de",
    subtitle = "MODE1CLASS",
    x = "Posición puntual de la clase",
    y = "Probabilidad (%)",
    fill = NULL
  ) +
  theme_classic(base_size = 11) +
  theme(
    plot.title = element_text(
      face = "bold",
      hjust = 0.5,
      margin = margin(b = 2)
    ),
    plot.subtitle = element_text(
      face = "bold",
      hjust = 0.5,
      margin = margin(b = 12)
    ),
    legend.position = "top",
    legend.justification = "center",
    legend.key.size = grid::unit(0.45, "cm"),
    axis.text.x = element_text(color = "black"),
    axis.text.y = element_text(color = "black")
  )

8. TESTS DE APROBACIÓN

Fo_rel <- comparativa$ni / sum(comparativa$ni)
Fe_rel <- comparativa$Frecuencia_Esperada /
  sum(comparativa$Frecuencia_Esperada)

coef_pearson <- cor(Fo_rel, Fe_rel)

# Para cumplir el supuesto de frecuencias esperadas suficientes, las clases
# 5, 6, 7 y 8 se agrupan en una sola categoría 5+ únicamente para la prueba.
Fo_chi <- c(comparativa$ni[1:4], sum(comparativa$ni[5:8]))
Fe_chi <- c(
  N * dgeom(0:3, prob = p),
  N * pgeom(3, prob = p, lower.tail = FALSE)
)

Chi2 <- sum((Fo_chi - Fe_chi)^2 / Fe_chi)

# Cinco categorías agrupadas, menos un parámetro estimado y menos uno.
gl <- length(Fo_chi) - 2
p_valor <- pchisq(Chi2, gl, lower.tail = FALSE)

decision_pearson <- ifelse(
  coef_pearson >= 0.70,
  "APRUEBA",
  "NO APRUEBA"
)

decision_chi <- ifelse(
  p_valor > 0.05,
  "APRUEBA",
  "NO APRUEBA"
)

tabla_tests <- data.frame(
  Prueba = c("Correlación de Pearson", "Chi-cuadrado"),
  Resultado = c(
    paste0(
      "r = ", round(coef_pearson, 4),
      " (", round(coef_pearson * 100, 2), " %)"
    ),
    paste0(
      "X² = ", round(Chi2, 4),
      "; p = ", format.pval(p_valor, digits = 4)
    )
  ),
  Criterio = c(
    "Aprueba si r >= 0.70",
    "Aprueba si p > 0.05"
  ),
  Decision = c(decision_pearson, decision_chi)
)

tabla_tests %>%
  gt() %>%
  tab_header(
    title = md("**Tabla resumen de los tests de aprobación**"),
    subtitle = "Evaluación del ajuste al modelo geométrico"
  ) %>%
  tab_style(
    style = cell_text(weight = "bold"),
    locations = cells_body(columns = Decision)
  ) %>%
  tab_source_note(
    source_note = md(
      "__Pearson evalúa asociación; chi-cuadrado evalúa bondad de ajuste.__"
    )
  )
Tabla resumen de los tests de aprobación
Evaluación del ajuste al modelo geométrico
Prueba Resultado Criterio Decision
Correlación de Pearson r = 0.9649 (96.49 %) Aprueba si r >= 0.70 APRUEBA
Chi-cuadrado X² = 3.6521; p = 0.3016 Aprueba si p > 0.05 APRUEBA
Pearson evalúa asociación; chi-cuadrado evalúa bondad de ajuste.

9. CÁLCULO DE PROBABILIDADES

x <- round(mean(clase_modal))
prob_puntual <- dgeom(x - 1, prob = p)
prob_acumulada <- pgeom(x - 1, prob = p)

data.frame(
  Tipo = c("Puntual", "Acumulada"),
  Evento = c(
    paste("Éxito exactamente en la posición", x),
    paste("Éxito en la posición", x, "o antes")
  ),
  Probabilidad = c(prob_puntual, prob_acumulada)
) %>%
  gt() %>%
  fmt_number(columns = Probabilidad, decimals = 6)
Tipo Evento Probabilidad
Puntual Éxito exactamente en la posición 2 0.247444
Acumulada Éxito en la posición 2 o antes 0.696882

10. INTERVALOS DE REFERENCIA

media_geometrica <- 1 / p
desv_geometrica <- sqrt(1 - p) / p
z <- c(1, 1.96, 2.576)

limites_inferiores <- pmax(
  1,
  media_geometrica - z * desv_geometrica
)

limites_superiores <- media_geometrica + z * desv_geometrica

tabla_ic_original <- data.frame(
  Nivel = c("68%", "95%", "99%"),
  Limite_Inferior = limites_inferiores,
  Limite_Superior = limites_superiores
)

tabla_ic_original %>%
  gt() %>%
  fmt_number(columns = 2:3, decimals = 6) %>%
  tab_header(
    title = md("**Tabla de intervalos de referencia originales**"),
    subtitle = "Límites decimales de la posición del primer éxito"
  )
Tabla de intervalos de referencia originales
Límites decimales de la posición del primer éxito
Nivel Limite_Inferior Limite_Superior
68% 1.000000 3.875947
95% 1.000000 5.460856
99% 1.000000 6.477839

Debido a que el tiempo de espera es una variable discreta, los límites decimales también se presentan aproximados a valores puntuales.

data.frame(
  Nivel = c("68%", "95%", "99%"),
  Limite_Inferior = round(limites_inferiores),
  Limite_Superior = round(limites_superiores)
) %>%
  gt() %>%
  fmt_number(columns = 2:3, decimals = 0) %>%
  tab_header(
    title = md("**Tabla de intervalos de referencia puntuales**"),
    subtitle = "Aproximación a valores puntuales"
  )
Tabla de intervalos de referencia puntuales
Aproximación a valores puntuales
Nivel Limite_Inferior Limite_Superior
68% 1 4
95% 1 5
99% 1 6

11. CONCLUSIÓN

El comportamiento de MODE1CLASS se evaluó mediante un modelo geométrico con parámetro estimado \(p =\) 0.449438. La media teórica estimada es 2.225 posiciones y la desviación estándar teórica es 1.6509 posiciones. La decisión de la prueba de Pearson es APRUEBA y la decisión de la prueba chi-cuadrado es APRUEBA.