top of page

COSAS VEREDES

  • fjroar
  • 23 mar
  • 6 Min. de lectura

Cuando he visto ejemplos de LSTM aplicados a series temporales como los que se observan, por ejemplo aquí:



 

Se queda uno/a con la desazón de si serán o no una buena herramienta para el análisis de series temporales ya que o el ejemplo es muy pobre para tal fin, o de algún modo no se consiguen unos resultados que uno pueda decir ¡Wow! ¡Qué maravilla frente a otros modelos! o al menos generar algo con cierta calidad.


Para no hacer muy extenso esta entrada, recomiendo que quién no tenga ni idea de lo que es un modelo Long Short-Term Memory se mire al menos por encima, el siguiente blog:



Básicamente hago un resumen de la idea que se busca cuando se trata de predecir series temporales:


  • Un LSTM es un tipo de red neuronal recurrente en la que se requiere cierta persistencia cuando se quiere realizar predicciones, por tanto se desea un tipo de red neuronal que realice bucles tal y como muestra el siguiente esquema extraída del citado blog:


ree
  • La recurrencia anterior se consigue en la práctica con una estructura en “puertas” donde se decide:

 

  • Qué información olvidar (donde se usa una función sigmoida)

  • Qué nueva información se agrega a la memoria (donde se usa una función sigmoida y una tangente hiperbólia)

  • Qué parte de la memoria se usa para generar la salida (donde se una función sigmoida y una tangente hiperbólica)

 

  • Todo lo anterior se vincula de este modo, donde en el blog referenciado se explica bastante bien:

ree

Pues bien, analizando con mis alumnos un ejemplo sobre prever visitas a Cádiz con datos públicos descargados del INE, decidimos ir esta vez con “pólvora del rey” y aplicar un modelo como estos para afianzar conceptos clave sobre qué puede hacer un modelo de Inteligencia Artificial actual con múltiples aplicaciones como el reconocimiento de voz (y otros) además del tema en concreto que aquí nos ocupa, el de series temporales donde como he indicado al principio, no he visto ejemplos muy relevantes que me inciten a su uso intensivo y es una teoría a la que le tengo mucho cariño ya que fue con la que me introduje en el mundo de la estadística hace unos 25 años ya (que se dice pronto ...)


Dicho lo cual, nos proponemos analizar la siguiente serie temporal cuyos datos y código dejo en el siguiente github: https://github.com/FJROAR/LTSMEXAMPLE siendo la serie de datos el número de visitantes a la provincia de Cadiz que tiene la siguiente forma:


ree

Se observa una típica serie con períodos anuales, donde se nota la caída con el período COVID del año 2020, la recuperación del 2021 y la vuelta a la normalidad a partir del 2022 finalizando el último dato disponible hasta prácticamente Febrero de este año 2025.


Además, es una serie curiosa porque se observa, sobre todo en los períodos más antiguos el pico de los carnavales, la caída tras estos y después el Verano que es cuando hay más afluencia, además se ve un comportamiento de creciente en variabilidad y claramente una fuerte estacionalidad.


En este caso el ejercicio a realizar fue muy sencillo. Se va a entrenar con el 90% de la información (básicamente hasta el año 2022) y se va a ver qué predice el LSTM a partir de ese momento. Gran parte del código lo generamos con Chat GPT que a día de hoy es un gran aliado en las clases donde se quiere hacer algo importante. Previamente creamos una variable de intervención para el año 2020 y otra para el 2021 para recoger mejor los “efectos COVID” que alteran la serie.


Pues bien, se montó un LSTM con 12 pasos siendo el núcleo "definitorio" del modelo la siguiente parte del código python que está en el git anteriormente mencionado:

ree

Donde tras su ajuste, se obtiene el siguiente resultado:


ree

Con un error absoluto medio relativo igual al 0.0830 que es bastante aceptable, sobre todo se tiene en cuenta que no se ha metido la variable calendario tipo “carnavales” que estoy seguro que mejoraría y reproduciría más fielmente esos picos de desfase que varían y que como dependen de la Semana Santa, por tanto hay que meter “algo lunar” para mejorar la predicción.


Pues bien, podemos generar el siguiente año dando como resultado:


ree

Donde se observa que parece que va hacia un nivel más o menos constante de visitas, siendo mejorable la predicción si se mete el mencionado efecto carnaval que por el momento no voy a utilizar.


Y ahora la pregunta es ¿Qué pasa si comparo este resultado con el que me daría un modelo econométrico ARIMA? A ver, he tomado un modelo básicamente por defecto tipo LSTM y no le he metido mucha “más historia”, por tanto la comparación la voy a llevar a cabo con un segundo código donde voy a considerar el autoarima que ofrece Python sin meterme a trabajar la serie vía metodología de Box-Jenkins que sería lo correcto, pero entonces no iría a una solución que me ocupase tiempo y análogamente, si hago un grid-search de LSTM, seguro que incluso mejoro lo anteriormente obtenido, por tanto, las reglas del juego van a ser en que vamos a utilizar el auto-arima partiendo de la serie básica por defecto a ver qué sale y el resultado, siguiendo pasos análogos y tras seleccionar como mejor modelo arima el siguiente:


ree

Fueron los siguientes (que se analizan en el test):


ree

Donde el error absoluto medio relativo está en torno a 15.69 que resulta demasiado alto, siendo la predicción final la que refleja el siguiente gráfico a 12 meses:


ree

Donde hay una clara diferencia en el mes de Febrero de 2026 que parece que la serie se va, pero entonces ¿Por qué el modelo ARIMA es tan malo? Pues bien, es que ha tomado la serie y no se ha considerado las variables de intervención para separar el efecto pandemia y recuperación, que sí se hizo en el ejemplo anterior. Así pues que se va a dar un paso adicional y tras la selección de ese primer modelo ARIMA, vamos a utilizarlo pero esta vez pero con esas variables explicativas adicionales observándose que entonces se genera el siguiente resultado bastante mejor que el anterior:


ree

Un ajuste bastante mejor con un error absoluto medio ahora ya en torno al 0.1001 que se acerca bastante al anteriormente obtenido generándose una predicción bastante razonable tal como sigue:


ree

Que es bastante más razonable y en línea con lo dado por el LSTM, por tanto en resumen tenemos que las predicciones de viajeros de Marzo de 2025 hasta Febrero de 2026 por los modelos considerados serán:


ree

Para no extender más este trabajo, ya que se podría discutir sobre comparar con modelos ML y con el Prophet (lo que da para otro post), voy a finalizar con unas conclusiones y consejos cuando se trabaja con series temporales:

 

  1. En general es recomendable usar medidas tipo error absoluto medio relativo con algunas variantes adicionales, entendiendo que cuando se está por debajo de un 0.1 se tiene, por lo general, un buen modelo


  2. En esta serie el LSTM ha ido bien, al igual que el ARIMA con variables exógenas porque la serie tiene claras componentes pero, en series más complejas, tendremos problemas si no se cuenta con buenas variables exógenas y en series financieras el problema suele ser muy complejo, sino sería millonario y por desgracia, no es el caso


  3. Siempre hay que ver las predicciones, tanto el LSTM como el ARIMA con exógenas, parecen ofrecer resultados bastantes consistentes, que varían del modelo ARIMA simple donde el impacto de la Pandemia y de la Recuperación del 2021 al no tenerse controlado, distorsionan la predicción final


  4. Al igual que con tuning creo que el LSTM mejoraría bastante más su error absoluto medio, no hay que ignorar la potencia de la metodología clásica Box - Jenkins, ya que en la serie, no se han realizado transformaciones de box-cox ni un análisis serio para considerar el tema de autocorrelaciones, estacionariedad que seguramente también mejoraría el resultado


  5. No olvidar que mientras un LTSM es un modelo caja negra, el ARIMA tiene una ecuación y parámetros de tipo lineal que se puede escribir y dar lugar una ligera interpretabilidad, lo cual resulta muy positivo


  6. Si aceptamos el LTSM, este año habrá unos 2.930.431 viajeros aproximadamente que visitarán Cádiz, espero que se lo pasen genial

 
 
 

Una de las últimas clases que tuve, tras impartir la clase de Modelos de Ensemble en el Master de Data Science y analítica avanzada de la UIC https://www.uic.es/es/estudis-uic/ade/master-en-data-science-y-analitica-avanzada fue una apuesta arriesgada porque prácticamente la improvisé toda y la dimos entre los alumnos que asistieron y yo que hice lo que me dijeron.


Básicamente ese día llegué con un dataset de Kaggle que era el siguiente: https://www.kaggle.com/datasets/hopesb/student-depression-dataset?resource=download y que tenía las siguientes características que me interesaban para considerarlo como instructivo:

 

  • Tiene un tamaño considerable de algo más de 27.000 registros en total

  • Los nombres de las variables resultan autoexplicativas y están además explicadas en el enlace aquí dado

  • Las anteriores variables, aunque bastante limpias, tenían algunos problemillas que comentaremos

  • Existe una variable target denominada Depression ya montada

 

Pues bien, como describiré a continuación llegamos a sacar cosas como estas:


ree

Así pues, tras unas sesiones de teoría, hicimos algo que generalmente no suele dar tiempo en hacerse en una mañana de clase que fue lo que tuvimos y es que al final nos propusimos como objetivo, tratar de asociar distintos modelos de analítica avanzada (que la gente en general denomina de Machine Learning) y hacer una discusión entre los principales modelos que habíamos estudiado en la teoría y que queríamos aplicar.

Nadie, ni tan siquiera yo había estudiado el dataset previamente y la verdad es que salió todo bastante redondo tal y como voy a describir a continuación.

En definitiva, con el nombre del dataset y tras horas de machaque teórico, los veía un poco alicaídos y este conjunto sobre “alumnos deprimidos”, fue un tanto jocoso porque permitía una cierta identificación que lo que pretendía era realmente animarlos un poco así pues lo que nos propusimos fue usar a mansalva Chat GPT y ver si llegábamos a hacer una discusión de modelos adecuada.

Tanto el código que comentaré a continuación como el dataset y la estructura que cualquiera puede llevar a su máquina si lo quiere ejecutar estaría aquí https://github.com/FJROAR/AnalisisDatasetDepression y prácticamente el 95% de éste código lo hicimos en clase y yo añadí un poquito más de vuelta en el tren para que quedase presentable por si alguien lo quiere utilizar para lo que desee.

Pues bien, la clase se desarrolló tal como sigue:

 

  1. Lo primero era elegir en qué lenguaje lo hacíamos, mis alumnos eligieron Python y aunque a mí me gusta más R, pues nada, había que hacerlo en Python y trabajamos por tanto en Spyder. En todo caso, nos íbamos a ayudar de ChatGPT, porque aunque ellos tenían alguna idea de programación en Python, teníamos un tiempo muy limitado y no podíamos pararnos a pensar mucho el código


  2. Lo único que les indiqué era que hiciésemos una carpeta que se llame code donde estaría el código y otra data donde estarían los datos que Kaggle permitían descargarlos en formato .csv


  3. Cuando se trabaja por primera vez con datos es increíble que hasta lo más tonto, se puede convertir en un mundo y claro, había que leer los datos. Pues nada, pregunta al canto y rápido se obtiene una solución totalmente sencilla y correcta, trabajada además con rutas relativas como debe ser:

    ree
  4. Tras esto echamos una inspección visual y aunque es cierto que en un proyecto en real hay que llegar a construir este dataset a partir de unir distintas tablas, ese trabajo lo teníamos resuelto, pero tras abrir el dataset nos encontramos esto:


    1. Había algunas variables como City que al estar en formato carácter no van a poder usarse en Python, tampoco la variable Gender ni otras Have you ever had suicidal thoughts ?


    2. Otras variables como Profession parecían que presentaban un único valor, pero no era así, no siempre vale Student y había que tomar decisiones de que se hacía con los no tomaba ese valor y con la variable en sí


    3. Por otro lado en concreto con la citada variable City vimos que había unas 52 categorías y por tanto ¿Qué hacíamos con esta variable? ¿Hacíamos Dummy u optamos por algo tipo LabelEncoding?


      Todas estas y otras decisiones fueron tomadas conforme la marcha y generando un código gracias a las distintas preguntas que los estudiantes le iban haciendo a Chat GPT que generaba parte de un código que después adaptábamos a nuestras necesidades. Un pequeño fragmento de lo que se hizo es lo que se muestra a continuación:


      ree

      Tomar por tanto la decisión, ver que funcionaba, adaptar … Nos llevó bastante tiempo y vimos parte del marrón que en la vida real toca sobre preparación de la información antes de poder tocar los modelos


  5. Del paso anterior decidimos prepara y “numerizar” todas las variables tipo carácter salvo 2 de ellas que eran las variable Gender y Degree. Estas 2 variable le íbamos a dar un tratamiento alternativo tipo label encoding donde en conjunto training contaríamos por cada categoría, cuántas veces aparece en el dataset y asignaríamos una proporción. Por tanto, con un dataset tal como este:

    ree

    Llegamos al punto de hacer los respectivos conjuntos training y test con un código que nos proporción ChatGPT y que debidamente adaptamos a nuestra necesidades donde quitamos la variable id que no nos sirve para nada y donde separamos la target de las variables explicativas haciendo lo siguiente:

    ree
  6. Tras lo anterior, se estaba en disposición de transformar en numéricas las 2 variables comentadas en (4) en el training para aplicar esa transformación en test, para esto preguntamos de nuevo ChatGPT y nos proporcionó bastante ayuda al respecto, permitiendo dicha transformación tal y como se observa en una de ellas a continuación:

    ree

  7. Aunque no llegamos a hacerlo, antes de llegar a la fase de modelización es siempre conveniente realizar una pre-selección de variables previa o al menos eliminar las que son muy parecidas entre sí, mediante un análisis de correlaciones, no lo hicimos y decidimos ir a ver si iba a salir algo predictivo o no con todo lo que se tenía, así que lo único que se hizo fue una mera imputación de valores missing que había unos pocos y fuimos por fin a la FASE DE MODELIZACIÓN.

    ree

  8. Es pues este paso el más excitante de lo que hicimos porque queríamos asociar modelos y teníamos muchas posibilidades ¿Qué hacer? ¿Cogemos una tipología de modelos y aplicamos un grid search? ¿Hacemos un repaso de todos los modelos que conocemos? ¿Combinamos lo anterior? … Optamos por la segunda opción y elegimos ver distintas opciones de lo que habíamos visto hasta el momento tal y como sigue a continuación:

    ree

  9. Para analizar todo esto, necesitábamos montar un bucle, que permitiese aplicar opción por opción a test y decidimos en cada caso medir mediante el índice de Gini y generar un dataset para tener una discusión adecuada, el corazón y la parte más importante del código sería por tanto la siguiente:

ree

Llegados a este punto debo admitir que me sorprendió ChatGPT, estaba ayudando a unos estudiantes a sacar un código con cierto sentido de modo ordenado que iba a generar el listado de modelos que he puesto como Figura Principal al principio de este escrito.


Y hasta aquí lo principal de la parte del código el resto fue sacar conclusiones y ver para qué servía esto de los modelos realmente y se entabló un debate interesante donde resalto algunas de las ideas:


  • No siempre el modelo más complicado (o más famoso como el xgboost) resulta ser el mejor, aquí ganó la regresión ridge

 

  • Analizamos en los modelos tipo xgboost el típico gráfico de importancia de las variables que podía ser comparado con los coeficientes que salían de la regresión Ridge:


ree

¿Cuál aporta más información? ¿Qué indica cada uno? ¿Se pueden usar de modo conjunto? ¿Tiene sentido lo que dicen? ¿Cómo podría elaborar políticas entre mis estudiantes con estos resultados? Aquí está la verdadera utilidad de los modelos aparte de por supuesto el poder predictivo con unos Ginis tan sumamente buenos


  • Y como al principio salió el XGBoost como mejor modelo bajamos al mundo de la interpretabilidad de modelos de analítica avanzada de la mano de los Shap values y generamos gráficos como el que está en la figura principal (aquí se genera para otro estudiante distintos):

 

ree

¿Son los estudiantes distintos en su propensión a tener o no depresión? ¿Cómo influyen localmente las variables que inciden en la problemática bajo estudio? ¿Qué diferencia y/o relación hay con la interpretación que nos da una regresión y la de un xgboost? …


Finalmente, aunque es claro que en un proyecto en real hay que hacer muchas más cosas, esto fue lo que nos dio parte de una mañana de práctica, discusión y uso de los conceptos que nos conviene tener claros, por supuesto todo esto está a mejorar ¿Cómo? Pues eliminando variables redundantes, igualmente eliminando variables poco importantes que no aportan nada a los distintos modelos, aplicando Grid Search de hiperparámetros para cada una de las familias de los modelos presentados y seguro que mejorarían tanto los random forest como el xgboost, controlar el overfitting (en el caso del decision tree fundamental) que se nos iba de las manos al no estar controlada la profundidad, variables ... Pero eso lo dejamos para otra ocasión.


En definitiva, creo que avanzamos bastante y plantear un escenario así hace unos años y llegar a sacar algunas conclusiones como a las que llegamos, era cuestión, o de dedicarle algunas jornadas y llevarlo todo muy preparado (sin empezar de cero), o de limitarlo todo a analizar un único modelo y punto, quedé muy contento tanto con lo alumnos como con el modo de trabajo y lo que hicimos en esa clase.

 
 
 

Continuando la parte del anterior post véase:



Se había conseguido con los programas de R proporcionados generar 2 vectores con distribuciones pseudo-aleatorias a lo largo de sus componentes de los números 1, 2 y 3.


En este sentido se había observado que mientras la distribución dada por R permitía dibujar el fractal conocido como triángulo de Sierpinski, sin embargo, se observó que las distribuciones de los vectores que finalmente generan las figuras, el basado en el algoritmo Mersenne – Twister que usa R por defecto y el basado en la sucesión de Fibonacci visualmente mostraban vectores con los números 1, 2 y 3 aparentemente bien distribuidos.


Por tanto, la pregunta es ¿Pueden los test estadísticos decidir con un número la presencia de aleatoriedad o no? Si se observa, por ejemplo, la distribución de los vectores generados, se obtienen los siguientes diagramas de barras:


ree

Salvo un “pelín” de acumulación en el 2 cuando se trata de los números pseudo-aleatorios tipo Fibonacci básicamenonte la distribución es análoga.


No obstante, para contrastar realmente la aleatoriedad debe aplicarse algún test de rachas, que en R se podría hacer (de modo no paramétrico) mediante el uso de la función runs.test() de la librería tseries. Para aplicar este test de rachas se escogen los datos de los vectores que generan los anteriores gráficos y se aplica el modulo 2 a sendos vectores ya que esta función analiza rachas en variables binarias, por lo que si se hace tal transformación se alcanzan los siguientes resultados:


ree

Donde básicamente se obtiene aleatoriedad en ambas secuencias de números al ser el p-valor muy elevado y no poderse rechazar la hipótesis de no aleatoriedad.


Otra comprobación adicional que se podría hacer es una basada en correlaciones mediante el establecimiento de un modelo de regresión lineal, en este sentido cabe generar una variable que se puede denominar t y que va desde 1 hasta 100000 (dado este caso) y que serviría para ordenar las observaciones. Así pues, si se ponen los datos obtenidos (números del 1 al 3) que genera el triángulo de Sierpinski y el otro en función de la variable t debería pasar que el la pendiente del modelo debería ser en todo caso nula y con mínima o nula significatividad, mientras que la constante debería tomar un valor próximo a 2 como de hecho ocurre:

ree

Lo anterior nos muestra, que hay que tener mucho cuidado con los test estadísticos porque claramente no nos están dando una información suficientemente precisa y hay que investigar siempre más.


También cabe indicar que a la luz de los anteriores test son lo mismo las 2 sucesiones (incluso en esta última prueba la distribución tipo Fibonacci podría decirse que es incluso más aleatoria), pero gráficamente hemos visto que no tienen nada que ver por el modo de escoger los 3 vértices para generar los puntos del triángulo de sierpinski, por tanto, y para concluir, ojito que no todo lo que hay que saber de estadística (o sobre data scientist) está en un único libro (ni mucho menos en Chat GPT) y cosas aparentemente inconexas pueden estar más conectadas de lo que creemos.


PD Intenté usar Chat GPT para esto, pero si en algo me ayudó, se confunde un montón con el tema de los test y los resultados dando respuestas falsas que continuamente corrige y al final te hace ir a las fuentes y a libros fiables.

 
 
 

© 2021 by Francisco J. Rodríguez Aragón. Proudly created with Wix.com

bottom of page