Nowcast de Actividad Económica con Machine Learning

Adelantando el resultado del Estimador Mensual de la Actividad Económica (EMAE) usando redes neuronales

WhatsApp Image 2021-08-05 at 10.23.22 AM.jpeg

Resumen

Se realizó un modelo para anticipar el dato del EMAE utilizando 14 indicadores relacionados al ciclo económico que son conocidos con un rezago de 5 días de vencido el mes de referencia, lo que implica una ganancia de tiempo de entre 6 y 7 semanas. El modelo utiliza una Red Neuronal Artificial llamada Perceptrón Multicapa, que tiene la capacidad de aprender por su cuenta patrones y relaciones entre variables. El código de Python está disponible hacia el final de la publicación.

Nowcasting

De la combinación de Now y Forecasting, el nowcasting es una técnica utilizada para estimar en tiempo real el valor de algún indicador que en general es conocido con algún rezago.

Consiste en utilizar variables (inputs) para estimar el indicador objetivo (output). Para esto, es necesario que los input cumplan dos requisitos:

  • Estar relacionados al output.
  • Estar disponibles con un rezago menor al del output.

En economía, por ejemplo, se usa para conocer la evolución de los precios (la tasa de inflación suele ser conocida 15 días después de finalizado el mes), o del PIB (que se publica con frecuencia trimestral y tres meses de rezago).

EMAE

El Estimador Mensual de la Actividad Económica (EMAE) del INDEC refleja la evolución mensual de la actividad económica de los sectores productivos a nivel nacional, de manera conjunta.

A su manera, el EMAE es una forma de nowcasting: es un indicador provisorio y anticipado del PIB. Sin embargo, el EMAE es publicado con un rezago de entre 50 y 60 días de concluído el mes al que hace referencia, es decir, debemos esperar casi dos meses para saber el resultado de un mes determinado. Si bien es de gran utilidad para no tener que esperar al PIB, sigue siendo un rezago importante.

El modelo

Con lo anterior en mente, la idea es acortar el tiempo necesario para contar con información de la actividad económica de un mes determinado.

En este modelo, se toman 14 indicadores de diferentes naturalezas (de sectores específicos, monetarios, financieros, de recaudación y de confianza), todos relacionados con el ciclo económico, y se entrena a una red neuronal artificial para que aprenda a relacionar esas variables con el EMAE.

Estos indicadores son un subconjunto de los utilizados en la publicación de Laura D'Amato, Lorena Garegnani y Emilio Blanco, utilizado por el BCRA para lidiar con la falta de información oficial hacia fines de 2015.

Los datos para todas las variables tienen frecuencia mensual y van desde enero de 2004 hasta junio de 2021.

La lista completa de variables utilizadas (con ajustes estacionales en las que corresponden):

  1. Producción Nacional Automóviles
  2. Exportación de Automóviles
  3. Ventas a Consesionarios
  4. Ventas de Vehículos Nacionales a Consesionarios
  5. Despachos Provisorios de Cemento Portland
  6. Recaudación del Impuesto a las Ganancias
  7. Recaudación del Impuesto a las Ganancias DGI
  8. Recaudación del Impuesto a las Ganancias DGA
  9. Recaudación del IVA
  10. Recaudación del IVA DGI
  11. Merval
  12. M2 privado
  13. Tasa de interés para plazos fijos
  14. Indice de Confianza del Consumidor

tabla.png Despachos de Cemento.png

Ventas de Vehiculos Nacionales Mdo Domestico.png

Tasa de Interes.png

Redes Neuronales: Multi-Layer Perceptron

Un Multi-Layer Perceptron (MLP) es un tipo de red neuronal artificial, que tiene la capacidad de recibir variables input y aprender, por su cuenta, a relacionarlas para dar la mejor estimación posible de una variable output (o varias).

Breve explicación del funcionamiento del MLP

La arquitectura de un MLP se caracteriza porque tiene capas o layers de diferentes niveles (entrada, ocultas y salida), que son conformadas por neuronas. Las neuronas, como su nombre lo indica, son las encargadas de procesar la información recibida. En un MLP, las neuronas de una capa toman la información resultante de la capa anterior y, luego de realizar una transformación, envían esa información a la siguiente, hasta terminar todas las capas y alcanzar un resultado final. El gráfico ayudará a ilustrar el funcionamiento de esta red.

  • Capa de entrada: las neuronas de esta capa se encargan simplemente de recibir las señales o patrones del exterior, en forma de datos sueltos, y propagar dichas señales a todas las neuronas de la siguiente capa.

  • Capas ocultas (una o varias): las neuronas de cada capa oculta toman las señales enviadas por la capa anterior (la primera oculta recibe las señales de la capa de entrada), y realiza un procesamiento no lineal de los patrones recibidos. A su vez, el output de estas neuronas alimentará a las neuronas de la capa siguiente (el output de las neuronas de la última oculta alimentará a la capa de salida).

  • Capa de salida: proporciona al exterior la respuesta de la red para cada uno de los patrones de entrada.

El proceso de aprendizaje del modelo consiste en:

  1. Con un conjunto arbitrario de parámetros para el modelo, estimar un output.
  2. Comparar ese output con el deseado y calcular una métrica del error
  3. Cambiar los parámetros y estimar nuevamente el output.
  4. Volver a comparar el output nuevo con el anterior, y ver la mejora en la estimación (menor error).
  5. Repetir el proceso hasta alcanzar un punto en el que un nuevo cambio de parámetros no reduzca significativamente el error de estimación, o hasta alcanzar una cantidad determinada de intentos, lo que suceda primero.

Estimación del modelo

Una vez recopilados los datos necesarios, se determinan los parámetros técnicos del modelo (función de activación de las capas, cantidad máxima de iteraciones, learning rate, método de resolución, etc.), y se le exige que aprenda a relacionar a los inputs con el output con los datos hasta un mes determinado.

Una vez ejecutado el modelo, se obtiene la estimación de los coeficientes finales que intervienen en la transformación de inputs a output.

Con esos coeficientes, se aplica el modelo a los inputs del mes posterior al último incluido en el entrenamiento, para obtener la estimación del EMAE de ese mes. Este proceso se repite hasta el último mes disponible en la base, siempre extendiendo el train set hasta el último mes disponible anterior al que se busca estimar. Así, se obtiene una serie de estimaciones del EMAE que pueden ser contrastadas con el verdadero valor observado, para calcular un error promedio. Realizando este ejercicio para todos los meses desde 2012, se encuentra que el error absoluto porcentaje promedio (MAPE) es de 1.29%.

index.png

Prueba: estimando el EMAE de mayo 2021

Para probar con un ejemplo la utilidad práctica del modelo, se rehace el ejercicio anterior pero aprovechando toda la información disponible (excepto la del mes a nowcastear) para entrenar el modelo, y pidiéndole que estime el valor de mayo de 2021, último mes disponible a la fecha.

  • Proyectado: 135,0034...
  • Verdadero: 135,3784...
  • Diferencia: -0,28%

Como se puede observar, el resultado de aplicar el modelo hubiese sido muy positivo, con una sub-estimación de menos del 0.3%.

Repitiendo este ejercicio para los últimos 12 meses, se encuentra que el MLP mayormente se desempeña bien, aunque con diferencias significativas en algunos meses puntuales, alcanzando en un mes una sub-estimación del índice del 5%.

Las razones pueden ser diversas, pero probablemente se deba a la existencia de factores que no fueron incluídos en el modelo, que hayan causado una disociación entre el EMAE y nuestros inputs en esos meses particulares. Si esta hipotesis es correcta, una solución podria ser añadir más variables relevantes. Cabe recordar que los indicadores utilizados en este modelo son tomados del estudio previamente citado, y no fueron elegidos para este modelo puntual, por lo que un análisis más intenso de los potenciales input podría mejorar la performance.

Código de Python

Recomiendo ejecutar en Jupyter Notebook y separar cada bloque según los comentarios del código

# Impotar librerías

import pandas as pd
import requests
from requests.auth import HTTPBasicAuth
import csv
import datetime
from datetime import datetime as dt
from matplotlib import pyplot as plt
import seaborn as sns
from sklearn.neural_network import MLPRegressor
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
import pandas_profiling as ppf
from dateutil.relativedelta import relativedelta

# Definir user key para la API
user_key = 'xxxxxxxxxxx'

# Función para obtener el primer día del mes solicitado
def changeday(date):
    year = date.year
    month = date.month
    return dt(year,month,1)

# DESCARGA DE DATOS Y ARMADO DE BASE

# Adefa

adefa = requests.get('https://charts.alphacast.io/api/datasets/5600.csv', auth=HTTPBasicAuth(user_key, ''))
open('adefa.csv', 'wb').write(adefa.content)
adefa1 = pd.read_csv('adefa.csv', delimiter = ',')
adefa1['Year'] = pd.to_datetime(adefa1['Year'])
adefa1.set_index('Year', inplace = True)
adefa1 = adefa1[['Production - Cars - sa', 'Exports - Cars - sa', 'Sales to domestic market - Total', 'Sales to domestic market - National vehicles']]
adefa1.columns = ['Produccion Automoviles Total (sa)', 'Exportacion Automoviles (sa)','Ventas Totales Mdo Domestico (sa)','Ventas de Vehiculos Nacionales Mdo Domestico']

# Portland

portland = requests.get('https://charts.alphacast.io/api/datasets/5537.csv', auth=HTTPBasicAuth(user_key, ''))
open('portland.csv','wb').write(portland.content)
portland1 = pd.read_csv('portland.csv', delimiter = ',')
portland1['Year'] = pd.to_datetime(portland1['Year'])
portland1.set_index('Year', inplace = True)
portland1 = portland1[['Cement Dispatches - Total']]
portland1.columns = ['Despachos de Cemento']

# MECON

mecon = requests.get('https://charts.alphacast.io/api/datasets/5632.csv', auth=HTTPBasicAuth(user_key, ''))
open('mecon.csv', 'wb').write(mecon.content)
mecon1 = pd.read_csv('mecon.csv', delimiter = ',')
mecon1['Year'] = pd.to_datetime(mecon1['Year'])
mecon1.set_index('Year', inplace = True)
mecon1 = mecon1[['GANANCIAS - sa', 'GANANCIAS DGI - sa', 'GANANCIAS DGA - sa', 'IVA - sa', 'IVA DGI - sa' ]]
mecon1.columns = ['Ganancias (sa)','Ganancias DGI (sa)','Ganancias DGA (sa)','IVA (sa)','IVA DGI (sa)' ]
mecon1 = mecon1.loc['2004-01-01':]

# Merval

merval = requests.get('https://charts.alphacast.io/api/datasets/5816.csv', auth=HTTPBasicAuth(user_key, ''))
open('merval.csv', 'wb').write(merval.content)
merval1 = pd.read_csv('merval.csv', delimiter = ',')
merval1['Year'] = pd.to_datetime(merval1['Year'])
merval1.set_index('Year', inplace = True)
merval1 = merval1[['MERVAL']]
merval1 = merval1.loc['2004-01-01':]
merval1.columns = ['Merval']
merval1 = merval1.resample('MS').mean()

# BCRA

bcra = requests.get('https://charts.alphacast.io/api/datasets/6054.csv', auth=HTTPBasicAuth(user_key, ''))
open('bcra.csv', 'wb').write(bcra.content)
bcra1 = pd.read_csv('bcra.csv', delimiter = ',')
bcra1['Year'] = pd.to_datetime(bcra1['Year'])
bcra1 = bcra1[['Year','Tasas de interés, promedio mensual en porcentaje nominal anual - Por depósitosa plazo fijo de 30 a 59 días de plazo - De moneda nacional']]
bcra1.columns = ['Year','Tasa de Interes']
bcra1['Year'] = bcra1['Year'].apply(lambda x: changeday(x))
bcra1.set_index('Year', inplace = True)
bcra1 = bcra1.loc["2004-01-01":]

bcra_arg = requests.get('https://charts.alphacast.io/api/datasets/5277.csv', auth=HTTPBasicAuth(user_key, ''))
open('bcra_arg.csv', 'wb').write(bcra_arg.content)
bcra_arg1 = pd.read_csv('bcra_arg.csv', delimiter = ',')
bcra_arg1['Year'] = pd.to_datetime(bcra_arg1['Year'])
bcra_arg1.set_index('Year', inplace = True)
bcra_arg1 = bcra_arg1[['Private M2 - sa']]
bcra_arg1.columns = ['Private M2 (sa)']
bcra_arg1 = bcra_arg1.loc['2004-01-01':]

# UTDT

utdt = requests.get('https://charts.alphacast.io/api/datasets/5596.csv', auth=HTTPBasicAuth(user_key, ''))
open('utdt.csv','wb').write(utdt.content)
utdt1 = pd.read_csv('utdt.csv', delimiter = ',')
utdt1['Year'] = pd.to_datetime(utdt1['Year'])
utdt1.set_index('Year', inplace = True)
utdt1 = utdt1[['Indice de Confianza del Consumidor (ICC) - Nacional']]
utdt1.columns = ['Indice de Confianza del Consumidor']
utdt1 = utdt1.loc['2004-01-01':]

# EMAE

emae = requests.get('https://charts.alphacast.io/api/datasets/5331.csv', auth=HTTPBasicAuth(user_key, ''))
open('emae.csv','wb').write(emae.content)
emae1 = pd.read_csv('emae.csv',delimiter = ',')
emae1['Year'] = pd.to_datetime(emae1['Year'])
emae1.set_index('Year', inplace = True)
emae1 = emae1[['Emae','Emae - current_prices_mom','Emae - current_prices_yoy','Emae - sa_orig','Emae - sa_orig - current_prices_mom','Emae - sa_orig - current_prices_yoy']]
emae1.columns = ['EMAE', 'EMAE MoM','EMAE YoY','EMAE (sa)','EMAE (sa) MoM','EMAE (sa) YoY']
emae1 = emae1.loc['2004-01-01':]

# Armado de tabla final

tabla_final = pd.concat([emae1[['EMAE (sa)']], adefa1,portland1,mecon1,bcra_arg1,utdt1,merval1,bcra1], axis = 1)

# Función para graficar emae vs. variable solicitada

sns.set_theme(style='darkgrid')
def graficar_corr(variable):
    fig = sns.scatterplot(x=tabla_final.transpose().loc[variable,:],y=tabla_final.transpose().loc['EMAE (sa)'])
    plt.title('EMAE (sa) vs %s'%variable)
    plt.xlabel(variable)
    plt.ylabel('EMAE (sa)')
    plt.savefig('%s.png'%variable)
    return fig

# Aplicación de esa función para diferentes variables

graficar_corr('Despachos de Cemento')

graficar_corr('Ventas Totales Mdo Domestico (sa)')

graficar_corr('Ventas de Vehiculos Nacionales Mdo Domestico')

graficar_corr('Tasa de Interes')

# Función que ejecuta el modelo para un mes determinado, utilizando solo la información que estaba disponible hasta
# ese momento

def estimar(fecha,tabla_final=tabla_final):
    scaler = StandardScaler()
    X = tabla_final.loc[:, tabla_final.columns != 'EMAE (sa)'].loc[:fecha]
    X = scaler.fit_transform(X)
    y = tabla_final[['EMAE (sa)']].loc[:fecha].values.ravel()
    X_train_posta = X[0:len(X)-1]
    X_target = X[len(X)-1]
    y_train_posta = y[0:len(X)-1]
    y_target = y[len(X)-1]
    regr_posta = MLPRegressor(random_state=1, activation='tanh', max_iter=5000, learning_rate='adaptive', solver='sgd', momentum=0.01).fit(X_train_posta, y_train_posta)
    y_pred_posta = regr_posta.predict(X_target.reshape(1,-1))
    dif = ((y_pred_posta/y_target)-1)*100
    return y_pred_posta, y_target, dif


# Ejecución del modelo para ver mayo 2021
estimar(fecha='2021-05-01')

# Ejecución de la función anterior para todos los meses desde 2012

m = 6 ## lo seteo en junio
meses=[]
for i in range(1,114):
    meses.append(dt(2021,m,1)+relativedelta(months=-i))
meses.sort()

posta_l=[]
pred_l=[]
dif_l=[]
for mes in meses:
    pred,posta,dif = estimar(mes)
    posta_l.append(posta)
    pred_l.append(pred[0])
    dif_l.append(dif[0])


estimar_df = pd.DataFrame(list(zip(posta_l,pred_l,dif_l)),index=meses,columns=['Actual','Pred','Diff (%)'])
plt.plot(estimar_df[['Actual']],label='Actual')
plt.plot(estimar_df[['Pred']],label='Pred')
plt.legend(loc="upper left")
#plt.savefig('12 meses.png')
estimar_df


Mean Absolute Percentage Error: 1.29%
ZayatAlex

Written by

ZayatAlex

Published in

My Public Repo

You can use you first public repository to share content with the community

Related insights

  • Read more...

    La economía de las elecciones

    ¿Cómo llega la economía "de bolsillo" a las elecciones legislativas?

    Se muestra la evolución de algunos indicadores económicos cercanos a las personas (inflación, dólar, consumo, empleo, salarios, confianza), para ilustrar el estado de la economía de cara a las cercanas elecciones legislativas (PASO en septiembre, generales en noviembre).

    Inflación

    *Se toman datos