Aqualia
Connecting Waterpeople

IA en el agua para todos 3: Algo más que lectura inteligente… predictiva

  • IA agua todos 3: Algo más que lectura inteligente… predictiva

Sobre el blog

José María de Cuenca de la Cruz
Curioso, inquieto y creativo… aprendiz de escritor, e interesado también por las nuevas tecnologías y la educación. Me encanta asumir retos y compartir lo aprendido. Trabajando en lo que me apasiona…. me siento como un pez, en el agua claro.
Xylem Water Solutions España
Global Omnium

Haber desplegado un sistema de telelectura no es igual que tener una lectura inteligente.

Sin el análisis de los datos y la comprensión de toda la información recabada, nos quedaremos en un analfabetismo funcional, y pronto tendremos que dar la razón a los que nos advirtieron que no era rentable ir más allá de la lectura necesaria para la facturación. Para evitarlo, no hay en el mercado una solución de tele lectura que no se nos muestre con una cautivadora plataforma de software.

En estas plataformas, con frecuencias de solo una lectura diaria podremos conocer los patrones de consumo y gestionar mejor la demanda, además de simplificar enormemente la sectorización de nuestras redes (no hay retraso en la lectura de cada zona) e incluso reducir la aparición de fugas y minimizar el coste tanto de las pérdidas de agua, como de los daños que provocan. Si vamos más allá, con una frecuencia de lectura cuarto horaria podemos incluso detectar fallos en las instalaciones interiores del abonado, y hasta nos podemos plantear colaborar con los servicios sociales y de emergencias. Todas estas aplicaciones se basan en el análisis estadístico de las lecturas recogidas, para interpretar el entorno del consumo y facilitar las decisiones al operador.

Pero la inteligencia, desde mi punto de vista, también requiere desplegar creatividad y anticipación… e incluso autonomía. ¿Es posible entonces crear un sistema inteligente que prediga anticipadamente la demanda abonado por abonado, más allá de los análisis de los datos que incorporan las plataformas actuales? Vamos a crearlo –juntos- para convencerte de que es posible.

Las lecturas de un contador de agua sencillo son básicamente datos seriados, que se caracterizan por un sello temporal (timestamp) del momento en que se anotan, y el valor del volumen acumulado desde la última anotación. Usaremos el dataset de un consumidor doméstico, medido con un contador de velocidad de 13mm y un emisor de pulsos. Los datos han sido recogidos con nuestro propio diseño de datalogger GPRS y plataforma. Este dataset puede descargarse en formato csv desde aquí, donde también está el cuaderno Jupyter con el código que utilizaremos sobre Anaconda. Si estás siguiendo la serie de post, en el anterior puedes ver cómo instalar y utilizar ese entorno para ejecutar el código: la mecánica es la misma. O si lo prefieres, puedes abrir el archivo ipynb directamente en tu navegador para verlo.

Si trabajamos con datos en bruto, en primer lugar una vez cargados debemos comprobar que no hay valores anormales (datos faltantes, valores negativos según el tipo de emisor, imposiblemente elevados, etc…). Luego deberemos prepararlos para el análisis. Como se trata de una serie temporal, resulta esencial que la fecha esté en un formato específico para ellas.

Una vez tenemos los datos preparados, podremos realizar su análisis exploratorio: calcular estadísticas, buscar patrones o realizar gráficas… El cuaderno lo incluye porque siempre útil para explicar lo que sucede, aunque no sea estrictamente necesario para nuestro propósito, que es ilustrar como predecir el consumo de un abonado: aunque parezca mentira el aprendizaje automático resolverá cómo hacerlo.

El siguiente paso es elegir el método para pronosticar series temporales. Hay unos cuantos. Los más simples hacen suposiciones ingenuas con valores pasados. Otros algo más complejos usan medias móviles y buscan autocorrelaciones dentro de la serie. Hasta llegar a algoritmos de aprendizaje profundo, entre los que están las redes neuronales recurrentes, y más específicamente las redes LSTM (Long Short Term Memory), con una arquitectura especializada en aprender las variaciones de una secuencia, dando mayor peso a los datos más actuales y “olvidando” los más antiguos. Usaremos este último tipo de red recurrente, que actualmente es el más potente. Pero esta vez, a diferencia del segundo post, crearemos nuestra propia red neuronal y la entrenaremos… de ahí que incluya el archivo con el dataset.

Como ya vimos, cualquier red neuronal trabaja con los datos colocados sobre una matriz numérica, cuyos valores se sitúan en un rango acotado, por lo general de 0 a 1. Así que en primer lugar vamos a re-escalar la serie original. Luego, como se trata de una serie temporal, al convertirla en una matriz numérica usaremos n columnas adicionales en cada fila, en las que recoger los n valores de los registros anteriores. Por ejemplo, si tenemos datos cuarto horarios y queremos usar para la predicción los consumos de las 24h previas, añadiremos 96 columnas para otros tantos datos anteriores. De esta manera en cada registro o fila tendremos todos los valores precedentes que consideramos pueden influir en el último de ellos.

Nuevamente se trata de un aprendizaje supervisado, en el que los datos del problema son los registros de consumo anteriores al actual (los 96 datos añadidos en columnas adicionales), y la “etiqueta” o resultado correcto es el propio registro del consumo actual (el dato que corresponde al timestamp de esa fila).

Como queremos definir nuestra propia red, dividiremos este conjunto inicial de datos en 4 partes, en dos con el 80% de los datos y los resultados que usaremos para el entrenamiento de la red; y otras 2 de menor tamaño, también con los datos y los resultados restantes, que usaremos para comprobar si el modelo una vez entrenado trabaja correctamente. Porque para la comprobación es esencial usar datos que el modelo no tenga “aprendidos”. Un aspecto importante es que los datos entrarán en la matriz ordenados secuencialmente, pero sin las referencias de fecha. Por ello otra cosa importante es que todos los datos tengan igual frecuencia de registro, en este caso 15 minutos. Así tendremos matrices de datos con n registros por 96 columnas, que repiten con desplazamiento los datos de las filas anteriores. Y matrices de resultados o etiquetas, con solo una columna, el valor de la lectura realmente registrada para la misma fila de datos.

Por otra parte, para que puedan ser engullidas por nuestra red neuronal, las matrices de datos que hemos creado deben ser un arreglo de 3 dimensiones: muestras (número de muestras en los datos de entrada), pasos de tiempo (valores anteriores que usaremos) y características (en este caso solo el valor de los pulsos, aunque nada impide usar más variables y complicar el modelo). Por otra parte, la matriz con las etiquetas solo tendrá una dimensión, con los valores reales registrados. Comprender esta estructura matricial es esencial para poder crear la capa de entrada de una red LSTM.

A continuación vamos a definir la red neuronal. Para facilitar al máximo esta tarea usaremos Tensor Flow con la librería Keras y su modo secuencial. Si seguimos la instalación de Anaconda que referenciamos en el segundo post de esta serie, tendremos ya ambas disponibles. Comencemos: la primera capa de la red debe tener tantas celdas como valores anteriores estamos considerando para cada cálculo. Como consideramos que tendrán influencia las 24 horas anteriores de valores cuarto horarios, usaremos 24x4 = 96 nodos o neuronas, que a su vez coincidirá con la segunda de las dimensiones de la matriz de entrenamiento. A continuación podemos incorporar en la red una capa de dropout, que descarta de forma aleatoria el 10% de los datos para regularizar el modelo y reducir la posibilidad de sobreajustes a los datos de entrenamiento. Añadiremos dos veces más este par de capas para capturar los patrones entre los datos a la vez que los concentramos reduciendo su dimensionalidad. Hasta terminar en una capa totalmente conectada con una sola neurona de salida, cuyo valor deberá aproximarse lo más posible al resultado de cada muestra durante el aprendizaje de la red. El modelo sigue la estructura de un perceptrón multicapa típico de las redes neuronales, y funciona como una especie de embudo que elimina los detalles superfluos hasta llegar el resultado deseado.

En función del intervalo de retraso de los datos, tendremos mayor o menor número de columnas en la matriz, y de parámetros en la red. También podemos añadir otros tipos de información, como nuevas dimensiones de la matriz. Si lo hacemos el modelo tardará más en ejecutar su aprendizaje, aunque a cambio proporcionará datos mucho mejores. Como se trata de un ejemplo, lo mantendremos solo con las lecturas correspondientes a las 24 horas anteriores, de forma que se pueda entrenar con un pc en unos pocos minutos. El entrenamiento es el proceso por el que el modelo creado realiza su aprendizaje. Consiste en la asignación y ajuste de los pesos de influencia de unos nodos sobre otros dentro de la red, de manera que sus cálculos se aproximen lo más posible al resultado deseado.

Este entrenamiento se realiza por iteraciones sucesivas, en las que se ajustan los parámetros de cada nodo. El grado de avance entre dos iteraciones hacia el resultado deseado se regula con el coeficiente de paso. Si entre una época y la siguiente es muy alto permitiremos un ajuste muy grande entre los valores y podemos errar. Pero conforme nos acerquemos más a los resultados, el paso debe reducirse, para ir afinando el modelo. Por ello es aconsejable permitir valores mayores en las primeras iteraciones e ir reduciéndolo cuando el modelo no sea capaz de seguir aprendiendo tras varias repeticiones. Para este ejemplo haremos 20 iteraciones ó épocas. Se incluye un gráfico para ver cómo con cada iteración se van reduciendo las pérdidas, y el modelo cada vez es más preciso.

Una vez entrenado, usamos el conjunto de datos de prueba que separamos, para ver si es capaz de ajustarlos a los resultados de prueba. Con él obtenemos las métricas de error para la predicción del modelo, por lo general media y error cuadrático medio.

Si hacemos una gráfica con las predicciones, veremos que siguen un patrón similar al de los valores reales, aunque este primer modelo aún no es capaz de reproducir fielmente los intervalos de consumo cero, ni la verdadera magnitud de las puntas de caudal. Esto es debido a haber utilizado un histórico de consumos bastante limitado (unos pocos meses), lo que a su vez condiciona el número de valores anteriores (datos de solo las últimas 24 horas). Con un registro más amplio y con valores anteriores de varios días, el modelo sería básicamente el mismo pero sus resultados mejorarían mucho… aunque el tiempo de ejecución también sería mayor. El equilibrio entre estas opciones estará en la utilidad que le queramos dar a nuestro modelo…

Para contestar a preguntas como ¿goteará la cisterna? ¿fallará el contador? ¿tuvo un accidente el abonado o simplemente se ausentó? es cuestión de añadir esas etiquetas a los datos, y ampliar las dimensiones de las matrices….

Por otra parte, también es posible detectar anomalías en las predicciones, y explotarlas mediante aprendizaje no supervisado… de manera que el propio sistema se pregunte ¿qué patrón en los datos de entrada provoca la desviación?. Es decir, que el algoritmo detecte que se equivoca y busque las causas… porque el mayor signo de inteligencia probablemente sea reconocer nuestro desconocimiento.

Si he logrado interesarle lo suficiente como para seguir paso a paso todo lo relatado en este post, puede descargar el dataset y el código aquí. Espero que esté bastante comentado como para que pueda seguirlo fácilmente. Si tiene dudas o inquietudes, puede intentar contactar conmigo mediante un comentario a este blog.