1 Resumen

En redes de distribución de agua potable digitalizadas en SIG (QGIS/PostGIS), la apariencia cartográfica no garantiza conectividad topológica adecuada para análisis avanzados. Este estudio piloto se enfocó en transformar una red digitalizada hacia una representación como grafo y evaluar cuantitativamente su estructura por DMA. Se procesaron cinco DMAs (EPSG:32719), convirtiendo nudos y válvulas en nodos y tuberías en aristas, asignando conectividad mediante los extremos geométricos de cada tubería hacia su nodo más cercano con tolerancia de 0.05 m. Con el grafo construido se calcularon métricas topológicas (nodos, aristas, densidad, componentes conexas, porcentaje de nodos con grado 1 y longitud total). Adicionalmente, se aplicó un procedimiento de validación/corrección en el dominio de grafos (A–B) y se utilizó Wilcoxon pareado (α=0.05) como verificación piloto. Se concluye que el enfoque QGIS/PostGIS→Grafo estandariza una validación cuantitativa por DMA y establece una base confiable para la etapa principal del estudio.

Palabras clave: grafos; QGIS; PostGIS; DMA; conectividad; calidad topológica; Wilcoxon.

2 Introducción

Los SIG permiten gestionar redes como capas georreferenciadas, pero pequeñas incongruencias geométricas pueden afectar la conectividad analítica sin ser evidentes en el mapa. La teoría de grafos formaliza la conectividad y permite cuantificar propiedades estructurales comparables por DMA. El objetivo de este artículo piloto es validar cuantitativamente la red mediante su conversión a grafo y la evaluación estadística de métricas topológicas, como etapa previa al desarrollo del tema principal.

3 Objetivo

Objetivo general: Validar cuantitativamente la calidad topológica de redes por DMA mediante su conversión desde QGIS/PostGIS a grafos y el cálculo de métricas, incluyendo estadística descriptiva y validación piloto (Wilcoxon).

4 Metodología

Se trabajó con cinco DMAs exportados desde QGIS/PostGIS a GeoPackage. Se construyó un grafo no dirigido por DMA donde los nodos corresponden a nudos y válvulas y las aristas a tuberías. Se consideraron dos estados:

Se calcularon métricas: número de nodos, aristas, densidad, componentes conexas, porcentaje de nodos con grado 1 y longitud total. Se reportó estadística descriptiva y Wilcoxon pareado (α=0.05).

5 Resultados

5.1 Carga de datos

library(readr)
library(dplyr)
library(tidyr)
library(knitr)

metrics_all <- read_csv("data/metricas_5DMA_AB.csv", show_col_types = FALSE)
wide <- read_csv("data/tabla_5DMA_AB_delta.csv", show_col_types = FALSE)

metrics_all
## # A tibble: 10 × 8
##    dma   estado n_nodos n_aristas densidad n_componentes pct_grado1
##    <chr> <chr>    <dbl>     <dbl>    <dbl>         <dbl>      <dbl>
##  1 DMA01 A          543       651  0.00442             2       20.6
##  2 DMA01 B          535       628  0.00440             1       21.3
##  3 DMA02 A           92       100  0.0239              5       31.5
##  4 DMA02 B           88        96  0.0251              1       35.2
##  5 DMA03 A          151       176  0.0155              1       25.2
##  6 DMA03 B          151       174  0.0154              1       26.5
##  7 DMA04 A          118       125  0.0181              1       39.0
##  8 DMA04 B          118       124  0.0180              1       39.8
##  9 DMA05 A           45        47  0.0475              1       42.2
## 10 DMA05 B           45        47  0.0475              1       42.2
## # ℹ 1 more variable: longitud_total_m <dbl>
wide
## # A tibble: 5 × 17
##   dma   n_nodos_A n_nodos_B n_aristas_A n_aristas_B densidad_A densidad_B
##   <chr>     <dbl>     <dbl>       <dbl>       <dbl>      <dbl>      <dbl>
## 1 DMA01       543       535         651         628    0.00442    0.00440
## 2 DMA02        92        88         100          96    0.0239     0.0251 
## 3 DMA03       151       151         176         174    0.0155     0.0154 
## 4 DMA04       118       118         125         124    0.0181     0.0180 
## 5 DMA05        45        45          47          47    0.0475     0.0475 
## # ℹ 10 more variables: n_componentes_A <dbl>, n_componentes_B <dbl>,
## #   pct_grado1_A <dbl>, pct_grado1_B <dbl>, longitud_total_m_A <dbl>,
## #   longitud_total_m_B <dbl>, d_n_componentes <dbl>, d_pct_grado1 <dbl>,
## #   d_densidad <dbl>, d_longitud_m <dbl>

5.2 Tabla A vs B por DMA

kable(metrics_all, digits = 4,
      caption = "Métricas topológicas por DMA en estados A y B (piloto n=5).")
Métricas topológicas por DMA en estados A y B (piloto n=5).
dma estado n_nodos n_aristas densidad n_componentes pct_grado1 longitud_total_m
DMA01 A 543 651 0.0044 2 20.6262 32109.184
DMA01 B 535 628 0.0044 1 21.3084 32079.499
DMA02 A 92 100 0.0239 5 31.5217 5772.750
DMA02 B 88 96 0.0251 1 35.2273 5765.743
DMA03 A 151 176 0.0155 1 25.1656 9473.718
DMA03 B 151 174 0.0154 1 26.4901 9470.653
DMA04 A 118 125 0.0181 1 38.9831 6578.788
DMA04 B 118 124 0.0180 1 39.8305 6577.888
DMA05 A 45 47 0.0475 1 42.2222 2748.221
DMA05 B 45 47 0.0475 1 42.2222 2748.221

5.3 Cambios Δ (B − A)

kable(wide, digits = 4,
      caption = "Diferencias por DMA (Δ = B − A) para variables topológicas.")
Diferencias por DMA (Δ = B − A) para variables topológicas.
dma n_nodos_A n_nodos_B n_aristas_A n_aristas_B densidad_A densidad_B n_componentes_A n_componentes_B pct_grado1_A pct_grado1_B longitud_total_m_A longitud_total_m_B d_n_componentes d_pct_grado1 d_densidad d_longitud_m
DMA01 543 535 651 628 0.0044 0.0044 2 1 20.6262 21.3084 32109.184 32079.499 -1 0.6823 0.0000 -29.6849
DMA02 92 88 100 96 0.0239 0.0251 5 1 31.5217 35.2273 5772.750 5765.743 -4 3.7055 0.0012 -7.0071
DMA03 151 151 176 174 0.0155 0.0154 1 1 25.1656 26.4901 9473.718 9470.653 0 1.3245 -0.0002 -3.0651
DMA04 118 118 125 124 0.0181 0.0180 1 1 38.9831 39.8305 6578.788 6577.888 0 0.8475 -0.0001 -0.9000
DMA05 45 45 47 47 0.0475 0.0475 1 1 42.2222 42.2222 2748.221 2748.221 0 0.0000 0.0000 0.0000

5.4 Estadística descriptiva global por estado

resumen <- metrics_all %>%
  group_by(estado) %>%
  summarise(
    med_componentes = median(n_componentes),
    iqr_componentes = IQR(n_componentes),
    med_pct_grado1  = median(pct_grado1),
    iqr_pct_grado1  = IQR(pct_grado1),
    med_longitud_m  = median(longitud_total_m),
    iqr_longitud_m  = IQR(longitud_total_m),
    .groups = "drop"
  )

kable(resumen, digits = 4, caption = "Mediana e IQR por estado (A vs B).")
Mediana e IQR por estado (A vs B).
estado med_componentes iqr_componentes med_pct_grado1 iqr_pct_grado1 med_longitud_m iqr_longitud_m
A 1 1 31.5217 13.8175 6578.788 3700.967
B 1 0 35.2273 13.3404 6577.888 3704.910

5.5 Validación inferencial: Wilcoxon pareado (piloto)

w_comp <- wilcox.test(wide$n_componentes_B, wide$n_componentes_A, paired = TRUE, exact = FALSE)
w_deg1 <- wilcox.test(wide$pct_grado1_B,   wide$pct_grado1_A,   paired = TRUE, exact = FALSE)
w_len  <- wilcox.test(wide$longitud_total_m_B, wide$longitud_total_m_A, paired = TRUE, exact = FALSE)

w_comp
## 
##  Wilcoxon signed rank test with continuity correction
## 
## data:  wide$n_componentes_B and wide$n_componentes_A
## V = 0, p-value = 0.3711
## alternative hypothesis: true location shift is not equal to 0
w_deg1
## 
##  Wilcoxon signed rank test with continuity correction
## 
## data:  wide$pct_grado1_B and wide$pct_grado1_A
## V = 10, p-value = 0.1003
## alternative hypothesis: true location shift is not equal to 0
w_len
## 
##  Wilcoxon signed rank test with continuity correction
## 
## data:  wide$longitud_total_m_B and wide$longitud_total_m_A
## V = 0, p-value = 0.1003
## alternative hypothesis: true location shift is not equal to 0
tests <- data.frame(
  variable = c("n_componentes", "pct_grado1", "longitud_total_m"),
  V = c(as.numeric(w_comp$statistic), as.numeric(w_deg1$statistic), as.numeric(w_len$statistic)),
  p_value = c(w_comp$p.value, w_deg1$p.value, w_len$p.value)
)

kable(tests, digits = 4, caption = "Resultados Wilcoxon pareado (A vs B).")
Resultados Wilcoxon pareado (A vs B).
variable V p_value
n_componentes 0 0.3711
pct_grado1 10 0.1003
longitud_total_m 0 0.1003

5.6 Visualización rápida (cambio pareado)

plot(wide$n_componentes_A, wide$n_componentes_B,
     xlab = "A: n_componentes", ylab = "B: n_componentes",
     main = "Cambio pareado por DMA (A→B)")
abline(0, 1)
text(wide$n_componentes_A, wide$n_componentes_B, labels = wide$dma, pos = 3)

6 Discusión

En el piloto se observan mejoras marcadas en conectividad (reducción de componentes) en DMAs con inconsistencias iniciales, mientras que DMAs previamente consistentes permanecen estables. El contraste Wilcoxon no muestra significancia estadística a α=0.05, coherente con el tamaño muestral reducido (n=5) y con la concentración del cambio en algunos DMAs. Estos resultados respaldan el uso del flujo QGIS/PostGIS→Grafo como validación cuantitativa previa, y justifican escalar el análisis a un mayor número de DMAs (p. ej., 10 o 87) para fortalecer la inferencia.

7 Conclusiones

  1. La conversión desde QGIS/PostGIS a grafo permite cuantificar la conectividad y estructura topológica por DMA.
  2. La validación/corrección en el dominio de grafos reduce componentes desconectadas en DMAs con problemas iniciales.
  3. En el piloto, Wilcoxon no detecta diferencias significativas, consistente con baja potencia estadística; se recomienda ampliar la muestra.
  4. El protocolo constituye una base cuantitativa confiable para avanzar al tema principal.

8 Reproducibilidad

sessionInfo()
## R version 4.5.2 (2025-10-31 ucrt)
## Platform: x86_64-w64-mingw32/x64
## Running under: Windows 11 x64 (build 26200)
## 
## Matrix products: default
##   LAPACK version 3.12.1
## 
## locale:
## [1] LC_COLLATE=Spanish_Bolivia.utf8  LC_CTYPE=Spanish_Bolivia.utf8   
## [3] LC_MONETARY=Spanish_Bolivia.utf8 LC_NUMERIC=C                    
## [5] LC_TIME=Spanish_Bolivia.utf8    
## 
## time zone: America/La_Paz
## tzcode source: internal
## 
## attached base packages:
## [1] stats     graphics  grDevices utils     datasets  methods   base     
## 
## other attached packages:
## [1] knitr_1.51  tidyr_1.3.2 dplyr_1.1.4 readr_2.1.6
## 
## loaded via a namespace (and not attached):
##  [1] crayon_1.5.3      vctrs_0.7.1       cli_3.6.5         rlang_1.1.7      
##  [5] xfun_0.56         purrr_1.2.1       generics_0.1.4    jsonlite_2.0.0   
##  [9] bit_4.6.0         glue_1.8.0        htmltools_0.5.9   sass_0.4.10      
## [13] hms_1.1.4         rmarkdown_2.30    evaluate_1.0.5    jquerylib_0.1.4  
## [17] tibble_3.3.1      tzdb_0.5.0        fastmap_1.2.0     yaml_2.3.12      
## [21] lifecycle_1.0.5   compiler_4.5.2    pkgconfig_2.0.3   rstudioapi_0.18.0
## [25] digest_0.6.39     R6_2.6.1          utf8_1.2.6        tidyselect_1.2.1 
## [29] parallel_4.5.2    vroom_1.7.0       pillar_1.11.1     magrittr_2.0.4   
## [33] bslib_0.10.0      bit64_4.6.0-1     tools_4.5.2       cachem_1.1.0