library(tidyverse)
library(DBI)
library(reshape)
library(dplyr)
library(ggplot2)
library(RSQLite)
library(caTools)
library(ROCR)
library(rstatix)
library(scales)
library(patchwork)
library(psych)
library(readxl)
library(fpp2)
options(scipen=999)
Se cuenta con un esquema relacional conformado por 4 bases de datos: estados_financieros, cartera, ciiu_cliente, ciiu_sector. Se utiliza SQLite para la lectura de los datos.
= dbConnect(SQLite(),dbname="C:/Users/carac/OneDrive/Escritorio/prueba iris/datosPrueba (1).db") datos
Para esta primera parte se selecciona el registro más reciente del cliente en los estados financieros y se guarda en un dataframe:
select s1.C43ID, s1.fecha as last_date, s2.C43TAC, s2.C43ING, s2.C43EGR
from
select max(C43FIN) as fecha, C43ID from estados_financieros group by C43ID ) as s1
( inner join
select C43TAC, C43FIN, C43ING,C43EGR,C43ID from estados_financieros ) as s2
( on s1.fecha = s2.C43FIN and s1.C43ID = s2.C43ID
ORDER BY s1.fecha ASC
Se guardan las tablas cartera, ciiu_cliente y ciiu_sector como dataframe:
select*
from cartera
select*
from ciiu_cliente
select*
from ciiu_sector
Seguidamente se consolida la información en un solo dataframe, para esto se hace uso de los respectivos join:
#Renombrar llaves
= rename(cartera, c(M01ID="C43ID"))
cartera = rename(ciiu_cliente,c(C40ID="C43ID"))
ciiu_cliente= rename(ciiu_cliente,c(C40LNE="CIIU"))
ciiu_cliente
# Left Join para consolidar un solo data frame
=merge(x = last_estado_fin, y = cartera, by ="C43ID",all.x = TRUE)
df1=merge(x = df1, y = ciiu_cliente, by ="C43ID",all.x = TRUE)
df2= merge(x = df2, y = ciiu_sector, by ="CIIU",all.x = TRUE)
df df
La base de datos cuenta con 12 variables y 632 clientes. Finalmente se procede a depurar la base de datos, para este caso se cambia el tipo de fecha de estado financiero a un cliente en específico, también se renombran las variables del dataset y finalmente se tiene una pequeña vista descriptiva de los datos:
#Corregir fecha para cliente en especifico
=df[order(df$last_date),]
dfrow.names(df) <- 1:nrow(df)
632,3]=20211231
df[=df[order(df$last_date),]
dfrow.names(df) <- 1:nrow(df)
#Renombrar variables
names(df)=c("cod_CIIU","ID_cliente","fecha_estado_fin","total_activos","ingresos","egresos","calificacion_cliente","saldo_actual","dias_mora","fecha_ultima_act","desc_CIIU","sector_economico")
attach(df)
$sector_economico= as.factor(df$sector_economico)
df$calificacion_cliente= as.factor(df$calificacion_cliente)
df#Descriptivos generales de la base de datos
summary(df)
## cod_CIIU ID_cliente fecha_estado_fin total_activos
## Min. : 10 Min. : 106726333 Min. :20060925 Min. : 0
## 1st Qu.: 10 1st Qu.:2711851412 1st Qu.:20210622 1st Qu.: 0
## Median : 10 Median :5070451866 Median :20211112 Median : 0
## Mean :1673 Mean :5039769496 Mean :20212336 Mean : 103391189344
## 3rd Qu.:4290 3rd Qu.:7320618857 3rd Qu.:20220630 3rd Qu.: 6084899612
## Max. :9491 Max. :9974121077 Max. :20230224 Max. :9145828319000
##
## ingresos egresos calificacion_cliente
## Min. : 0 Min. : 0 BUENA:370
## 1st Qu.: 1642160 1st Qu.: 0 MALA :262
## Median : 2662295 Median : 62770
## Mean : 72460852579 Mean : 23137710642
## 3rd Qu.: 2340226223 3rd Qu.: 640236914
## Max. :9946526999000 Max. :3972812795000
##
## saldo_actual dias_mora fecha_ultima_act desc_CIIU
## Min. : 1 Min. : 0.0 Min. :20060925 Length:632
## 1st Qu.: 2130397 1st Qu.: 0.0 1st Qu.:20210607 Class :character
## Median : 12728659 Median : 0.0 Median :20211024 Mode :character
## Mean : 399343624 Mean : 101.0 Mean :20212958
## 3rd Qu.: 271296617 3rd Qu.: 146.8 3rd Qu.:20220826
## Max. :8639238120 Max. :1529.0 Max. :20230306
##
## sector_economico
## ASALARIADO:397
## COMERCIO : 67
## CONSTRUCCI: 36
## MANUFACTUR: 36
## SERVICIOS : 24
## FINANCIERO: 23
## (Other) : 49
#Agrupación del saldo por sector
<-
grupo_sector%>%
df group_by(sector_economico) %>%
::summarize(n= n()) %>%
dplyrmutate(proporcion=n/sum(n),porcentaje=proporcion*100)
#Grafico de barras para la distribución del saldo por sector
ggplot(data=grupo_sector, aes(x=reorder(sector_economico,-porcentaje), y=porcentaje)) +
geom_bar(stat="identity", position="dodge",colour="red", fill="skyblue")+ theme(axis.text = element_text(size=3.7))+guides(fill = guide_legend(title = "Sector Economico"))+ ggtitle('Distribucion del Saldo por Sector Economico') + labs(x='Sector Economico', y='Porcentaje')
De acuerdo a la tabla de frecuencias y al gráfico de barras, podemos observar que la concentración del saldo se encuentra distribuido mayormente en los sectores Asalariado, Comercio, Construcción y Manufactura los cuales suman aproximadamente el 85% del saldo total.
Para presentar un mejor análisis gráfico del problema, se procede realizarle el logaritmo a la variable saldo.
#Grafico de violin para observar la variabilidad y distribucion del saldo en cada sector
ggplot(df, aes(x = sector_economico, y = log(saldo_actual), fill=sector_economico)) +geom_violin(trim = FALSE) +geom_boxplot(width = 0.07)+ theme(axis.text = element_text(size=3.7))+guides(fill = guide_legend(title = "Sector Economico"))+ ggtitle('Variabilidad del Saldo Por Sector Economico')
Del gráfico podemos observar conjuntamente la distribución de los
datos tanto en densidad como en variabilidad. Se puede destacar que los
sectores educación e industrial presentan una variabilidad muy baja, es
decir que los clientes ubicados en estos sectores tienden a tener un
saldo en común. Por otro lado, el sector manufactura, servicios y
transporte son los que representan mayor variabilidad en los
saldos.
#Agrupacion de los días mora por cada sector
<-
grupo_mora%>%
df group_by(sector_economico) %>%
::summarize(n= sum(dias_mora)) %>%
dplyrmutate(proporcion=n/sum(n),porcentaje=proporcion*100)
#Diagrama de barras para representar la distribución de los días mora por sector
ggplot(data=grupo_mora, aes(x=reorder(sector_economico,-porcentaje), y=porcentaje)) +geom_bar(stat="identity", position="dodge",colour="red", fill="skyblue")+ theme(axis.text = element_text(size=3.7))+guides(fill = guide_legend(title = "Sector Economico"))+ ggtitle('Distribucion de los dias mora por Sector Economico') + labs(x='Sector Economico', y='Porcentaje')
De acuerdo con el gráfico de barras, podemos observar que los días
mora se encuentran distribuidos principalmente en el sector de
asalariado y comercio, siendo este el 83% de los días moras total.
#Agrupacion de los dias mora por calificacion
<-
grupo_calif%>%
df group_by(calificacion_cliente) %>%
::summarize(n= sum(dias_mora)) %>%
dplyrmutate(proporcion=n/sum(n),porcentaje=proporcion*100)
#Diagrama de sectores para ver la distribucion de los dias mora por calificacion
ggplot(grupo_calif,aes(x=2,y=porcentaje, fill=calificacion_cliente))+
geom_bar(stat = "identity",
color="white")+
geom_text(aes(label=percent(porcentaje/100)),
position=position_stack(vjust=0.5),color="white",size=6)+
coord_polar(theta = "y")+
scale_fill_manual(values=c("skyblue","salmon"))+
theme_void()+
labs(title="Distribucion de los dias mora por Calificacion")+
xlim(0.5,2.5)
Se puede observar que notoriamente los clientes mal calificados son
los que representan casi el 100% de la distribución de los días
mora.
Se realiza un análisis exploratorio para las variables numéricas del estudio, esto con el fin de encontrar posibles relaciones con la variable objetivo.
#Graficos de puntos para las variables numericas
<-ggplot(df,aes(x = calificacion_cliente)) +geom_bar()+ theme(axis.text = element_text(size=3.7))+guides(fill = guide_legend(title = "Calificacion"))+ ggtitle('Distribucion de la variable objetivo') + labs(x='Calificacion', y='Conteo')
p1
<-ggplot(df, aes(x = log(ingresos), y = log(saldo_actual), fill=calificacion_cliente)) + geom_point(aes(colour = calificacion_cliente))+ ggtitle('ingresos vs saldo actual por Calificacion')
p2
<-ggplot(df, aes(x = log(ingresos), y = log(egresos), fill=calificacion_cliente)) + geom_point(aes(colour = calificacion_cliente))+ ggtitle('ingresos vs egresos por calificacion')
p3
<-ggplot(df, aes(x = log(ingresos), y = log(dias_mora), fill=calificacion_cliente)) + geom_point(aes(colour = calificacion_cliente))+ ggtitle('ingresos vs total activos vs calificacion')
p4
#Unir los graficos en una sola ventana
+ p2 + p3 + p4 +
p1 plot_layout(ncol = 2)
De acuerdo a los gráficos podemos observar primeramente que la variable objetivo no presenta un desbalance, por tanto, no es necesario aplicar ninguna técnica de balanceo. Por otro lado, se puede observar que la calificación es una variable que discrimina de buena manera las variables cuantitativas del estudio. Finalmente se realiza el análisis de correlaciones:
#Matriz de correlacion de pearson para las variables numericas
= select(df,total_activos,ingresos,egresos,saldo_actual,dias_mora)
df_numcorPlot(df_num,main="Matriz de Correlacion")
Se puede observar que la variable ingresos esta notoriamente
correlacionada con total activos y egresos, lo cual puede ser un
problema para el modelo ya que puede sobre estimar algún tipo de
relación.
No se tendrá en cuenta las variables categóricas para la modelación. Cabe recalcar que la variable sector económico tiene un gran impacto para la discriminación de la calificación, pero no es óptimo tener una variable explicativa con 13 categorías, ya que puede generar complicaciones en la división de la base de datos, por lo que alguna de sus clases pueda no estar representada en la base training o test. Además, no se incluye la variable ingresos debido a su alta correlación con otras variables del dataset.
Posteriormente se realizar el proceso de estandarización para las variables numéricas, esto con el fin de que el modelo no sufra algún problema de sobreestimación a ciertas variables.
#Seleccion de las variables a modelar
=select(df, -cod_CIIU, -ID_cliente,-fecha_estado_fin,-fecha_ultima_act,-desc_CIIU,-sector_economico,-ingresos)
df_mod
#Estandarizacion de las variables numericas
$total_activos= scale(df_mod$total_activos, scale = TRUE)
df_mod$egresos= scale(df_mod$egresos, scale = TRUE)
df_mod$saldo_actual= scale(df_mod$saldo_actual, scale = TRUE)
df_mod$dias_mora= scale(df_mod$dias_mora, scale = TRUE)
df_mod df_mod
Finalmente, se cuenta con 6 variables de las cuales
calificación_cliente es la variable objetivo y las variables
total_activos, ingresos, egresos, saldo_actual y días moras son las
variables predictivas.
Se dividen los datos con un 70% para el entrenamiento y un 30% para los datos de prueba:
set.seed(1234)
#Division es base training y test
<- sample.split(df_mod$calificacion_cliente, SplitRatio = 0.7)
split <- subset(df_mod, split == TRUE)
training_set <- subset(df_mod, split == FALSE) test_set
Esta metodología se utiliza para modelar la relación entre dos o más variables explicativas y una variable de respuesta encajando una ecuación lineal a los datos observados. Para este caso es óptimo ya que la variable de respuesta es cualitativa y el enfoque estará en hallar la probabilidad de que un cliente presente una calificación mala.
#Ajuste del modelo logit
<- glm(calificacion_cliente ~ ., family = binomial, data = training_set)
clasificadorRL #Resumen del modelo
summary(clasificadorRL)
##
## Call:
## glm(formula = calificacion_cliente ~ ., family = binomial, data = training_set)
##
## Deviance Residuals:
## Min 1Q Median 3Q Max
## -1.95459 -0.36365 -0.34999 0.00043 2.40963
##
## Coefficients:
## Estimate Std. Error z value Pr(>|z|)
## (Intercept) 4.90267 1.15772 4.235 0.00002288071 ***
## total_activos -0.08856 0.33672 -0.263 0.793
## egresos -0.02092 0.62676 -0.033 0.973
## saldo_actual -0.04574 0.23439 -0.195 0.845
## dias_mora 13.68478 2.25593 6.066 0.00000000131 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## (Dispersion parameter for binomial family taken to be 1)
##
## Null deviance: 599.61 on 441 degrees of freedom
## Residual deviance: 156.61 on 437 degrees of freedom
## AIC: 166.61
##
## Number of Fisher Scoring iterations: 10
Del resumen del modelo podemos observar que la variable días mora es la que presenta mayor discriminación ante la variable de respuesta, ya que un aumento en los días de mora aumenta notoriamente la probabilidad de obtener una mala calificación. Finalmente, se evalúa el accuracy y la matriz de correlación:
#Predicciones con la base training
<- predict(clasificadorRL, type = 'response', ndata = training_set)
pred_train <- ifelse(pred_train > 0.5, 1, 0)
pred_train <- factor(pred_train, levels = c("0", "1"), labels = c("BUENA", "MALA"))
pred_train
#Matriz de confusión con la base training
<- table(training_set$calificacion_cliente, pred_train)
matrizConfusion matrizConfusion
## pred_train
## BUENA MALA
## BUENA 258 1
## MALA 22 161
#Accuracy con la base training
= (matrizConfusion[1]+matrizConfusion[4])/442
Accuracy Accuracy
## [1] 0.9479638
Podemos observar que se tiene un accuracy del 94% lo cual indica que el modelo presenta una alta capacidad predictiva. Por otro lado, cabe destacar que el modelo es especialista para la clasificación de los clientes calificados como buenos, no obstante, presenta un excelente performance para la clasificación de malos clientes.
Lo más recomendable es utilizar un método de validación cruzada para
tener una idea de posible sobre ajuste en el modelo, además evaluar
múltiples modelos con diferentes combinaciones de variables predictivas,
esto con el fin de tener el modelo con mayor calidad.
Finalmente se procede a evaluar el modelo con los datos test:
#Predicciones con la base test
<- predict(clasificadorRL, type = 'response', newdata = test_set)
pred_valid <- ifelse(pred_valid > 0.5, 1, 0)
pred_valid <- factor(pred_valid, levels = c("0", "1"), labels = c("BUENA", "MALA"))
pred_valid
#Matriz de confusión con la base test
<- table(test_set$calificacion_cliente, pred_valid)
matrizConfusion2 matrizConfusion2
## pred_valid
## BUENA MALA
## BUENA 110 1
## MALA 10 69
#Accuracy con la base test
= (matrizConfusion2[1]+matrizConfusion2[4])/190
Accuracy2 Accuracy2
## [1] 0.9421053
Se tiene un resultado similar a lo evaluado con el dataset training,
por lo cual se puede concluir que el modelo de regresión logística es
adecuado para determinar la calificación de los clientes. Por otro lado,
es recomendable utilizar diferentes metodologías para la predicción del
mismo, como bien puede ser random forest, KNN o Naive Bayes.
#Curva ROC
<- prediction(as.numeric(pred_valid), as.numeric(test_set$calificacion_cliente))
pred1 <- performance(pred1, "tpr", "fpr")
perf1 plot(perf1)
Podemos observar que el área bajo la curva que se presenta en la
curva ROC es muy alta, es por esto que se confirma que el modelo tiene
una alta capacidad predictiva.
De esta primera parte podemos concluir que se consolidó una base de datos con 632 clientes y 12 variables, las cuales presentan características del estado financiero, cartera y características del sector económico. El análisis exploratorio dio como resultado que la variable ingreso está muy correlacionada con dos variables del estudio, además se pudo observar que los dias mora representan una notoria discriminación en cuanto a la calificación del cliente. Finalmente, en la modelación se pudo evidenciar que el modelo de regresión logística es un método potente ante las características del dataset, ya que se cuenta con una baja cantidad de datos y variables.
Es recomendable utilizar diferentes metodologías para tener un mayor
entendimiento del comportamiento del problema. Además, se recomienda
utilizar validación cruzada con el fin de tener precaución con el
sobreajuste. Finalmente se recomienda evaluar múltiples modelos con
diferentes combinaciones de variables, ya que se podría tener un modelo
aún mejor.
La base de datos cuenta con un indicador mensual el cual evalúa la rentabilidad de la compañía, se cuenta con información de 40 meses, los cuales inician en noviembre del 2019 y finaliza en febrero del 2023.
Inicialmente se guarda como dataframe los datos por medio de SQLite.
select*
from irs
datos_serie
Seguidamente, se crea el objeto de serie de tiempo el cual será utilizado para el pronóstico:
# creando objeto ts para modelo
<- ts(datos_serie$IRS,
data_ts frequency = 12,
start=112019)
#Grafico inicial de la serie
autoplot(data_ts)+
labs(title = "Serie de tiempo",
x = "Mes",
y = "Valor",
colour = "#00a0dc")+
theme_bw()
El primer análisis gráfico de los datos deja en evidencia que en el
2021 hubo un aumento notorio en el indicador, pero tuvo una decaída a
finales del año 2022.
una serie temporal es estacionaria cuando la media y la variabilidad se mantienen constantes a lo largo del tiempo, es decir, no es en función del tiempo; y además, no presenta tendencia. Es fundamental que la serie sea estacionaria ya que muchos métodos parten del supuesto de una serie estacional. Es por esto que se hará una descomposición aditiva para ver gráficamente el comportamiento estacional de la serie y si presenta tendencia:
# Descomposición de la serie de tiempo. Se almacena en el objeto fit
<- decompose(data_ts, type='additive')
fit
# Para graficar esta descomposición volvemos a emplear la funcion autoplot
autoplot(fit)+
labs(title = "Descomposición de la serie de tiempo",
x = "Tiempo",
y = "Valor",
colour = "Gears")+
theme_bw()
Del gráfico anterior podemos observar que existe una notoria tendencia, por lo cual se necesitará una transformación en la serie de tiempo para cumplir el supuesto de estacionariedad. Dicho esto, se aplicará el logaritmo a la serie con el fin de corregir la heterocedasticidad. Finalmente, se aplicarán las pruebas de hipotesis Dickey-Fuller y Phillips-Perron para determinar estacionariedad:
#Test de estacionariedad Dickey-Fuller
library(tseries)
adf.test(diff(log(data_ts)), alternative="stationary", k=0)
##
## Augmented Dickey-Fuller Test
##
## data: diff(log(data_ts))
## Dickey-Fuller = -9.277, Lag order = 0, p-value = 0.01
## alternative hypothesis: stationary
#Test de estacionariedad Phillips-Perron
pp.test(diff(log(data_ts), alternative="stationary"))
##
## Phillips-Perron Unit Root Test
##
## data: diff(log(data_ts), alternative = "stationary")
## Dickey-Fuller Z(alpha) = -44.107, Truncation lag parameter = 3, p-value
## = 0.01
## alternative hypothesis: stationary
Dados los resultados de las pruebas, podemos determinar que la serie presenta estacionariedad, ya que el valor p es menor a 0.05, por tanto, no se rechaza la hipótesis nula. Finalmente analizamos de nuevo la descomposición de la serie:
#Descomposicion Serie de tiempo con transformacion
plot(decompose(diff(log(data_ts))))
Podemos observar que la tendencia a desaparecido y cumplido los
supuestos de estacionariedad ya se puede proceder a los métodos
inferenciales para realizar los pronósticos. Para este caso se desea
pronosticar los 4 meses siguientes del 2023 (marzo, abril, mayo,
junio).
El modelo es muy simple, pero poderoso, en cuanto que es resultado directo de los datos y su tratamiento con simple estadística bayesiana de la probabilidad condicionada. Hay que tener en cuenta que se asume, por simplificación que las variables son todas sucesos independientes.
# elaborando el método
<- snaive(diff(log(data_ts)), h=4)
m1
# verificando el ajuste del metodo
=autoplot(m1)+autolayer(fitted(m1), series="Ajuste")
c1 c1
En primera instancia podemos interpretar que este método no estima de
buena manera los puntos constantes de la serie de tiempo.
Se utilizará el modelo de regresión lineal para dictaminar la predicción de los 4 meses siguientes. Dicho modelo es muy fuerte ante series de tiempo que no presenten una alta complejidad y que su esencia sea un comportamiento lineal.
# elaborando la regresion
<- tslm(diff(log(data_ts)) ~ trend + season)
regresion
# elaborando el pronostico
<- forecast(regresion, h=4)
m2
# verificando el ajuste del método
=autoplot(m2)+autolayer(fitted(m2), series="Ajuste")
c2 c2
En primera instancia se puede inferir que no existe un ajuste correcto
del método con los datos reales.
El modelo ARIMA consiste en la combinación de un término autorregresivo (AR) y un término de promedio móvil (MA). Es una buena métodolgia para la predicción en el corto plazo, debido a su capacidad de aprender de los cambios en la dinámica de la serie.
# elaborando el modelo ARIMA
<- auto.arima(diff(log(data_ts)))
modelo_arima
# elaborando el pronostico
<- forecast(modelo_arima, h=4)
m3
# verificando el ajuste del metodo
=autoplot(m3)+autolayer(fitted(m3), series="Ajuste")
c3 c3
En primera instancia se puede observar que el metodo no es capaz de
pronosticar correctamente los picos que toma la serie de tiempo.
Este método consiste en encontrar la relación de pesos a través de un proceso iterativo en el que, secuencialmente, se va analizando cada uno de los patrones de entrada a la red, reajustando en cada iteración la relación de pesos.
# elaborando el modelo de red neuronal
<- nnetar(diff(log(data_ts)))
neural_network
# elaborando el pronostico
<- forecast(neural_network, h=4)
m4
# verificando el ajuste del metodo
=autoplot(m4)+autolayer(fitted(m4), series="Ajuste")
c4 c4
En primera instancia se puede observar que el método es capaz de
pronosticar correctamente los picos que toma la serie de tiempo.
Para la comparación de los modelos se utilizará la raíz del error cuadrático medio (RMSE), el cual compara las diferencias entre el valor real y el valor predicho por el modelo.
#Se comparan los ajustes de los 4 modelos en una sola ventana
+ c2 + c3 + c4 +
c1 plot_layout(ncol = 2)
#Resultados RMSE en dataframe
<- data.frame("RMSE_Naive"=0.40,
resultados"RMSE_RegresionLineal"=0.24,
"RMSE_ARIMA"=0.28,
"RMSE_REDNEURONAL"=0.14)
resultados
Dado los resultados del ajuste y el RMSE, podemos dictaminar que la Red Neuronal es la que presenta un mejor ajuste a la serie de tiempo en cuestión, dado que es la que presenta notoriamente un menor RMSE. Finalmente es importante para el pronóstico que se cumpla el supuesto de no correlación y que los residuos sigan una distribución normal con media igual a cero.
# verificando los residuales
checkresiduals(m4)
##
## Ljung-Box test
##
## data: Residuals from NNAR(3,1,2)[12]
## Q* = 13.952, df = 8, p-value = 0.08302
##
## Model df: 0. Total lags used: 8
Dado los resultados, podemos dictaminar que se cumplen los supuestos
de autocorrelación y normalidad de los residuos, por tanto, el método de
red neuronal es el más adecuado para el estudio. Los resultados del
pronostico indican que existira un pico de aumento en el indicador y
seguidamente un pico de decremento, finalmente se estabiliza para los
últimos dos meses.
De esta segunda parte podemos concluir que se consolidó una base de datos con 40 meses y 1 variable indicadora de la rentabilidad de la empresa. Se verificó la estacionariedad y tendencia de la serie de tiempo, la cual dio notorios avistamientos de presentar tendencia, es por esto que se aplicó logaritmo con el fin de reducir la heterocedasticidad y así poder aplicar los métodos de pronóstico.
En cuanto a los métodos de pronóstico, se pudo observar que el método basado en redes neuronales es el óptimo para el estudio, ya que fue capaz de identificar los diferentes picos de la serie de tiempo, algo que a los otros métodos se les dificulta. Esto puede deberse a que las redes neuronales están capacitadas ante datos con un comportamiento complejo. Finalmente se recomienda utilizar diversas metodologías y aumentar el periodo de tiempo a pronosticar, ya que algunos métodos son potentes a largo plazo.