Skip to content
R0SEWTPublic

About

Riesgo delictivo latente en Lima bajo sesgo de denuncia: experimentos en marimo donde cada cifra tiene procedencia verificable. Incluye el TP de Complex Networks sobre corredores críticos.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Repository files navigation

InWatch

Riesgo delictivo latente en Lima, medido bajo el sesgo de denuncia,
en experimentos visuales donde cada cifra tiene procedencia verificable.

Python uv marimo CI

Experimentos · TP de Complex Networks · Diapositivas del Hito 1 · Empezar · Ninguna cifra a mano

El pulso de estadios: riesgo de robo callejero alrededor del Estadio Monumental, hora por hora, promedio de 71 días de partido
La pieza de difusión de pulso-estadios: el riesgo alrededor del Monumental en días de partido, contra el mismo lugar sin partido.

Contenido
  1. Qué es
  2. Experimentos
  3. TP de Complex Networks: corredores críticos
  4. Cómo está hecho
  5. Empezar
  6. Mapa del repo
  7. Convenciones
  8. Equipo
  9. Licencia

Qué es

Los datos policiales no miden crimen. Miden la intersección de tres filtros: que la víctima denuncie, que la institución registre y que el sistema geocodifique. Los tres son fuertes y desiguales en el espacio, así que un mapa que los ignora muestra dónde se denuncia, no dónde ocurre.

InWatch es el banco de experimentos donde esa premisa se vuelve manipulable. Cada experimento es un notebook reactivo que permite mover un parámetro y ver qué le pasa al hallazgo. Dos reglas atraviesan todo el repo:

  • Sin datos ≠ seguro. Una celda sin registro se dibuja deshilachada, nunca vacía ni verde.
  • Ningún número se escribe a mano. Toda cifra portante sale de un registro canónico, con el commit y el hash del script que la produjo (ver cómo).

No es un producto de ruteo ni un mapa de calor de denuncias.

(volver arriba)

Experimentos

Cada uno responde una pregunta, y la respuesta corta está acá. El detalle, los controles y las limitaciones están en el README de cada experimento.

Experimento La pregunta Lo que encontró
donde-falla-el-dato ¿Dónde deja de decir algo el mapa de denuncias? Solo el 34.5 % de la grilla de Lima y Callao tiene al menos un registro geocodificado. El resto no es calma: es ausencia de dato.
observado-latente Corregir por subdenuncia, ¿reordena el mapa? No: ρ = 0.997 entre las dos superficies. Cambia la escala y la composición: la estafa pasa de 4.3 % a 32.1 % del riesgo.
curva-de-evaluabilidad Con un registro flaco, ¿se puede saber si el modelo acierta? Con 10 % de geocodificación, la habilidad real apenas cae (0.433 de ρ), pero la medible se desploma a 0.316. Colapsa el termómetro, no el modelo.
tejido-vs-hexagono ¿Cuánto cuesta mirar Lima a través de hexágonos? El 11.0 % de las manzanas morfológicas cae partido entre dos o más hexágonos: el 27.2 % del área.
pulso-estadios Si el crimen sube alrededor del estadio, ¿hay más delito o más gente que denuncia? En los primeros 500 m, el riesgo en días de partido es 3.67 veces el de días emparejados sin partido, y el pulso desaparece en los partidos sin público.
corredores-criticos ¿Qué calles concentran el flujo potencial de la red vial? Del top-100 por betweenness, solo el 20.0 % es arteria declarada en OSM, contra una tasa base de 12.5 %. Cuatro de cada cinco corredores no están declarados arteriales.

(volver arriba)

TP de Complex Networks: corredores críticos

Diapositiva del hallazgo 3: el top-100 de tramos por betweenness contra las arterias de OSM
Clic para ver la exposición completa, con el guion de cada diapositiva.

corredores-criticos es el Trabajo Parcial del curso Complex Networks (UPC 1ACC0202, 2026-2), tema 2. Mide la betweenness exacta, por longitud y por tiempo de viaje, sobre la red drive de OpenStreetMap del eje Metropolitano centro-sur: 7559 intersecciones.

Entregable Dónde
Diapositivas y guion r0sewt.github.io/InWatch/hito1, con PDF y PowerPoint para descargar
Notebook con salidas entrega/hito1.ipynb, que se abre en GitHub sin correr nada
Reporte técnico README del experimento, con cada cifra anclada al registro
Entorno requirements.txt, generado desde uv.lock

La cadena completa se reprodujo desde un clon limpio en otra máquina: mismos nodos, mismas aristas y mismas cifras.

(volver arriba)

Cómo está hecho

fuentes por nombre ──► loader.py / etapas ──► data/silver/<slug>/*.parquet   (gitignored)
(registry/fuentes.toml)        │                        │
                               ▼                        ▼
                  registry/canonical_numbers.json   notebook.py (marimo) ──► .ipynb / WASM
                  valor + commit + sha del script         │
                  y de los insumos                        ▼
                               └──────────► README y docs citan la cifra por clave
                                            la CI falla si una cita no coincide

Qué corre dónde. marimo exporta a WASM, pero geopandas y PyTorch Geometric no corren en Pyodide. Por eso la separación no se negocia: loader.py hace el cómputo pesado y deja parquet con hash; notebook.py lee artefactos y presenta, nunca calcula desde datos crudos.

Ninguna cifra a mano. El mecanismo existe porque el fallo ya ocurrió: en el repo de origen, un multiplicador quedó desactualizado tras volver a correr el pipeline y llegó así a un paper enviado. Ahora el emisor registra el número con su procedencia, y todo lo demás lo pide por clave:

from inwatch import canon

canon.emit(
    "multiplier.robo_hurto_callejero", lat / obs, variant="victim",
    unit="latente/observado (adim.)", estimator="pooled Σλ*/Σy 2018-2024",
    inputs=[rate_file], script=__file__,
)

canon.display("multiplier.robo_hurto_callejero")   # "4.6", ya redondeado por la policy

Los documentos lo citan con un ancla CANON: en un comentario HTML junto a la cifra, incluido este README. uv run canon check las valida todas y corre en la CI.

La unidad espacial es un parámetro. Conviven la grilla H3 res-8 (h3_8), la manzana censal (manzana) y la tesselación morfológica (morfologica); poder cambiar entre ellas es uno de los experimentos. El contrato completo está en design/contrato-unidades.md.

(volver arriba)

Empezar

Requisitos: Python 3.12 y uv. Sin uv: pip install -r requirements.txt.

1. Entorno y verificación. No necesita datos:

uv sync --extra geo --extra viz
uv run pytest -q -m "not needs_data"
uv run canon check

Los tests tienen que pasar, y canon check tiene que terminar con ✓ check_canon: N ancla(s) verificada(s) contra el registro.

2. Un experimento de punta a punta. corredores-criticos es el único que corre sin los datos privados del repo de origen; solo pide transit_stations.csv (ver su README):

export INWATCH_FUENTE_TRANSIT_STATIONS=/ruta/a/transit_stations.csv
for etapa in loader centralidad capas arterias metricas; do
  uv run python experiments/corredores-criticos/$etapa.py
done
uv run marimo edit experiments/corredores-criticos/notebook.py

El loader tiene que reportar 7559 nodos y 15813 aristas. La betweenness exacta tarda entre 10 y 20 minutos, según la máquina.

Los demás experimentos leen el corpus de denuncias y los artefactos de la tesis de origen, que no son públicos. Sus fuentes se resuelven por nombre con uv run fuentes estado.

(volver arriba)

Mapa del repo

Ruta Qué hay
experiments/<slug>/ Un experimento: etapas de cómputo, notebook.py, README.md con las cifras ancladas, y tests.
src/inwatch/ El paquete: canon (registro de cifras), fuentes (catálogo de datos por nombre) y unidades (contrato espacial, incluida la red vial).
registry/ canonical_numbers.json, versionado porque es memoria científica, y fuentes.toml.
design/ Contratos de datos y decisiones de diseño.
analysis/ Reportes por experimento, versionados; los datos no.
tests/ Pruebas sobre datos sintéticos, que corren en cada PR.
data/ Artefactos regenerables (gitignored), salvo data/curado/, que sí viaja.

(volver arriba)

Convenciones

  • Git Flow: nada entra directo a develop ni a main. Una rama por unidad de trabajo (feat/…, fix/…, docs/…) desde develop, y un PR con la CI en verde y las conversaciones de revisión resueltas. main recibe a develop por release, con tag por entregable (hito1, …).
  • Ninguna cifra a mano: toda cifra portante pasa por canon. Lo que emite cifras se fusiona con merge commit, nunca con squash, para que el commit de procedencia siga existiendo en la historia.
  • Tareas en beads (bd ready), no en TODOs sueltos.
  • Repo público: nada de secretos, credenciales, datos crudos ni rutas de máquina. El grupo del TP se nombra por usuario de GitHub.

Las reglas completas, para agentes y para personas, están en CLAUDE.md.

(volver arriba)

Equipo

El TP de Complex Networks es del grupo 2 (UPC, 2026-2).

(volver arriba)

Licencia

Sin definir todavía, y por eso sin LICENSE: todos los derechos reservados.

El repo es público desde el 2026-09-14 para poder compartirlo, entre otros con el docente del curso donde se usa. Que sea público no concede permisos de reutilización. La licencia sigue siendo una decisión pendiente y deliberada: el material derivado proviene de un repo bajo CC BY-NC-SA 4.0 con dos titulares de copyright, así que no puede elegirse en solitario ni por defecto. Mientras tanto aplican los términos de GitHub para ver y hacer fork; cualquier otro uso requiere permiso de los titulares.

(volver arriba)

About

Riesgo delictivo latente en Lima bajo sesgo de denuncia: experimentos en marimo donde cada cifra tiene procedencia verificable. Incluye el TP de Complex Networks sobre corredores críticos.

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages