mar 012013
 
Captura de pantalla 2013-03-01 a la(s) 13.50.50

He tenido el blog un poco abandonado últimamente, pero no he dejado de enredar. Lo último que he estado desarrollando con R es una aplicación web para la identificación y estimación de modelos ARIMA. La idea surgió cuando, en el primer cuatrimestre, volví a enseñar este tipo de modelos a la primera promoción del Grado de Economía de la Especialidad de Análisis Económico (aunque no llegaron a ver la aplicación).

El paquete shiny de R apareció a finales de 2012 y hace sencillo crear pequeñas aplicaciones a las que el usuario accede desde el navegador. Pueden estar alojadas en un servidor externo o en el propio equipo del usuario. Con dicha herramienta, una vez se adquiere cierta soltura, se puede crear aplicaciones vistosas en relativamente poco tiempo.

Ayer presenté la versión actual (28 de febrero de 2013) de la aplicación en el Grupo de Usuarios de R de Madrid. El video de la presentación se puede ver pulsando aquí. La aplicación en vivo aparece a continuación (es trabajo en curso, así que habrá muchos cambios y puede no funcionar). También se puede acceder a ella en http://glimmer.rstudio.com/grserrano/idts.

Funciona mejor en Chrome que en otros navegadores, pero estaré encantado de recibir comentarios con las combinaciones de navegador y sistema operativo donde se aprecie algún problema. En el iPhone se ve estupendamente, así que ya tengo un ARIMAphone:

idts1idts2

 

 

 

 

 

 

 

sep 032012
 
chiste-politica-1

Quería preparar un ejemplo de web scraping (extracción de datos de páginas web) con R y me decidí por utilizar algún indicador de los que publica periódicamente el Centro de Investigaciones Sociológicas (CIS) en los Barómetros mensuales. Elegí los indicadores de la situación política. Ciertamente, no es que anduviera sobrado de esperanza en lo tocante a la confianza que los ciudadanos vienen depositando en los políticos, pero los datos son para llorar, y es que viene de antiguo:

Continue reading »

may 172012
 
Rlogo-beta

5.5  Cointegración y modelo de correción de error

Se habla de cointegración entre dos series temporales cuando ambas son no estacionarias (requieren una diferencia para serlo) pero una combinación lineal de ellas sí lo es. En este caso, la combinación lineal estacionaria se puede interpretar como una relación a largo plazo e incluirla retardada en el modelo en diferencias como factor de ajuste o término de corrección de error.

Aunque sin justificación teórica, nos podemos preguntar si el consumo de cigarrillos y la publicidad están cointegradas. Para ello estimamos un modelo en logaritmos de las variables y calculamos los residuos, que deberían ser estacionarios. Para contrastar formalmente la estacionariedad se utiliza el contraste de Dickey-Fuller aumentado (adf.test() del paquete tseries), aplicado a los residuos de la regresión en logaritmos de consumo de tabaco sobre publicidad:

> library(tseries)
> mcoint <- dynlm(log(consumo)~log(publicidad),
+                 data=window(tabdz, start=1940))
> summary(mcoint)


Time series regression with "zooreg" data:
Start = 1940, End = 1978

Call:
dynlm(formula = log(consumo) ~ log(publicidad), data = window(tabdz,
    start = 1940))

Residuals:
     Min       1Q   Median       3Q      Max
-0.56682 -0.01087  0.03205  0.07480  0.16525

Coefficients:
                Estimate Std. Error t value Pr(>|t|)
(Intercept)      7.96733    0.04374 182.138  < 2e-16 ***
log(publicidad)  0.17307    0.04195   4.126 0.000201 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1445 on 37 degrees of freedom
Multiple R-squared: 0.3151,	Adjusted R-squared: 0.2966
F-statistic: 17.02 on 1 and 37 DF,  p-value: 0.0002011
 


> adf.test(as.ts(residuals(mcoint)))  ## Requiere ts, no sirve zoo


	Augmented Dickey-Fuller Test

data:  as.ts(residuals(mcoint))
Dickey-Fuller = -3.3081, Lag order = 3, p-value = 0.08536
alternative hypothesis: stationary

No se puede rechazar la presencia de raíz unitaria en los residuos al 5% de significación (al no poder rechazar la nula), aunque sí al 10%. Si se asume la estacionariedad de los residuos de la regresión anterior, se podrían incluir retardados en la estimación del modelo como un término de corrección de error o relación a largo plazo entre las variables. A continuación, añadimos el término de corrección de error (residuos de la estimación en logaritmos) al data.frame tabz con merge() para, después, estimar los modelos tabm1 y tabm2 incluyendo dicha variable retardada:

> tabdz <- merge(tabdz, err.c=residuals(mcoint))
> tab.ecm1 <- dynlm(d(log(consumo))~d(log(publicidad))+L(err.c),
+                  data=window(tabdz, start=1940))
> tab.ecm2 <- dynlm(d(log(consumo))~L(d(log(consumo)))+L(err.c),
+                  data=window(tabdz, start=1940))
> mtable(tab.ecm1, tab.ecm2)


Calls:
tab.ecm1: dynlm(formula = d(log(consumo)) ~ d(log(publicidad)) + L(err.c),
    data = window(tabdz, start = 1940))
tab.ecm2: dynlm(formula = d(log(consumo)) ~ L(d(log(consumo))) + L(err.c),
    data = window(tabdz, start = 1940))

=======================================
                    tab.ecm1  tab.ecm2
---------------------------------------
(Intercept)          0.021***  0.014*
                    (0.006)   (0.006)
d(log(publicidad))  -0.083
                    (0.075)
L(err.c)            -0.217*** -0.219***
                    (0.042)   (0.054)
L(d(log(consumo)))             0.272*
                              (0.125)
---------------------------------------
R-squared              0.545     0.537
adj. R-squared         0.519     0.509
sigma                  0.033     0.031
F                     20.983    19.688
p                      0.000     0.000
Log-likelihood        77.507    77.476
Deviance               0.038     0.033
AIC                 -147.014  -146.951
BIC                 -140.464  -140.508
N                     38        37
=======================================

may 162012
 
Rlogo-beta

5.4  Autocorrelación y matriz de covarianzas consistente

Aunque la varianza de las estimaciones de los coeficientes del modelo se suele presentar como \mathrm{V}(\hat{\boldsymbol{\beta}})=\sigma^2(X'X)^{-1}, se trata de un caso particular. En general, la varianza de los estimadores por MCO es:

\mathrm{V}(\hat{\boldsymbol{\beta}})=(X'X)^{-1} X'\Omega X (X'X)^{-1},

de donde se obtiene el caso particular si \mathrm{V}(\boldsymbol{\varepsilon})=\Omega=\sigma^2 I_n. Sin embargo, existen situaciones en las que el supuesto ideal de perturbaciones esféricas no se cumple.

El primer caso, llamado heterocedasticidad, ocurre cuando las perturbaciones no tienen idéntica varianza, es decir Vi)=σ2i ≠ σ2. En esta situación Ω es una matriz diagonal, pero los elementos no nulos son diferentes. El segundo caso, que denominamos autocorrelación, consiste en que las perturbaciones no son independientes (Covts) ≠ 0) y por lo tanto, los elementos de fuera de la diagonal de la matriz Ω son distintos de cero. En cualquiera de los casos mencionados, la estimación de \mathrm{V}(\hat{\boldsymbol{\beta}}) por mínimos cuadrados produce un estimador inconsistente, que invalida los contrastes realizados sobre los coeficientes estimados.

Se ha propuesto una familia general de estimadores consistentes de la matriz de covarianzas, de manera que distintas elecciones para estimar X’ΩX producen estimaciones consistentes ante la presencia de heterocedasticidad y/o autocorrelación, siendo pioneros el de White para heterocedasticidad y el de Newey-West para el caso de heterocedasticidad y autocorrelación.

La presencia de autocorrelación, además, si se incluyen retardos de la variable explicada como explicativa, puede dar lugar a estimaciones inconsistentes del vector de parámetros. Para detectar la presencia de autocorrelación en el modelo lineal general, además de las funciones de autocorrelación simple y parcial de los residuos del modelo, se puede utilizar el contraste de Breusch-Godfrey, donde hay que especificar el orden de la autocorrelación de las perturbaciones que se desea contrastar o el más genérico contraste de Ljung-Box, cuya hipótesis nula es que la serie (de residuos en este caso) sigue un proceso de ruido blanco. Volviendo a los modelos de consumo de tabaco:

> bgtest(tabm1, 1)


	Breusch-Godfrey test for serial correlation of order up to 1

data:  tabm1
LM test = 8.8763, df = 1, p-value = 0.002889


> Box.test(residuals(tabm1), 6,  type="Ljung-Box")


	Box-Ljung test

data:  residuals(tabm1)
X-squared = 14.3463, df = 6, p-value = 0.026


> bgtest(tabm2, 1)


	Breusch-Godfrey test for serial correlation of order up to 1

data:  tabm2
LM test = 2.4486, df = 1, p-value = 0.1176


> Box.test(residuals(tabm2), 6, type="Ljung-Box")


	Box-Ljung test

data:  residuals(tabm2)
X-squared = 4.9471, df = 6, p-value = 0.5506

En el modelo tabm1 existe evidencia de autocorrelación de primer orden de acuerdo con el contraste de Breusch-Godfrey y se rechaza que los residuos sean ruido blanco según el contraste de Ljung-Box, por lo que los estadísticos t de significación individual (o cualquier otro contraste) no son válidos. Sin embargo, no aparecen problemas de autocorrelación en el modelo tabm2.

Para estimar la matriz de varianzas covarianzas consistente se puede usar la función vcovHAC() (sería vcovHC() si el problema fuese sólo de heterocedasticidad). Como existen distintos estimadores consistentes, la función vcovHAC admite un argumento type para seleccionar un estimador concreto o alternativamente, utilizar la función NeweyWest() que devuelve el estimador de Newey-West de \mathrm{V}(\hat{\boldsymbol{\beta}}). Por su parte, la función coeftest() realiza los contrastes t habituales admitiendo diferentes estimaciones de la matriz de covarianzas de los coeficientes estimados:

> library(sandwich)
> coeftest(tabm1) ## Estimador de la varianza MCO


t test of coefficients:

                     Estimate Std. Error t value Pr(>|t|)
(Intercept)         0.0267053  0.0074777  3.5713 0.001031 **
d(log(publicidad)) -0.2627841  0.0872122 -3.0132 0.004712 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


> coeftest(tabm1, vcov.=vcovHAC(tabm1))


t test of coefficients:

                    Estimate Std. Error t value Pr(>|t|)
(Intercept)         0.026705   0.012354  2.1617  0.03737 *
d(log(publicidad)) -0.262784   0.126461 -2.0780  0.04490 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1


> coeftest(tabm1, vcov.=NeweyWest(tabm1, lag=2))


t test of coefficients:

                    Estimate Std. Error t value Pr(>|t|)
(Intercept)         0.026705   0.011400  2.3426  0.02479 *
d(log(publicidad)) -0.262784   0.107444 -2.4458  0.01947 *
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

La inconsistencia de la matriz de covarianzas no sólo invalida los contrastes t, también cualquier contraste de hipótesis lineales presentados en la Sección 4.2 utilizando la forma de Wald, no así la forma basada en sumas residuales, que no se ven alteradas. En su momento vimos la función linearHypothesis(), que también admite un argumento vcov.= para especificar una función que calcule la matriz de covarianzas consistente o bien la propia matriz de covarianzas.

may 082012
 
Rlogo-beta

5.3  Modelo lineal con series temporales

En las secciones anteriores se ha visto como cargar y crear un objeto de clase zooreg para tratar datos de series temporales. A continuación, se presentan algunas funciones específicas para la estimación del modelo lineal general en  incluyendo elementos habituales para esta clase de datos como retardos y diferencias. Tomando el conjunto de datos sobre consumo de tabaco y publicidad, cuya descripción se puede encontrar al final, se cargan los datos y se crea un objeto zooreg excluyendo la primera columna cargada (que contiene el año):

> library(zoo)
> tabd  <- read.csv("http://grserrano.es/datos/datos_tabaco.csv")
> tabdz <- zooreg(tabd[, -1], start=1930, frequency=1)

La falta de estacionariedad (media no constante) de las variables del ejemplo es evidente a la vista del gráfico en logaritmos que se presentó en la entrada sobre gráficos de series temporales, por lo que especificaremos los modelos en tasas de variación logarítmica. Para justificar formalmente tomar diferencias, se pueden utilizar los contrastes de Dickey-Fuller (adf.test(), que se ilustra un poco más adelante) o el de Phillips-Perron (pp.test()) aplicados a las series en logaritmos.

Para la estimación, el paquete dynlm estima modelos lineales por mínimos cuadrados, pero facilita la especificación de regresiones con retardos y diferencias en las variables. No insistiré aquí en la importancia de no estimar regresiones con variables que comparten tendencias, puesto que casi siempre serán regresiones espurias.

En el siguiente fragmento se estima un modelo en tasas de variación (diferencias de logartimos, usando la función d()) explicando el consumo de tabaco en función del gasto en publicidad utilizando datos desde 1940 (argumento data con la función window()) que se muestran en el Gráfico 1.



Gráico 1: Evolución del consumo de tabaco y el gasto en publicidad en tasas logarítmicas de variación interanual.

> library(dynlm)
> tabdz1 <- diff(log(window(tabdz[, c("consumo", "publicidad")], start=1940)))
> tmp  <- data.frame(date=as.Date(paste(1941:1978, "-6-30", sep="")),
+                    consumo=tabdz1[, "consumo"],
+                    publicidad=tabdz1[, "publicidad"])
> tmpl <- melt(tmp, id.vars="date")
> qplot(date, value*100, data=tmpl, geom=c("point", "line"),
+       ylab="T.V. Interanual (%)", xlab="Año", colour=variable)
> tabm1 <- dynlm(d(log(consumo))~d(log(publicidad)),
+                data=window(tabdz, start=1940))
> summary(tabm1)


Time series regression with "zooreg" data:
Start = 1941, End = 1978

Call:
dynlm(formula = d(log(consumo)) ~ d(log(publicidad)), data = window(tabdz,
    start = 1940))

Residuals:
      Min        1Q    Median        3Q       Max
-0.077950 -0.032970 -0.004458  0.012886  0.098907

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)
(Intercept)         0.026705   0.007478   3.571  0.00103 **
d(log(publicidad)) -0.262784   0.087212  -3.013  0.00471 **
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.04285 on 36 degrees of freedom
Multiple R-squared: 0.2014,	Adjusted R-squared: 0.1792
F-statistic: 9.079 on 1 and 36 DF,  p-value: 0.004712

Como se aprecia en la estimación, el consumo está inversamente relacionado con el gasto publicitario, resultado anómalo sólo explicable por la progresiva concienciación de los perjuicios del tabaco para la
salud.

Para introducir un retardo de la tasa de variación del consumo de tabaco como variable explicativa se usa la función L() (dentro de la fórmula de dynlm()):

> tabm2 <- dynlm(d(log(consumo))~L(d(log(consumo))) + d(log(publicidad)),
+                data=window(tabdz, start=1940))
> summary(tabm2)
 


Time series regression with "zooreg" data:
Start = 1942, End = 1978

Call:
dynlm(formula = d(log(consumo)) ~ L(d(log(consumo))) + d(log(publicidad)),
    data = window(tabdz, start = 1940))

Residuals:
     Min       1Q   Median       3Q      Max
-0.07860 -0.02460 -0.00015  0.02212  0.08261

Coefficients:
                    Estimate Std. Error t value Pr(>|t|)
(Intercept)         0.011739   0.007496   1.566  0.12659
L(d(log(consumo)))  0.430304   0.138768   3.101  0.00386 **
d(log(publicidad)) -0.136513   0.081429  -1.676  0.10282
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.03638 on 34 degrees of freedom
Multiple R-squared: 0.3658,	Adjusted R-squared: 0.3285
F-statistic: 9.806 on 2 and 34 DF,  p-value: 0.0004341

Ahora es la tasa de variación del consumo en el año anterior lo que mejor explica la variación en el presente y el gasto publicitario ha perdido significación. No obstante, estos resultados deben tomarse con precaución hasta realizar los diagnósticos del modelo, ya que es frecuente la presencia de autocorrelación, lo que puede hacer que la estimación de las varianzas de los coeficientes resulte inconsistente (Sección 5.4).

El gráfico de residuos (Gráfico 2(a)), como siempre, es una primera herramienta para el diagnóstico de un modelo estimado. Primero hay que preparar un data.frame con las fechas y los residuos tipificados para usar ggplot2:

> tmp <- data.frame(date=as.Date(paste(1942:1978, "-6-30", sep="")),
+                   resid=scale(residuals(tabm2)),
+                   precio=subset(tabd, subset=(year>=1942), select="precio"))
> g6 <- qplot(date, resid, data=tmp, color=precio, geom=c("point", "line"),
+             ylab="Residuos tipificados", xlab="Año")

A la vista de las funciones de autocorrelación simple y parcial del Gráfico 2(b) (calculadas con acf() y pacf()) no se sospecha la presencia de autocorrelación en las perturbaciones del modelo, aunque sí se observa cierta variabilidad en la dispersión en el gráfico de residuos. Veremos contrastes formales en la Sección 5.4. Sobre el código del ejemplo, en la práctica no hay que programar el gráfico de las funciones de autocorrelación cada vez, sino que habría que empaquetarlo en una función que estaría siempre disponible (véase el Apéndice C).


Gráfico de residuos de tabm2

Funciones de autocorrelación simple y parcial


Gráfico 2: Residuos del modelo tabm2.

Para especificar más retardos de una variable se puede usar el segundo argumento de la función de retardo L() dentro de dynlm(). A continuación se estima un modelo autorregresivo de orden 2 para el consumo de tabaco:

> tabm2.ar <- dynlm(d(log(consumo))~L(d(log(consumo)), 1:2),
+                data=window(tabdz, start=1940))
> summary(tabm2.ar)


Time series regression with "zooreg" data:
Start = 1943, End = 1978

Call:
dynlm(formula = d(log(consumo)) ~ L(d(log(consumo)), 1:2), data = window(tabdz,
    start = 1940))

Residuals:
      Min        1Q    Median        3Q       Max
-0.067064 -0.018912  0.002138  0.019484  0.089672

Coefficients:
                         Estimate Std. Error t value Pr(>|t|)
(Intercept)              0.003018   0.006310   0.478   0.6356
L(d(log(consumo)), 1:2)1 0.275740   0.156556   1.761   0.0875 .
L(d(log(consumo)), 1:2)2 0.213038   0.145727   1.462   0.1532
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.03445 on 33 degrees of freedom
Multiple R-squared: 0.2615,	Adjusted R-squared: 0.2167
F-statistic: 5.843 on 2 and 33 DF,  p-value: 0.006726


Datos de consumo de tabaco y publicidad

El archivo datos_tabaco.csv contiene datos anuales desde 1930 a 1978 para EE.UU. de las siguientes variables:

  • consumo de cigarrillos per cápita,
  • renta per cápita,
  • precio medio de la cajetilla de tabaco en términos reales (es decir, deflactado por un índice de precios) en centavos,
  • un indicador del gasto en publicidad del sector tabaquero (una variable stock que se construye a partir del gasto corriente en publicidad de años anteriores, aplicando una cierta tasa de depreciación).

Además, se conoce la siguiente información:

  • En 1953, la American Cancer Society y el British Medical Research Council emitieron sendos informes que mostraban cómo las tasas de mortalidad eran más elevadas entre fumadores.
  • En 1964, el US General Surgeon Report concluía que fumar cigarrillos estaba ligado al cáncer de laringe.
  • En 1970 se aprobó la legislación que obligaba a las compañías a mostrar en las cajetillas mensajes de advertencia sobre los peligros del tabaco.
abr 162012
 

5.2  Análisis simple de series temporales

Un supuesto clásico es que una serie temporal (Yt) se puede descomponer en ciclo-tendencia (Ct), componente estacional (St) y componente irregular o ruido (vt):

Y_t = C_t + S_t + v_t, \qquad t=1,\ldots,T.

Si la descomposición anterior se aplica a una serie en logaritmos, estaríamos suponiendo que los componentes de la serie original son multiplicativos (Yt = Ct ·St ·evt) en lugar de aditivos, lo que resulta conveniente si la varianza no es constante.

Un supuesto simple (aunque casi siempre inadecuado) es que el componente tendencial es determinista y se puede ajustar a una recta (o polinomio) en función del tiempo: Ct = α+ βt + wt. Una vez estimado el modelo anterior por mínimos cuadrados, el componente estacional puede extraerse promediando, para cada mes o trimestre, las diferencias entre el valor observado y el componente tendencial ajustado por el modelo (equivalente a añadir variables ficticias estacionales).

> ipc09  <- window(ipcz, end=c(2009, 12))       ## Datos hasta diciembre 2009
> tiempo <- time(ipc09)                         ## Variable de tiempo
> mlipc  <- lm(log(ipc09)~tiempo)               ## Tendencia lineal
> mlipc2 <- lm(log(ipc09)~tiempo+I(tiempo^2))   ## Tendencia cuadrática
> ## Componente estacional
> factor.mes.lm <- aggregate(log(ipc09)-fitted(mlipc), cycle(ipc09), mean)
> factor.mes.lm


            1             2             3             4             5
-0.0054713293 -0.0066538299 -0.0028545010  0.0053092476  0.0056314714
            6             7             8             9            10
 0.0055681477 -0.0014711077 -0.0012383893 -0.0021442988  0.0017199817
           11            12
 0.0013317933  0.0002728143


> ## Preparación para el gráfico con ggplot2, cada dato se asocia al día 15
> ipc.df      <- data.frame(log.IPC=log(ipc09), Tend.Lin.=fitted(mlipc),
+                           Tend.Cuad.=fitted(mlipc2))
> ipc.df$date <- as.Date(paste(floor(time(ipc09)), cycle(ipc09), 15, sep="-"))
> ipc.dfl     <- melt(ipc.df, id="date")
> qplot(date, value, data=ipc.dfl, geom="line", color=variable,
+       ylab="logaritmos", xlab="Año")
> ggsave("desc-ts-1.pdf", last_plot())

Como se puede apreciar (Gráfico 8), las tendencias deterministas tanto lineal como cuadrática son incapaces de ajustarse al cambio que experimenta la evolución del IPC en 2008, con un crecimiento por encima del esperado, y al contrario en 2009. Dado que estos cambios se producen de manera habitual en datos económicos, el uso de tendencias deterministas sólo es razonable en contextos muy controlados.



Gráfico 8: Extracción de tendencia determinista lineal y cuadrática.

El cálculo de previsiones, bajo el supuesto de tendencia determinista, tan sólo requiere la extrapolación de la tendencia a la que habría que añadir el componente estacional. A continuación se ilustra el cálculo de previsiones para 2010 con la tendencia lineal, y se observa el error sistemático que comete el modelo de tendencia determinista:

> tend.prev <- predict(mlipc, data.frame(tiempo=2010 + 0:11/12))
> ipc.prev  <- zooreg(as.numeric(exp(tend.prev+factor.mes.lm)),
+                     start=c(2010,1), frequency=12)
> window(merge(ipcz, ipc.prev), start=c(2010, 1), end=c(2010, 12))


            ipcz ipc.prev
2010(1)  106.680 110.0170
2010(2)  106.480 110.1650
2010(3)  107.270 110.8641
2010(4)  108.420 112.0556
2010(5)  108.660 112.3753
2010(6)  108.850 112.6525
2010(7)  108.360 112.1453
2010(8)  108.640 112.4552
2010(9)  108.710 112.6376
2010(10) 109.705 113.3598
2010(11) 110.300 113.6025
2010(12) 110.979 113.7694

La función stl() devuelve una descomposición en ciclo-tendencia, componente estacional e irregular mucho más refinada, utilizando regresiones locales para la estimación del componente tendencial. El paquete mFilter contiene distintas funciones para la extracción de tendencias, entre ellas el conocido filtro de Hodrick-Prescott. Finalmente, la función StructTS() también realiza esta clase de descomposiciones permitiendo especificar qué componentes se consideran incluidos en la variable utilizando modelos estructurales de series temporales.

A continuación se ilustra el uso de stl() para la descomposición del IPC. Como se puede apreciar en el Gráfico 9 la tendencia es adaptativa, por lo que recoge el cambio en la evolución del IPC a partir de 2008.

> lipc.stl <- stl(log(ipc09), s.window="periodic")
> lipc.stl <- as.zooreg(lipc.stl$time.series) ## Series resultantes
> tend.stl <- lipc.stl[, "trend"]
> factor.mes.stl <- aggregate(lipc.stl[, "seasonal"],
+                             cycle(lipc.stl[, "seasonal"]), mean)
> factor.mes.stl


            1             2             3             4             5
-0.0073789123 -0.0085894080 -0.0048180723  0.0036906824  0.0043579095
            6             7             8             9            10
 0.0050215278 -0.0012907873 -0.0003226822 -0.0004932039  0.0036591368
           11            12
 0.0035590064  0.0026048053


> lipc.stl.df <- data.frame(log.IPC=log(ipc09), Tend.loc.=tend.stl)
> lipc.stl.df$date <- as.Date(paste(floor(time(ipc09)),
+                                   cycle(ipc09), 15, sep="-"))
> ipc.stl.dfl      <- melt(lipc.stl.df, id="date")
> qplot(date, value, data=ipc.stl.dfl, geom="line", color=variable,
+       ylab="logaritmos", xlab="Año")
> ggsave("desc-ts-2.pdf", last_plot())



Gráfico 9: Extracción de tendencia mediante regresiones locales.

Un método más simple consiste en utilizar medias móviles para extraer el componente ciclo-tendencia de forma adaptativa. Sin embargo, la media móvil centrada tiene el inconveniente de que no se puede calcular para las últimas observaciones, por eso es recomendable usar stl(), que básicamente calcula una media móvil ponderada robusta y se puede obtener la tendencia desde la primera a la última observación. Para calcular la media móvil centrada de orden 12 de los datos de IPC se haría:

> tend.mm <- rollapply(log(ipc09), 12, mean)
> ## Comparación tendencia stl y media móvil centrada en 2009
> window(merge(ipc09, exp(tend.stl), exp(tend.mm)), start=c(2009,1))


          ipc09 exp(tend.stl) exp(tend.mm)
2009(1)  105.59      106.8233     106.7913
2009(2)  105.60      106.7330     106.7191
2009(3)  105.78      106.6429     106.6277
2009(4)  106.81      106.6611     106.5691
2009(5)  106.77      106.6794     106.5963
2009(6)  107.24      106.7155     106.6667
2009(7)  106.33      106.7516           NA
2009(8)  106.70      106.7965           NA
2009(9)  106.45      106.8415           NA
2009(10) 107.21      106.8961           NA
2009(11) 107.79      106.9508           NA
2009(12) 107.76      107.0139           NA

En cualquiera de los casos anteriores, es necesario definir alguna estrategia de extrapolación de la tendencia si se pretenden calcular previsiones. Una opción simple, aunque no óptima, sería ajustar splines cúbicos a la tendencia, por lo que la extrapolación se basaría en los últimos datos.

abr 112012
 
Rlogo-beta

5.1  Carga de datos y gráficos de series temporales

Aunque la carga de datos se hace del mismo modo que se presentó anteriormente, una vez cargados en R y para utilizar funciones específicas de series temporales conviene crear una clase que tenga en cuenta la naturaleza de estas variables. Existen varias clases que facilitan esta tarea: ts (la básica en R), zoo y xts (ambas con más flexibilidad y funcionalidad). En lo que sigue, convertiremos los datos cargados a objetos de clase zooreg, específica para datos de series temporales regulares, aunque el paquete zoo también puede manejar series de frecuencia irregular.

En el siguiente ejemplo se cargan datos del IPC español desde enero de 2002 (no es necesario especificar la fecha final, zooreg() la deduce) y se crea un objeto de serie temporal zooreg con los datos cargados. La función window(), mediante los argumentos start y end, permite seleccionar un rango de observaciones basadas en fechas:

> library(zoo)
> ipcd <- read.csv("http://grserrano.es/datos/ipc0.csv")
> ipcz <- zooreg(ipcd[, "ipc"], start=c(2000, 1), frequency=12)
> window(ipcz, start=c(2009, 1), end=c(2009, 12))


 2009(1)  2009(2)  2009(3)  2009(4)  2009(5)  2009(6)  2009(7)  2009(8)
  105.59   105.60   105.78   106.81   106.77   107.24   106.33   106.70
 2009(9) 2009(10) 2009(11) 2009(12)
  106.45   107.21   107.79   107.76

Otras funciones útiles para tratar con objetos de tipo zooreg son time() y cycle(), que devuelven la fecha en formato decimal y el período dentro del año al que corresponde la observación. La función aggregate(), trabajando sobre series temporales, permite agregar los datos con distintas frecuencias y usando diferentes funciones de agregación. Las funciones lag() y diff() toman retardos y diferencias a la serie. Además, el paquete zoo incluye funciones como rollapply() que facilita aplicar una función a una ventana móvil de observaciones de una serie temporal.

Sin embargo, ggplot2 no es sensible a los objetos de serie temporal. Para utilizar la librería ggplot2 con esta clase de datos hay que crear un data.frame con las variables apiladas por columnas y una variable de fecha de la clase Date con la función as.Date(). Aunque es pesado, ambas tareas se solventan en un par de líneas.

En el siguiente ejemplo se cargan datos desde un fichero .csv, se añade una columna de fechas (se trata de datos anuales) con as.Date() y mediante la función melt() (del paquete reshape) se apilan las columnas. Finalmente se elabora un gráfico con cada serie en un panel diferente (Gráfico 7(a)) llamando a qplot() y facet_grid():

> tabd      <- read.csv("http://grserrano.es/datos/datos_tabaco.csv")
> head(tabd)


  year consumo precio renta publicidad
1 1930    1329  74.20 701.1    1.18915
2 1931    1254  86.84 652.7    1.39317
3 1932    1117  96.82 546.5    1.49735
4 1933    1198  87.63 527.9    1.56667
5 1934    1333  91.02 589.4    1.68602
6 1935    1406  90.27 666.1    1.70033


> ## Ponemos el dato anual en el 30 de junio de cada año
> tabd$date <- as.Date(paste(tabd$year, 6, 30, sep="-"))
> ## Apilamos las variables excluyendo year (primera columna)
> tabdl     <- melt(tabd[, -1], id.vars="date")
> head(tabdl)


        date variable value
1 1930-06-30  consumo  1329
2 1931-06-30  consumo  1254
3 1932-06-30  consumo  1117
4 1933-06-30  consumo  1198
5 1934-06-30  consumo  1333
6 1935-06-30  consumo  1406


> g5.a <- qplot(date, log(value), data=tabdl, geom="line", xlab="Año",
+               ylab="logaritmos") +
+         facet_grid(variable ~ ., scale = "free_y")

Una de las muchas facilidades que proporciona el paquete ggplot2 es que se puede ampliar un región del gráfico ajustando los límites de los ejes. A continuación hacemos zoom sobre los primeros 16 años de datos (Gráfico 7(b)) simplemente añadiendo una nueva especificación para los límites del eje de abscisas:

> g5.z <- g5.a + xlim(as.Date(c("1930-1-1", "1945-12-31")))

Puesto que las unidades son diferentes, no tiene sentido un gráfico con un eje común para las series, pero ya que están en logaritmos, y como ejemplo, a continuación se ilustra dicha representación (Gráfico 7(c)):

> g5.b <- qplot(date, log(value), data=tabdl, geom="line", xlab="Año",
+               ylab="logaritmos", colour=variable)


(a) Cada serie con su eje Y.

(b) Ampliación 1930-45 de (a).


(c) Eje de ordenadas común.


Gráfico 7: Evolución de las variables en datos_tabaco.csv.

Además de los estadísticos descriptivos que vimos en secciones anteriores, para series temporales, entre otras muchas, tenemos las funciones acf(), pacf() (para las funciones de autocorrelación simple y parcial), ccf() (función de autocorrelación cruzada) y contrastes específicos como Box.test() (contraste de Ljung-Box) y adf.test() (test de Dickey-Fuller aumentado).

dic 012010
 

En la primera parte de este artículo se ha visto cómo extraer datos de Google Trends desde R. Los datos normalizados de búsquedas de la palabra “crisis” quedaron guardados en un data.frame de la clase zoo llamado wdatz. Ahora, para ilustrar el trabajo con series temporales, vamos a agregar los datos semanales a mensuales y se extraer la tendencia de los mismos mediante locally weighted exponential smoothing, uno de los muchos algoritmos disponibles para hacerlo (otros se pueden encontrar en el paquete mFilter, entre ellos el popular filtro de Hodrick-Presscott o se pueden usar modelos estructurales de series temporales con la función StructTS).
Continue reading »

dic 012010
 

Google Trends (GTrends en adelante) proporciona datos de las búsquedas realizadas sobre uno o más conceptos, normalizados respecto a totales de búsquedas, de manera que consituyen una interesante secuencia del interés de los usuarios por determinadas cosas. En este ejemplo, dividido en dos partes, primero se ilustra cómo extraer los datos desde R utilizando el paquete RGoogleTrends de Duncan Temple Lang y en la segunda parte se muestra un sencillo tratamiento de los mismos extrayendo la tendencia. Los datos de GTrends se pueden obtener también de su página web, que permite exportar los resultados en formato de texto separado por comas.
Continue reading »

oct 252010
 

El histograma de rentabilidad diaria del IBEX nos permite introducir algunas funciones nuevas de R. El paquete quantmod incluye funciones (como getSymbols y otras) para acceder directamente a los datos de Yahoo Finance usando el ticker del activo, de manera que se pueden obtener datos históricos (hasta ayer mismo) de cotización de prácticamente cualquier activo cotizado en alguna bolsa del mundo (línea 3). En la línea 4 se cambia el tipo de almacenamiento, de la clase xts a la clase zoo, con la que trabajamos habitualmente con series temporales. La otra línea novedosa en el script es la 10, en la que se añade al histograma una función matemática (función curve), en este caso la función de densidad de una normal (dnorm) cuyos momentos (media y desviación típica) se calculan con los datos de rentabilidad diaria del IBEX. Además, se han añadido las fronteras de un gráfico de caja Q1-1.5 IQRx y Q3+1.5 IQRx para ilustrar la frecuencia de valores atípicos en esta clase de datos.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
library(MASS); library(quantmod); library(zoo)
 
getSymbols("^IBEX", src="yahoo", from="2005-01-01")
IBEX < - as.zoo(IBEX)   ## Al cargar son de tipo xts
tail(IBEX)             ## ¿Cómo va hoy?
rentibex <- diff(log(IBEX[,"IBEX.Adjusted"]))
 
truehist(rentibex, prob=TRUE, xlab='Rentabilidad', ylab='Frecuencia escalada',
    main="IBEX")
curve(dnorm(x, mean=mean(rentibex), sd=sd(rentibex)),
       from=-0.1, to=0.1, add=TRUE)
qq  <- quantile(rentibex, c(0.25, 0.5, 0.75))
iqr <- qq[3]-qq[1]
abline(v=c(qq[3]+1.5*iqr, qq[1]-1.5*iqr), lty=2, col="red")
text(qq[3]+1.5*iqr, 30, expression(Q[3]+1.5*IQR[x]), pos=4, col="red")
text(qq[1]-1.5*iqr, 30, expression(Q[1]-1.5*IQR[x]), pos=2, col="red")