Samuel Blixen 4375 Torre A 1408
+598 2614 4965
hola@kreilabs.com

Completando registros de temperatura

Basándonos en los datos públicos de L.A.C.A. completamos el registro histórico de temperatura de la estación meteorológica de Azapa – Chile entre los años 1977-1980

Imagen que contiene hombre, persona, pared, interior Descripción generada automáticamente

Gabriel Naya | Kreilabs | 6/10/2019

Mi intención en este ejercicio fue ubicar un juego de datos sobre el clima de Uruguay, para revisar la evolución de las marcas de temperatura media diaria registradas en diferentes puntos del país, y – aplicando inteligencia artificial – completar los registros en caso de que hubiera datos faltantes.

Me fue imposible hallar un dataset publico de Uruguay, pero si pude acceder a datos publicados por Latin American Climate Assessment & Dataset (LACA&D), obteniendo archivos de tipo TXT mediante consulta al sitio: http://lacad.ciifen.org/ES/.

Formulación del problema

El ejercicio consiste en acotar el juego de datos a las estaciones meteorológicas de una región (Chile), buscando archivos que informen de registros en períodos de tiempo (en años) similares.

Una vez obtenidos los datos de al menos 6 estaciones meteorológicas, seleccionar una como destino, e intentar hallar una forma de predecir los valores de los registros faltantes.

El juego de datos

Se pre seleccionaron y obtuvieron los registros de las siguientes estaciones:

STAID STANAME CN LAT LON HGHT
553 CAQUENA CL -18:03:15 -69:12:06 4400
557 CHUNGARA AJATA CL -18:14:07 -69:11:00 4585
562 PARINACOTA EX ENDESA CL -18:12:15 -69:16:06 4420
564 GUALLATIRE CL -18:29:54 -69:09:17 4240
565 CHILCAYA CL -18:47:38 -69:05:04 4270
584 PACOLLO CL -18:10:37 -69:30:33 4185
585 PUTRE CL -18:11:57 -69:33:37 3545
587 PUTRE (DCP) CL -18:11:42 -69:33:32 3560
588 LLUTA CL -18:24:37 -70:10:09 290
589 MURMUNTANE CL -18:21:07 -69:33:07 3550
595 ARICA OFICINA CL -18:28:39 -70:19:15 20
596 AZAPA CL -18:30:56 -70:10:50 365
597 U. DEL NORTE CL -18:29:00 -70:17:37 55
598 EL BUITRE AERODROMO CL -18:30:43 -70:17:03 110
599 CHACA CL -18:49:01 -70:09:00 350
600 CODPA CL -18:49:56 -69:44:38 1870

De entre ellas, luego de analizar los períodos reportados y la calidad de los datos imputados, se seleccionaron definitivamente las siguientes estaciones del norte de Chile y sur de Perú, como soporte de información de entrada:

STAID STANAME CN LAT LON HGHT
553 CAQUENA CL -18:03:15 -69:12:06 4400
585 PUTRE CL -18:11:57 -69:33:37 3545
588 LLUTA CL -18:24:37 -70:10:09 290
595 ARICA OFICINA CL -18:28:39 -70:19:15 20
597 U. DEL NORTE CL -18:29:00 -70:17:37 55

Y se seleccionó la estación meteorológica de AZAPA (596) como objetivo

STAID STANAME CN LAT LON HGHT
596 AZAPA CL -18:30:56 -70:10:50 365

Básicamente todos los archivos tienen una fecha (DATE), un id del recurso (SOUID), la temperatura en décimas de grados centígrados (TG) y un indicador del origen del dato (Q_TG), donde Q_TG=cero implica un dato real, y Q_TG=9 implica un dato completado manualmente.

Vamos a importar la fecha como índice, y solamente la columna TG, creando cada uno de los dataframe y uniéndolos por el índice de fecha:

En este punto tenemos un dataframe con el set de datos integrado para empezar las diferentes aproximaciones a una solución.

Visualizando y depurando datos

Lo primero que vamos a hacer es asignar como nulos los registros que tienen TG=-9999

Y visualizar los datos nulos por columna

Si analizamos la información faltante por período en un heatmap:

Podemos observar que la información (fondo negro) es bastante compacta en el período octubre-1976 a diciembre 1984.

Al aplicar la eliminación de registros nulos en todo el dataset nos queda un juego de datos de 1477 registros, ubicados entre el 28/12/1976 y el 21/11/1984

Y si graficamos la información año a año:

Es hora de adentramos en aproximaciones a la solución posible.

Estrategia

Siempre antes de aproximarnos a un problema, debemos diseñar una estrategia. En realidad creo que la estrategia la tenemos en la cabeza pero antes de entrar de lleno a desarrollarla, resulta muy útil explicitarla para luego volver sobre ella. Por más que sabemos que al explorar las soluciones van surgiendo nuevos elementos que nos hacen alejarnos de esta idea original, la hacen variar, es bueno escribirla antes de empezar, y modificarla al concluir el trabajo.

Sobre este ejercicio, mi idea original era muy modesta, lo inicie como un ejercicio de un sábado a la mañana para mantenerme en forma, y realmente me ha desafiado más de lo esperado:

  • Veamos, se trata de un problema de regresión, debemos obtener la temperatura de una de las estaciones, así que probemos algoritmos de regresión y seguramente se termine el trabajo.
  • La fuente de datos es homogénea, no precisaríamos en principio hacer muchas cosas con las “features”.
  • El juego de datos es suficientemente amplio para pensar en buenos resultados, no presenta desbalances en los periodos de datos, o faltantes en ciertos meses, cosas del estilo que nos lleven a pensar en balanceo de datos.
  • Si los algoritmos de regresión no fueran suficientes con las columnas de las otras estaciones, se puede utilizar la fecha como dato adicional para agregar información estacional
  • Si los algoritmos no fueran suficientes, se pueden explorar una red neuronal de tipo RNN – LSTM.

Vayamos por un algoritmo de regresión

Antes de probar un conjunto de algoritmos de regresión, agregamos dos features al dataset, el seno y coseno del “día” del año, que va entre 0 y 360, tomando el primero de enero como día 1 y así ascendiendo hasta 359. Los últimos días del año, mayores o iguales a 359 son igualados a cero para simplificar la conversión.

Recordemos que los algoritmos de numpy para trignomoetría tienen su ingreso en radianes, por eso hacemos la conversión a grados antes de obtener seno y coseno:

Si en algún momento precisamos estas “features”, vamos a tener que escalar el resto de las columnas para dejar la información en un rango homogéneo y no desviar el funcionamiento interno de los algoritmos o redes que utilicemos.

Preparamos la entrada de datos a un modelo de regresión:

Luego de aplicar GradientBoostingRegressor de sklearn.ensemble, obtenemos los siguientes resultados:

Gradiente RMSLE score on train data:

5.4432688838663195

Accuracy –> 98.16939124093663

Gradiente RMSLE score on test data:

16.675179454983343

Accuracy –> 63.10001902521414

Lo que significa que en una primer aproximación con los datos de entrenamiento se obtiene una interesante precisión (que puede ser tomada como base para empezar a tratar de mejorarse); sin embargo, con los datos de test la precisión de la prediccion se derrumba: overfitting.

Tratemos de aplicarle KFold a nuestro algoritmo, probamos con grupos de datos de 10 y de 5, y en ambos casos el score es muy bajo, lo que nos indica que a priori por más precisión que obtengamos en el entrenamiento, al aplicarla sobre el juego de datos separado para testing, la precisión va a ser mala.

Bueno, definitivamente al obtener la precisión de validación cruzada, confirmamos que vamos muy mal. El algoritmo en si con el dataset se entrena bien, pero se pierde al sacarlo al dataset de testing, o si lo pusieramos en producción.

Podríamos aplicar diferentes técnicas para intentar mejorar esto, pero por suerte hay estrategias alternativas y la línea base nos lleva a intentar directamente con una red LSTM para ver si de inicio, tenemos mejores resultado.

Una red LSTM

Primero vamos a escalar los datos utilizando MinMaxScaler

Y nuevamente hacemos el corte de los datos en train y test, respetando la secuencialidad:

Armamos una red LSTM de 4 perceptrones, con una ventana de tiempo de 2 elementos, la entrenamos durante 100 y 150 epochs con un batch_size de 3, obteniendo:

Obtuvimos una precision de 4.71 decimas de grado en la media diaria, en principio es una precisión razonable:

Train: 6.56 RMSE

Test: 4.71 RMSE

Gráfico sobre los datos de entrenamiento

Y un gráfico sobre los datos de test:

Cambiamos la ventana de short memory a 5 observaciones y obtuvimos valores que no lo hicieron mejorar, incluso las cosas parecen haber funcionado un poco peor.:

Train: 6.72 RMSE

Test: 5.04 RMSE

Modificamos la estructura de nuestra red neuronal, subiendo la cantidad de perceptrones de 4 a 6 y entonces si, la precisión cambia y mejora sustancialmente (aunque el entrenamiento de la red sea un poco mas lento):

Train: 0.58 RMSE

Test: 0.46 RMSE

Y ahora graficamos nuevamente:

(parece una sola línea pero realmente son dos ¡!)

Una vez obtenido el modelo definitivo, debemos aplicarlo sobre la línea de datos de la estación meteorológica 596-Azapa, indicando con un “9” en la columna Q_TG, para dejar señalado que el dato fue obtenido de forma artificial y no a través de los registros reales iniciales.

Resumen

Una vez obtenido el juego de datos fino para ingresar en los modelos predictivos, es bueno plantearse una estrategia, tener alternativas, una idea, pero también es bueno hacer un sondeo entre las diferentes “lineas bases” y ver que resultados preliminares se obtienen, respetando la regla de ir siempre de lo más sencillo a lo más complejo.