Después de cenar en el centro de San Francisco, me despedí de mis amigos y saqué mi teléfono para pensar cómo llegar a casa. Eran cerca de las 11:30 p. m. y las estimaciones de Uber eran inusualmente largas. Abrí Google Maps y miré las indicaciones para caminar. Las rutas eran similares en distancia, pero dudé, no por cuánto tiempo tomaría la caminata, sino porque no estaba seguro de cómo se sentirían las diferentes partes de la ruta a esa hora de la noche. Google Maps podría decirme el camino más rápido a casa, pero no pudo ayudar a responder la pregunta que en realidad estaba haciendo: ¿cómo puedo filtrar una ruta que me lleve a través de bloques más seguros en lugar de la ruta más rápida?
Definición del planteamiento del problema
Dada una ubicación inicial, una ubicación final, un día de la semana y una hora, ¿cómo podemos predecir el riesgo esperado en la ruta a pie determinada? Por ejemplo, si quiero caminar desde el Ferry Building hasta Lower Nob Hill, Google Maps me muestra las siguientes rutas:
En un nivel alto, el problema que quería resolver era el siguiente: dada una ubicación inicial, una ubicación final, una hora del día y un día de la semana, ¿cómo podemos estimar el riesgo esperado a lo largo de una ruta a pie?
Por ejemplo, si quiero caminar desde Chinatown hasta Market y Van Ness, Google Maps presenta un par de opciones de ruta, todas ellas de aproximadamente 40 minutos. Si bien es útil comparar la distancia y la duración, no ayuda a responder una pregunta más contextual: ¿qué partes de estas rutas tienden a verse diferentes según el tiempo que estoy haciendo la caminata? ¿Cómo se compara la misma ruta a las 9 am de un martes versus a las 11 pm de un sábado?
A medida que las caminatas se hacen más largas (o pasan por áreas con patrones de actividad histórica muy diferentes), estas preguntas se vuelven más difíciles de responder intuitivamente. Si bien San Francisco no es especialmente inseguro en comparación con otras ciudades importantes, la seguridad pública sigue siendo una consideración importante, especialmente cuando se camina por áreas desconocidas o en momentos desconocidos. Mi objetivo era crear una herramienta tanto para locales como para visitantes que agregue contexto a estas decisiones, utilizando datos históricos y aprendizaje automático para mostrar cómo varía el riesgo en el espacio y el tiempo, sin reducir la ciudad a etiquetas simplistas.
Obtener los datos + preprocesamiento
Obteniendo el conjunto de datos sin procesar
Los departamentos de la ciudad y el condado de San Francisco publican diariamente informes de incidentes policiales a través del portal San Francisco Open Data. El conjunto de datos abarca desde el 1 de enero de 2018 hasta el presente e incluye información estructurada como categoría, subcategoría, descripción, hora y ubicación (latitud y longitud) del incidente.
Categorización de incidentes reportados
Un desafío inmediato con estos datos es que no todos los incidentes representan el mismo nivel o tipo de riesgo. Tratar todos los informes por igual borraría las diferencias significativas; por ejemplo, un informe de vandalismo menor no debería ponderarse de la misma manera que un incidente violento. Para abordar esto, primero extraje todas las combinaciones únicas de categoría, subcategoría y descripción de incidentes, lo que resultó en un poco más de 800 tripletes de incidentes distintos.
En lugar de calificar incidentes individuales directamente, utilicé un LLM para asignar puntuaciones de gravedad a cada tipo de incidente único. Esto me permitió normalizar las diferencias semánticas en los datos manteniendo la puntuación consistente e interpretable. Cada tipo de incidente se calificó en tres dimensiones separadas, cada una en una escala de 0 a 10:
Puntuación de daño: el riesgo potencial para la seguridad humana y de los transeúntes Puntuación de propiedad: el potencial de daño o pérdida de propiedad Puntuación de perturbación pública: el grado en que un incidente perturba la actividad pública normal
Estas tres puntuaciones se combinaron posteriormente para formar una señal de gravedad general para cada incidente, que luego podría agregarse espacial y temporalmente. Este enfoque hizo posible modelar el riesgo de una manera que refleje tanto la frecuencia como la naturaleza de los incidentes reportados, en lugar de depender únicamente de recuentos brutos.
Representación geoespacial
Proporcionar números de latitud y longitud sin procesar no agregará mucho valor al modelo de aprendizaje automático porque necesito agrupar el contexto agregado del incidente a nivel de bloque y vecindario. Necesitaba un método para asignar un bloque o vecindario a un índice fijo para simplificar la ingeniería de características y crear un mapeo espacial consistente. Vaya al blog de ingeniería fundamental publicado por Uber: H3.
El blog H3 de Uber describe cómo proyectar un icosaedro (poliedro de 20 caras) a la superficie de la tierra y dividirlo jerárquicamente en formas hexagonales (y 12 pentágonos estratégicamente colocados) puede ayudar a formar un mosaico en todo el mapa. Los hexágonos son especiales porque son uno de los pocos polígonos regulares que forman teselados regulares y su punto central es equidistante de sus vecinos, lo que simplifica el suavizado de gradientes.
¡El sitio web https://clupasq.github.io/h3-viewer/ es un experimento divertido para ver cuál es el índice H3 de su ubicación!
Representación Temporal
El tiempo es tan importante como la ubicación al modelar el riesgo al caminar. Sin embargo, codificar ingenuamente la hora y el día como números enteros introduce discontinuidades: las 23:59 y las 00:00 están numéricamente muy separadas, aunque en realidad solo están separadas por un minuto.
Para solucionar esto, codifiqué la hora del día y el día de la semana usando transformaciones de seno y coseno, que representan valores cíclicos en un círculo unitario. Esto permite que el modelo aprenda que las horas de la noche y las primeras horas de la mañana son temporalmente adyacentes, y que los días de la semana transcurren naturalmente del sábado al domingo.
Además, agregué incidentes en períodos de tiempo de 3 horas. Las ventanas más cortas eran demasiado escasas para producir señales confiables, mientras que las ventanas más grandes ocultaban diferencias significativas (por ejemplo, temprano en la tarde versus tarde en la noche). Los períodos de tres horas lograron un equilibrio entre granularidad y estabilidad, lo que dio como resultado períodos intuitivos como temprano en la mañana, tarde y última hora de la noche.
Representación de características finales
Después del preprocesamiento, cada punto de datos constaba de:
Un índice H3 que representa la ubicación. Funciones de hora y día codificadas cíclicamente. Una señal de gravedad agregada derivada de incidentes históricos.
Luego se entrenó el modelo para predecir el riesgo esperado para una célula H3 determinada, en un momento determinado del día y de la semana. En la práctica, esto significa que cuando un usuario abre la aplicación y proporciona una ubicación y hora, el sistema tiene suficiente contexto para estimar cómo varía el riesgo de caminar en las cuadras cercanas.
Entrenando el modelo usando XGBoost
¿Por qué XGBoost?
Con las características geoespaciales y temporales listas, sabía que necesitaba aprovechar un modelo que pudiera capturar patrones no lineales en el conjunto de datos y al mismo tiempo proporcionara baja latencia para realizar inferencias en múltiples segmentos de una ruta. XGBoost encajaba naturalmente por un par de razones:
Los modelos basados en árboles son naturalmente robustos en el modelado de datos heterogéneos: índices espaciales categóricos, características de tiempo cíclico y entradas escasas pueden coexistir sin una gran escalación o normalización de características. Los efectos de las características son más interpretables que en las redes neuronales profundas, que tienden a introducir opacidad innecesaria para los datos tabulares. La flexibilidad en los objetivos y la regularización permitieron modelar el riesgo de manera que se alinee con la estructura del problema.
Si bien consideré alternativas como modelos lineales, bosques aleatorios y redes neuronales, no resultaron satisfactorias debido a la incapacidad de capturar los matices de los datos, la alta latencia en el momento de la inferencia o la complicación excesiva de los datos tabulares. XGBoost logra el mejor equilibrio entre rendimiento y practicidad.
Modelado del riesgo esperado
Es importante aclarar antes de continuar que modelar el riesgo esperado no es un problema gaussiano. Al modelar las tasas de incidentes en la ciudad, noté por celda [H3, tiempo] que:
varias celdas tienen un recuento de incidentes = 0 y/o riesgo total = 0 varias celdas tienen solo 1 o 2 incidentes un puñado de celdas tienen incidentes muchos incidentes (> 1000) ocurren eventos extremos, pero rara vez
Estas son señales de que mi modelo no es simétrico ni los puntos de datos se agruparán alrededor de una media fija. Estas propiedades descartan inmediatamente suposiciones comunes como los errores distribuidos normalmente.
Aquí es donde la regresión Tweedie resulta útil.
¿Qué es la regresión Tweedie?
En pocas palabras, la regresión de Tweedie dice: "Su valor es la suma de eventos aleatorios donde el número de eventos es aleatorio y cada evento tiene un tamaño aleatorio positivo". Esto encaja perfectamente con el modelo de incidente criminal.
La regresión de Tweedie combina los procesos de distribución de Poisson y Gamma para modelar el número de incidentes y el tamaño (puntuación de riesgo) de cada incidente. Como ejemplo:
Proceso de Poisson: en la ventana de 6:00 p. m. a 9:00 p. m. del 10 de diciembre de 2025, ¿cuántos incidentes ocurrieron en el índice H3 89283082873ffff? Distribución gamma: ¿qué gravedad tuvo cada evento ocurrido en el índice H3 89283082873ffff entre las 6 p. m. y las 9 p. m. del 10 de diciembre de 2025?
¿Por qué esto es importante?
Un ejemplo concreto de los datos ilustra por qué este marco es importante.
En el Presidio, hubo un único y poco común incidente de alta gravedad que obtuvo una puntuación cercana a 9/10. Por el contrario, una cuadra cerca de 300 Hyde Street en Tenderloin tiene miles de incidentes a lo largo del tiempo, pero con una gravedad promedio más baja. Tweedie lo desglosa como:
Riesgo esperado = E[#incidentes] × E[severidad] # Presidio E[#] ≈ ~0 E[severidad] = alto → Riesgo esperado ≈ todavía ~0 # Lomo E[#] = alto E[severidad] = medio → Riesgo esperado = grande
Por lo tanto, si los eventos de alto riesgo tienden a ocurrir con más frecuencia en Presidio, entonces se ajustará el riesgo esperado en consecuencia y se elevarán las puntuaciones de producción. Tweedie maneja la distribución sesgada a la derecha y con peso cero del objetivo y las características de entrada que analizamos anteriormente simplemente explican la variación en ese objetivo.
Enmarcar el resultado
El resultado es un modelo que predice el riesgo esperado, no la gravedad condicional ni las etiquetas de seguridad binarias. Esta distinción importa. Evita reaccionar exageradamente ante eventos raros pero extremos, y al mismo tiempo refleja patrones sostenidos que emergen con el tiempo.
Pasos finales + Implementaciones
Para darle vida al modelo, utilicé la API de Google Maps para crear un sitio web que integra los mapas, las rutas y la interfaz de usuario de direcciones en la que puedo superponer colores según las puntuaciones de riesgo. Codifiqué por colores los segmentos tomando un percentil de distribuciones en mis datos, es decir, puntuación ≤ P50 = verde (seguro), puntuación ≤ P75 = amarillo (moderadamente seguro), puntuación ≤ P90 = naranja (moderadamente riesgoso), en caso contrario, rojo (arriesgado). También agregué una lógica para redirigir al usuario a través de una ruta más segura si el desvío no supera el 15% de la duración original. Esto se puede modificar, pero lo dejé como está por ahora ya que con las colinas de San Francisco un desvío del 15% podría funcionarte mucho.
También implementé backend en Render y frontend en Vercel.
¡Usando StreetSense!
Y ahora, volvamos al primer ejemplo que vimos: el viaje desde Chinatown hasta Market y Van Ness, ¡pero ahora con nuestro nuevo modelo + aplicación que hemos creado!
Así es como se ve la caminata a las 9 a.m. de un martes versus a las 11 p.m. de un sábado:
En la primera imagen, los segmentos de Chinatown que son verdes tienen un menor número de incidentes y gravedad en comparación con los segmentos que son rojos y los datos también lo respaldan. Lo bueno de la segunda imagen es que redirige automáticamente al usuario a través de una ruta que es más segura a las 11 p. m. de un sábado por la noche. Este es el tipo de toma de decisiones contextual que deseaba originalmente y la motivación detrás de la creación de StreetSense.
Pensamientos finales y posibles mejoras
Si bien el sistema actual captura patrones espaciales y temporales en incidentes históricos, hay áreas claras que se pueden mejorar:
Incorporar señales en tiempo real utilizando más datos reales sobre el terreno para validar y entrenar.
(a) si un incidente se marcó con una puntuación de riesgo de robo de 4/10 y podemos descubrir a través de la base de datos de San Francisco que se realizó un arresto, podemos aumentarlo a 5/10 para hacer que el índice H3 sea sensible a las celdas vecinas: Richmond exterior ~ Richmond central, de modo que el modelo debería inferir la proximidad y la información contextual debería compartirse parcialmente. Ampliar las características espaciales más allá de la identificación H3 (agregación de vecinos, distancia a los puntos críticos, características de uso del suelo). exploración más profunda de diferentes métodos de manejo de datos de incidentes + evaluaciones
(a) experimentar con diferentes funciones objetivo de XGBoost, como Pseudo Huber Loss
(b) Aprovechar los marcos de optimización de hiperparámetros y evaluar diferentes combinaciones de valores
(c) experimentar con redes neuronales que se expandan más allá de una sola ciudad haría que el modelo fuera más sólido
Como cualquier modelo basado en datos históricos, StreetSense refleja patrones pasados en lugar de predecir resultados individuales, y debe usarse como una herramienta para el contexto en lugar de la certeza. En última instancia, el objetivo no es etiquetar lugares como seguros o inseguros, sino ayudar a las personas a tomar decisiones más informadas y conscientes de la situación mientras se desplazan por una ciudad.
Pruebe StreetSense: https://san-francisco-safety-index.vercel.app/
Fuentes de datos y licencias
Este proyecto utiliza datos disponibles públicamente del Portal de datos abiertos de San Francisco:
Informes de incidentes del Departamento de Policía de San Francisco
– Fuente: Portal de datos abiertos de San Francisco (https://data.sfgov.org)
– Licencia: Licencia y Dedicación de Dominio Público Open Data Commons (PDDL)
Todos los conjuntos de datos utilizados están disponibles públicamente y se les permite su reutilización, modificación y uso comercial bajo sus respectivas licencias de datos abiertos.
Reconocimientos y referencias
Me gustaría agradecer al equipo de Datos Abiertos de San Francisco por mantener conjuntos de datos públicos de alta calidad que hacen posibles proyectos como este.
Las referencias adicionales que informaron mi comprensión de los métodos y conceptos utilizados en este trabajo incluyen: