R cuenta con numerosas funciones para el análisis de series temporales. El uso de tales funciones requiere que los objetos a los que se aplican sean de la clase ts
(time series). La función ts()
convierte un objeto a serie temporal.
IMPORTANTE: La construcción de objetos de la clase ts
requiere que los datos de partida estén distribuidos regularmente en la escala temporal utilizada; por ejemplo, que haya siempre un dato por día, o dos datos por mes o un dato cada dos años. En caso de que la serie temporal a tratar esté constituida por valores irregularmente distribuidos en el tiempo deberemos utilizar objetos de la clase zoo
.
El archivo liga2013-14.csv contiene los resultados de todos los partidos de fútbol de la liga española de primera división de la temporada 2013-14. Cada fila de este archivo corresponde a un partido, y las variables gLoc
y gVis
indican el número de goles marcados, respectivamente, por el equipo local y por el equipo visitante en cada partido:
library(RCurl)
ligaCsv=getURL("http://www.dma.ulpgc.es/profesores/personal/stat/datos/liga2013-14.csv")
liga1314=read.csv2(textConnection(ligaCsv),encoding="UTF-8",stringsAsFactors=FALSE)
head(liga1314)
## jornada fecha local visitante gLoc gVis
## 1 1 18-08-2013 Barcelona Levante 7 0
## 2 1 18-08-2013 Valencia Málaga 1 0
## 3 1 18-08-2013 Real Madrid Betis 2 1
## 4 1 18-08-2013 Sevilla At. Madrid 1 3
## 5 1 18-08-2013 Real Sociedad Getafe 2 0
## 6 1 18-08-2013 Valladolid At. Bilbao 1 2
La siguiente función construye un dataframe que contiene el total de goles marcados en cada jornada de esta liga:
nMedioGoles=with(liga1314,tapply(gLoc+gVis,jornada,sum))
nMedioGoles
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
## 35 25 29 33 27 29 17 30 19 32 33 23 33 42 27 27 37 26 28 24 38 26 30 20 23
## 26 27 28 29 30 31 32 33 34 35 36 37 38
## 22 27 28 28 21 24 29 24 28 29 24 24 24
Podemos convertir la sucesión de goles marcados por jornada en una serie temporal simplemente mediante:
goles=ts(nMedioGoles)
goles
## Time Series:
## Start = 1
## End = 38
## Frequency = 1
## 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
## 35 25 29 33 27 29 17 30 19 32 33 23 33 42 27 27 37 26 28 24 38 26 30 20 23
## 26 27 28 29 30 31 32 33 34 35 36 37 38
## 22 27 28 28 21 24 29 24 28 29 24 24 24
El objeto que hemos creado, goles
, es un objeto de clase Time Series
con inicio en 1, final en 38 y frecuencia 1; en resumen, es una simple sucesión ordenada de valores. La función plot()
muestra gráficamente la secuencia temporal de observaciones de esta variable.
plot(goles,main="Goles marcados durante la liga 2013-14",xlab="Jornada",ylab="Número de goles")
grid()
Nótese que en la construcción de esta serie temporal no hemos utilizado la fecha de celebración de cada jornada; por defecto, la función ts()
cuando no se especifica ninguna opción, asume que los datos se proporcionan en una secuencia regular; en este caso es simplemente la secuencia de valores de 1 a 38 (que corresponden precisamente a las jornadas de liga). No se ha tenido en cuenta que a veces se celebran dos jornadas en la misma semana, o que la última semana de diciembre no hay jornada de fútbol.
El archivo tempMediaGando.csv contiene las temperaturas medias mensuales en el aeropuerto de Gran Canaria (Gando) desde enero de 1981 hasta diciembre de 2013. Podemos leer este archivo mediante:
gandoCsv=getURL("http://www.dma.ulpgc.es/profesores/personal/stat/datos/tempMediaGando.csv")
gando=read.csv2(textConnection(gandoCsv))
str(gando)
## 'data.frame': 396 obs. of 1 variable:
## $ temp: num 16.8 16.1 18.5 17.7 18.9 21.4 22.1 22.8 22.9 21.7 ...
Como podemos observar, el dataframe gando
contiene una única variable temp
(no hay ninguna variable de fecha). Podemos convertir esta variable a una serie temporal mediante:
tempGando=ts(gando$temp,freq=12,start=c(1981,1))
En este caso hemos especificado freq=12
, lo que indica que a cada unidad temporal le corresponden 12 observaciones; R asume entonces que la unidad temporal a considerar es el año. Además la opción start=c(1981,1)
indica que la primera observación corresponde a enero de 1981. Si pedimos a R que nos muestre la estructura de la variable tempGando
obtenemos:
str(tempGando)
## Time-Series [1:396] from 1981 to 2014: 16.8 16.1 18.5 17.7 18.9 21.4 22.1 22.8 22.9 21.7 ...
y si le pedimos que nos presente la variable:
tempGando
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 1981 16.8 16.1 18.5 17.7 18.9 21.4 22.1 22.8 22.9 21.7 21.3 18.9
## 1982 17.7 17.3 17.6 18.0 19.5 21.0 23.1 22.9 22.7 21.9 20.0 17.4
## 1983 16.9 17.0 18.3 18.7 18.9 21.9 22.5 22.9 24.4 23.9 21.0 18.9
## 1984 17.6 17.2 17.7 19.1 19.2 20.6 23.7 22.9 23.1 22.3 19.9 18.1
## 1985 16.8 17.3 17.8 18.7 18.9 22.1 22.8 24.3 24.0 22.8 20.8 18.4
## 1986 17.3 16.9 17.2 17.5 19.8 20.3 21.8 23.2 23.8 21.9 19.7 18.0
## 1987 17.5 17.8 19.2 19.8 20.4 22.3 22.9 24.2 25.8 22.3 21.3 19.3
## 1988 17.7 17.4 18.4 18.8 20.1 21.7 23.6 24.3 23.7 22.4 20.8 18.9
## 1989 17.6 18.0 18.9 18.2 20.0 22.4 24.3 25.4 24.5 23.9 20.7 19.6
## 1990 17.7 19.7 20.5 18.7 20.7 22.1 23.7 26.2 24.3 23.1 21.2 19.2
## 1991 17.6 17.0 17.9 17.9 18.9 21.0 22.7 23.3 24.3 21.6 20.2 18.5
## 1992 17.4 17.4 18.0 18.8 19.6 20.8 22.6 23.4 22.8 21.6 20.0 17.8
## 1993 16.8 16.9 17.4 17.9 19.0 20.9 22.3 22.9 22.6 21.3 18.8 18.1
## 1994 16.8 17.0 17.4 18.5 19.6 21.7 23.6 23.9 23.2 22.1 21.2 19.7
## 1995 18.1 18.5 18.8 19.5 21.2 22.3 24.3 24.3 23.8 23.5 21.8 19.4
## 1996 18.7 17.6 17.9 19.2 21.4 22.0 23.2 23.8 23.5 23.0 21.1 19.1
## 1997 18.2 19.6 20.0 20.0 20.9 22.7 23.2 23.8 23.9 23.3 22.3 20.2
## 1998 19.3 20.6 20.8 19.7 20.1 22.2 23.2 24.5 24.6 23.4 22.5 19.4
## 1999 18.1 18.0 18.7 20.1 20.9 22.2 24.1 25.6 24.6 23.0 21.2 18.6
## 2000 17.2 18.6 19.5 19.2 20.3 21.9 23.4 24.3 24.2 22.6 20.6 19.8
## 2001 18.9 18.7 20.0 19.6 20.5 22.3 23.4 24.4 24.2 23.7 20.8 20.1
## 2002 18.8 18.8 19.4 20.0 20.1 21.8 22.2 23.0 23.7 24.4 21.7 19.9
## 2003 17.7 17.3 18.5 19.0 20.8 22.2 23.6 24.4 23.9 22.3 20.0 18.7
## 2004 17.6 18.4 18.2 18.4 19.3 22.4 24.3 25.8 24.4 23.4 21.1 18.3
## 2005 16.9 16.1 18.2 19.1 20.4 21.9 23.3 24.1 24.6 23.0 20.4 18.5
## 2006 16.9 17.2 17.9 19.2 20.2 21.8 23.4 24.2 24.7 22.9 21.9 18.4
## 2007 17.8 17.7 17.8 18.8 20.7 22.0 24.1 23.3 22.9 22.6 20.8 18.8
## 2008 18.5 18.6 18.8 21.2 21.0 22.2 23.5 23.9 23.3 21.8 19.3 17.7
## 2009 16.9 16.8 18.5 18.7 20.0 22.4 25.0 24.8 23.7 23.9 22.0 20.9
## 2010 18.9 20.1 20.1 20.7 21.0 22.3 23.7 25.1 24.4 23.0 21.5 20.4
## 2011 18.4 17.8 17.7 19.2 20.9 23.1 23.4 23.8 24.0 23.5 20.7 19.4
## 2012 18.0 16.8 18.5 18.5 21.8 23.6 24.2 25.6 24.7 23.5 21.6 19.4
## 2013 18.5 18.3 19.6 20.6 20.6 21.8 23.5 25.8 24.3 23.6 21.4 19.6
Vemos, pues, que R organiza automáticamente la variable en meses y años. La representación gráfica tiene en cuenta esta secuencia temporal:
plot(tempGando,main="Temperatura media mensual en el aeropuerto de Gran Canaria", xlab="Año", ylab="Temperatura")
La función ts()
puede aplicarse también a un dataframe que contenga varias variables; en tal caso, cada variable se convierte a serie temporal, y el dataframe adquiere la clase mts
(multivariate time series). El archivo tempVientoGando.csv contiene los valores mínimo, máximo y medio mensuales de temperaturas y velocidades de viento registrados en el aeropuerto de Gran Canaria desde enero de 1981:
gandoCsv=getURL("http://www.dma.ulpgc.es/profesores/personal/stat/datos/tempVientoGando.csv")
gando2=read.csv2(textConnection(gandoCsv))
head(gando2)
## TEMP.min TEMP.max TEMP.media WIND.min WIND.max WIND.media
## 1 13 24 16.8 0 16.4 4.7
## 2 10 23 16.1 0 12.8 5.1
## 3 13 30 18.5 0 12.8 4.8
## 4 13 23 17.7 0 13.8 5.8
## 5 15 24 18.9 0 15.4 7.3
## 6 17 26 21.4 0 14.4 7.7
Podemos convertirlo a serie temporal multivariante mediante:
vtGando=ts(gando2,freq=12,start=c(1981,1))
str(vtGando)
## Time-Series [1:403, 1:6] from 1981 to 2014: 13 10 13 13 15 17 19 18 19 18 ...
## - attr(*, "dimnames")=List of 2
## ..$ : NULL
## ..$ : chr [1:6] "TEMP.min" "TEMP.max" "TEMP.media" "WIND.min" ...
vtGando
## TEMP.min TEMP.max TEMP.media WIND.min WIND.max WIND.media
## Jan 1981 13 24 16.8 0.0 16.4 4.7
## Feb 1981 10 23 16.1 0.0 12.8 5.1
## Mar 1981 13 30 18.5 0.0 12.8 4.8
## Apr 1981 13 23 17.7 0.0 13.8 5.8
## May 1981 15 24 18.9 0.0 15.4 7.3
## Jun 1981 17 26 21.4 0.0 14.4 7.7
## Jul 1981 19 31 22.1 5.1 16.9 10.1
## Aug 1981 18 32 22.8 0.0 16.9 8.5
## Sep 1981 19 28 22.9 0.0 13.8 8.1
## Oct 1981 18 25 21.7 0.0 12.3 5.6
## Nov 1981 16 28 21.3 0.0 11.8 2.9
## Dec 1981 14 24 18.9 0.0 14.4 4.7
En este caso, el comando plot()
representa gráficamente todas las series del dataframe:
plot(vtGando,main="Temperatura y Viento en el aeropuerto de Gran Canaria")
Dadas dos series temporales \(X_t\) e \(Y_t\), observadas con la misma frecuencia, si queremos combinarlas en una única serie temporal multivariante (con dos columnas, una para la \(X_t\) y otra para la \(Y_t\)) podemos utilizar las funciones:
ts.union()
: junta las dos series, rellenando con NA los periodos en que una serie sea más larga que la otra.
intersect.ts()
: junta ambas series, pero sólo con los datos correspondientes al periodo común a ambas.
Ejemplo:
serie1=ts(1:20, freq=12, start=c(1981,3))
serie2=ts(1:15, freq=12, start=c(1980,9))
serie1
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 1981 1 2 3 4 5 6 7 8 9 10
## 1982 11 12 13 14 15 16 17 18 19 20
serie2
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 1980 1 2 3 4
## 1981 5 6 7 8 9 10 11 12 13 14 15
ts.union(serie1,serie2)
## serie1 serie2
## Sep 1980 NA 1
## Oct 1980 NA 2
## Nov 1980 NA 3
## Dec 1980 NA 4
## Jan 1981 NA 5
## Feb 1981 NA 6
## Mar 1981 1 7
## Apr 1981 2 8
## May 1981 3 9
## Jun 1981 4 10
## Jul 1981 5 11
## Aug 1981 6 12
## Sep 1981 7 13
## Oct 1981 8 14
## Nov 1981 9 15
## Dec 1981 10 NA
## Jan 1982 11 NA
## Feb 1982 12 NA
## Mar 1982 13 NA
## Apr 1982 14 NA
## May 1982 15 NA
## Jun 1982 16 NA
## Jul 1982 17 NA
## Aug 1982 18 NA
## Sep 1982 19 NA
## Oct 1982 20 NA
ts.intersect(serie1,serie2)
## serie1 serie2
## Mar 1981 1 7
## Apr 1981 2 8
## May 1981 3 9
## Jun 1981 4 10
## Jul 1981 5 11
## Aug 1981 6 12
## Sep 1981 7 13
## Oct 1981 8 14
## Nov 1981 9 15
Las funciones start()
y end()
muestran, respectivamente, los instantes correspondientes a la observaciones inicial y final de una serie temporal:
start(tempGando)
## [1] 1981 1
end(tempGando)
## [1] 2013 12
La función window()
extrae los valores de la serie temporal comprendidos entre una fecha de inicio y otra final. Podemos especificar sólo el año:
window(tempGando,start=1982,end=1985)
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 1982 17.7 17.3 17.6 18.0 19.5 21.0 23.1 22.9 22.7 21.9 20.0 17.4
## 1983 16.9 17.0 18.3 18.7 18.9 21.9 22.5 22.9 24.4 23.9 21.0 18.9
## 1984 17.6 17.2 17.7 19.1 19.2 20.6 23.7 22.9 23.1 22.3 19.9 18.1
## 1985 16.8
O también año y mes:
window(tempGando,start=c(1982,1),end=c(1985,12))
## Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
## 1982 17.7 17.3 17.6 18.0 19.5 21.0 23.1 22.9 22.7 21.9 20.0 17.4
## 1983 16.9 17.0 18.3 18.7 18.9 21.9 22.5 22.9 24.4 23.9 21.0 18.9
## 1984 17.6 17.2 17.7 19.1 19.2 20.6 23.7 22.9 23.1 22.3 19.9 18.1
## 1985 16.8 17.3 17.8 18.7 18.9 22.1 22.8 24.3 24.0 22.8 20.8 18.4
La función time()
crea un objeto de clase ts
con los instantes en que ha sido muestreada una serie temporal (en escala decimal).
time(tempGando)
## Jan Feb Mar Apr May Jun Jul Aug
## 1981 1981.00 1981.08 1981.17 1981.25 1981.33 1981.42 1981.50 1981.58
## 1982 1982.00 1982.08 1982.17 1982.25 1982.33 1982.42 1982.50 1982.58
## 1983 1983.00 1983.08 1983.17 1983.25 1983.33 1983.42 1983.50 1983.58
## Sep Oct Nov Dec
## 1981 1981.67 1981.75 1981.83 1981.92
## 1982 1982.67 1982.75 1982.83 1982.92
## 1983 1983.67 1983.75 1983.83 1983.92
Estas funciones nos muestran el tiempo entre observaciones (deltat()
) y número de observaciones por unidad de tiempo (frequency()
) de una serie temporal. Así, para las temperaturas del aeropuerto de Gran Canaria, donde la unidad de tiempo es el año:
deltat(tempGando)
## [1] 0.0833333
frequency(tempGando)
## [1] 12
La función lag()
construye una versión desfasada de la serie temporal, retardando (o adelantando) los valores de la serie en la magnitud del desfase especificado. Concretamente:
\[\mathsf{lag(}X_{t},k\mathsf{)}=X_{t+k}\]
Si no se especifica, el valor del desfase \(k\) por defecto es 1.
A modo de ejemplo, mostramos seguidamente el efecto de desfasar en uno y dos meses (hacia delante y hacia atrás) la serie de temperaturas medias mensuales en el aeropuerto de Gran Canaria:
head(cbind(lag(tempGando,-2),lag(tempGando,-1), tempGando,lag(tempGando),lag(tempGando,2)))
## lag(tempGando, -2) lag(tempGando, -1) tempGando lag(tempGando) lag(tempGando, 2)
## [1,] NA NA NA NA 16.8
## [2,] NA NA NA 16.8 16.1
## [3,] NA NA 16.8 16.1 18.5
## [4,] NA 16.8 16.1 18.5 17.7
## [5,] 16.8 16.1 18.5 17.7 18.9
## [6,] 16.1 18.5 17.7 18.9 21.4
En la siguiente figura representamos gráficamente los valores de la serie desfasada una unidad (\(X_{t+k}\)), frente a los valores originales \(X_t\). Puede apreciarse una clara relación lineal:
plot(tempGando,lag(tempGando),xlab="temp.Gando(t)",ylab="temp.Gando(t+1)")
Esta función representa la serie observada frente a una versión suya desfasada lags
unidades de tiempo, por lo que permite visualizar la “autodependencia” de la serie. Concretamente, lag.plot(x,lags=k)
es equivalente a plot(lag(x,k),x)
. No obstante, la función lag.plot()
presenta algunas ventajas, como por ejemplo hacer una representación simultánea para varios desfases:
lag.plot(tempGando, main="Temperatura media mensual en el aeropuerto de Gran Canaria")
lag.plot(tempGando,lags=4,layout=c(2,2))
Diferenciar una serie temporal \(X_t\) en tiempo discreto, consiste en transformar \(X_t\) en una nueva serie \(D_{t}^{\left(1\right)}\) definida como: \[D_{t}^{\left(1\right)}=D\left(X_{t}\right)=X_{t}-X_{t-1}\]
El procedimiento de diferenciación puede volver a aplicarse sobre una serie previamente diferenciada; obtenemos así las diferencias de segundo orden: \[D_{t}^{\left(2\right)}=D\left(D_{t}^{\left(1\right)}\right)=D_{t}^{\left(1\right)}-D_{t-\text{1}}^{\left(1\right)}\]
En general, la diferencia de orden \(m\) se obtiene como: \[D_{t}^{\left(m\right)}=D\left(D_{t}^{\left(m-1\right)}\right)=D_{t}^{\left(m-1\right)}-D_{t-\text{1}}^{\left(m-1\right)}\]
En general la diferenciación es una técnica utilizada habitualmente para eliminar la tendencia en una serie temporal.
Las diferencias pueden calcularse también sobre valores de la serie separados un desfase \(k\): \[D_{t,k}^{\left(1\right)}=D\left(X_{t}\right)=X_{t}-X_{t-k}\] y, en general: \[D_{t,k}^{\left(m\right)}=D_{t}^{\left(m-1\right)}-D_{t-\text{k}}^{\left(m-1\right)}\] En series temporales mensuales la diferenciación con desfase \(k=12\) suele recibir el nombre de diferenciación estacional.
En R, la función diff()
permite diferenciar una o más veces una serie temporal. Concretamente: \[D_{t,k}^{\left(m\right)}=\mathsf{diff(}X_{t},\mathsf{lag=}k,\mathsf{order}=m\mathsf{)}\]
Por ejemplo:
dtg=diff(tempGando)
head(dtg,12)
## [1] -0.7 2.4 -0.8 1.2 2.5 0.7 0.7 0.1 -1.2 -0.4 -2.4 -1.2
plot(dtg)
dtg2=diff(tempGando,differences=2)
head(dtg2,12)
## [1] 3.10000e+00 -3.20000e+00 2.00000e+00 1.30000e+00 -1.80000e+00 -3.55271e-15
## [7] -6.00000e-01 -1.30000e+00 8.00000e-01 -2.00000e+00 1.20000e+00 8.00000e-01
plot(dtg2)
difest=diff(tempGando,lag=12)
head(difest,12)
## [1] 0.9 1.2 -0.9 0.3 0.6 -0.4 1.0 0.1 -0.2 0.2 -1.3 -1.5
plot(difest,main="Temperaturas Medias en el aeropuerto con una diferencia estacional")
difest2=diff(tempGando,lag=12, differences=2)
head(difest2,12)
## [1] -1.7 -1.5 1.6 0.4 -1.2 1.3 -1.6 -0.1 1.9 1.8 2.3 3.0
plot(difest2,main="Temperaturas Medias en el aeropuerto \ncon una diferencia estacional de segundo orden")
acf()
calcula la función de autocorrelación simple de una serie temporal, y pacf()
la función de autocorrelación parcial. En ambos casos, por defecto se muestra el gráfico con bandas de confianza al 95%.
acf(tempGando)
pacf(tempGando)
En caso de que deseáramos extraer los valores numéricos de las autocorrelaciones, simplemente asignamos el resultado de la función a una variable y la mostramos:
acfTemp=acf(tempGando, plot=FALSE)
acfTemp
##
## Autocorrelations of series 'tempGando', by lag
##
## 0.0000 0.0833 0.1667 0.2500 0.3333 0.4167 0.5000 0.5833 0.6667 0.7500 0.8333 0.9167
## 1.000 0.830 0.480 0.040 -0.388 -0.688 -0.796 -0.691 -0.393 0.022 0.446 0.768
## 1.0000 1.0833 1.1667 1.2500 1.3333 1.4167 1.5000 1.5833 1.6667 1.7500 1.8333 1.9167
## 0.886 0.758 0.429 0.008 -0.400 -0.688 -0.789 -0.679 -0.385 0.018 0.432 0.734
## 2.0000 2.0833
## 0.843 0.719
La función ccf()
calcula la correlación cruzada entre dos series temporales. En particular el valor del retardo k devuelto por ccf(X,Y)
corresponde a la correlación entre \(X_{t+k}\) e \(Y_t\).
ccf(vtGando[,"TEMP.min"],vtGando[,"TEMP.max"])
Podemos extraer los valores numéricos de las correlaciones cruzadas del mismo modo que hicimos para acf()
:
ccfTemp=ccf(vtGando[,"TEMP.min"],vtGando[,"TEMP.max"],plot=FALSE)
ccfTemp
##
## Autocorrelations of series 'X', by lag
##
## -1.9167 -1.8333 -1.7500 -1.6667 -1.5833 -1.5000 -1.4167 -1.3333 -1.2500 -1.1667 -1.0833
## 0.501 0.314 0.046 -0.241 -0.439 -0.555 -0.508 -0.334 -0.073 0.220 0.503
## -1.0000 -0.9167 -0.8333 -0.7500 -0.6667 -0.5833 -0.5000 -0.4167 -0.3333 -0.2500 -0.1667
## 0.606 0.544 0.327 0.036 -0.196 -0.415 -0.523 -0.494 -0.306 -0.010 0.312
## -0.0833 0.0000 0.0833 0.1667 0.2500 0.3333 0.4167 0.5000 0.5833 0.6667 0.7500
## 0.560 0.684 0.569 0.358 0.092 -0.200 -0.441 -0.551 -0.482 -0.303 -0.018
## 0.8333 0.9167 1.0000 1.0833 1.1667 1.2500 1.3333 1.4167 1.5000 1.5833 1.6667
## 0.282 0.508 0.595 0.530 0.301 0.033 -0.221 -0.432 -0.516 -0.468 -0.294
## 1.7500 1.8333 1.9167
## -0.003 0.280 0.498
La función spectrum()
permite estimar el espectro de una serie temporal. De no especificarse ninguna opción se obtiene el periodograma “crudo” de la serie:
spectrum(tempGando)
La opción spans
permite suavizar el periodograma:
spectrum(tempGando,spans=c(5,5))
Las funciones decompose()
y stl()
permiten descomponer una serie temporal en sus componentes estacional, de tendencia y de ruido. En el caso de decompose()
la descomposición se lleva a cabo mediante un ajuste de medias móviles, mientras que stl()
realiza la descomposición mediante una ajuste polinómico local.
decompose()
:descomp1=decompose(tempGando)
str(descomp1)
## List of 6
## $ x : Time-Series [1:396] from 1981 to 2014: 16.8 16.1 18.5 17.7 18.9 21.4 22.1 22.8 22.9 21.7 ...
## $ seasonal: Time-Series [1:396] from 1981 to 2014: -3.022 -2.915 -2.208 -1.709 -0.606 ...
## $ trend : Time-Series [1:396] from 1981 to 2014: NA NA NA NA NA ...
## $ random : Time-Series [1:396] from 1981 to 2014: NA NA NA NA NA ...
## $ figure : num [1:12] -3.022 -2.915 -2.208 -1.709 -0.606 ...
## $ type : chr "additive"
## - attr(*, "class")= chr "decomposed.ts"
plot(descomp1)
Si queremos “eliminar” la componente estacional de nuestra serie temporal, y dejar solamente la componente de tendencia y el ruido, basta con restar a la serie original la parte estacional (descomp1$seasonal
) que acabamos de calcular:
tempGandoDes=tempGando-descomp1$seasonal
plot(tempGandoDes,main="Temperaturas medias mensuales desestacionalizadas \nAeropuerto de Gran Canaria 1981-2013")
stl()
:descomp2=stl(tempGando,s.window="periodic")
str(descomp2)
## List of 8
## $ time.series: Time-Series [1:396, 1:3] from 1981 to 2014: -3.018 -2.937 -2.18 -1.722 -0.618 ...
## ..- attr(*, "dimnames")=List of 2
## .. ..$ : NULL
## .. ..$ : chr [1:3] "seasonal" "trend" "remainder"
## $ weights : num [1:396] 1 1 1 1 1 1 1 1 1 1 ...
## $ call : language stl(x = tempGando, s.window = "periodic")
## $ win : Named num [1:3] 3961 19 13
## ..- attr(*, "names")= chr [1:3] "s" "t" "l"
## $ deg : Named int [1:3] 0 1 1
## ..- attr(*, "names")= chr [1:3] "s" "t" "l"
## $ jump : Named num [1:3] 397 2 2
## ..- attr(*, "names")= chr [1:3] "s" "t" "l"
## $ inner : int 2
## $ outer : int 0
## - attr(*, "class")= chr "stl"
plot(descomp2)
Existe una amplia literatura sobre la aplicación de modelos ARIMA en series temporales. R cuenta con numerosos procedimientos para la estimación, validación y predicción con estos modelos:
El uso adecuado de algunas funciones que ya hemos visto (acf()
, pacf()
y diff()
) permite al usuario identificar posibles modelos candidatos para representar una serie temporal estacionaria.
Estos modelos pueden estimarse fácilmente en R mediante la función arima()
.
El paquete forecast
incluye la función auto.arima()
que realiza un ajuste automático de un modelo ARIMA a una serie temporal dada.
La diagnosis del modelo estimado puede llevarse a cabo mediante la función ts.diag()
.
Se pueden realizar predicciones mediante predict()
o forecast()
(esta última función en el paquete homónimo, forecast
).
Por último, señalemos que la función arima.sim()
permite simular una serie temporal de acuerdo con el modelo ARIMA especificado por el usuario.
Simulamos una serie temporal de acuerdo con un modelo ARIMA(1,1,1):
miSerie = arima.sim(list(order = c(1,1,1), ar=0.5, ma=0.6), sd=1.55, n = 730)
plot(miSerie)
Veamos ahora como podemos utilizar R para estimar un modelo ARIMA para esta serie:
La serie es obviamente no estacionaria. Sin embargo, la serie diferenciada es razonablemente estacionaria:
dms=diff(miSerie)
plot(dms)
Los correlogramas sugieren un modelo ARMA(1,1) para la serie diferenciada:
par(mfrow=c(1,2))
acf(dms)
pacf(dms)
Este modelo puede estimarse a partir de los datos mediante:
ajuste=arima(miSerie,order=c(1,1,1))
ajuste
##
## Call:
## arima(x = miSerie, order = c(1, 1, 1))
##
## Coefficients:
## ar1 ma1
## 0.488 0.620
## s.e. 0.038 0.035
##
## sigma^2 estimated as 2.51: log likelihood = -1373.08, aic = 2752.17
La función tsdiag()
muestra que no queda estructura de autocorrelación en los residuos del ajuste:
tsdiag(ajuste)
Si utilizamos la función auto.arima()
obtenemos el mismo modelo:
library(forecast)
ajuste2=auto.arima(miSerie)
ajuste2
## Series: miSerie
## ARIMA(1,1,1)
##
## Coefficients:
## ar1 ma1
## 0.488 0.620
## s.e. 0.038 0.035
##
## sigma^2 estimated as 2.52: log likelihood=-1373.08
## AIC=2752.17 AICc=2752.2 BIC=2765.94
Podemos hacer predicciones con este modelo utilizando predict()
:
predict(ajuste,n.ahead=12)
## $pred
## Time Series:
## Start = 732
## End = 743
## Frequency = 1
## [1] 32.4211 32.8502 33.0595 33.1615 33.2112 33.2355 33.2473 33.2530 33.2558 33.2572
## [11] 33.2579 33.2582
##
## $se
## Time Series:
## Start = 732
## End = 743
## Frequency = 1
## [1] 1.58584 3.70002 5.59702 7.25571 8.71125 10.00466 11.17047 12.23521 13.21879
## [10] 14.13607 14.99827 15.81395
o también forecast()
:
forecast(ajuste)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## 732 32.4211 30.3888 34.4534 29.31290 35.5293
## 733 32.8502 28.1085 37.5920 25.59834 40.1021
## 734 33.0595 25.8866 40.2323 22.08951 44.0294
## 735 33.1615 23.8629 42.4600 18.94054 47.3824
## 736 33.2112 22.0473 44.3751 16.13747 50.2849
## 737 33.2355 20.4140 46.0569 13.62667 52.8442
## 738 33.2473 18.9317 47.5628 11.35356 55.1410
## 739 33.2530 17.5730 48.9331 9.27246 57.2336
## 740 33.2558 16.3153 50.1964 7.34749 59.1642
## 741 33.2572 15.1411 51.3733 5.55102 60.9634
plot(forecast(ajuste))
Como hemos señalado más arriba, la creación de objetos de clase ts()
requiere que las observaciones estén distribuidas de modo regular a lo largo del tiempo. En caso de que no sea así, podemos utilizar objetos de la clase zoo
(el nombre de la clase deriva del apellido del autor del paquete, Zeilies Ordered Observations). Los objetos de esta clase se crean mediante la función zoo()
.
Supongamos que en nuestro primer ejemplo (partidos de la liga de fútbol española durante la temporada 2013-14) quisiéramos disponer de la sucesión del número medio de goles marcados por los equipos locales en cada jornada con su fecha concreta de celebración. Para ello:
fechasLiga=with(liga1314,tapply(fecha,jornada,unique))
fechasLiga=as.Date(fechasLiga,format="%d-%m-%Y")
nMedioGolesLocal=with(liga1314,tapply(gLoc,jornada,mean))
zoo
, especificando la variable fechasLiga
como variable de ordenación:library(zoo)
equipoLocal=zoo(nMedioGolesLocal, order.by=fechasLiga)
str(equipoLocal)
## 'zoo' series from 2013-08-18 to 2014-05-18
## Data: Named num [1:38] 2.2 1.6 1.3 2.2 1.4 2 0.7 2 0.9 1.9 ...
## - attr(*, "names")= chr [1:38] "1" "2" "3" "4" ...
## Index: Date[1:38], format: "2013-08-18" "2013-08-25" "2013-09-01" "2013-09-15" "2013-09-22" "2013-09-25" ...
Gráficamente:
plot(equipoLocal, main="Número medio de goles por partido marcados por el equipo local\nLiga 2013-14",
ylab="Goles",xlab="Mes")
Una vez que se ha definido un objeto de clase zoo
la función index()
aplicada a dicho objeto devuelve los valores de tiempo en que la serie se ha observado:
index(equipoLocal)
## [1] "2013-08-18" "2013-08-25" "2013-09-01" "2013-09-15" "2013-09-22" "2013-09-25"
## [7] "2013-09-29" "2013-10-06" "2013-10-20" "2013-10-27" "2013-10-30" "2013-11-03"
## [13] "2013-11-10" "2013-11-24" "2013-12-01" "2013-12-15" "2013-12-22" "2014-01-05"
## [19] "2014-01-12" "2014-01-19" "2014-01-26" "2014-02-02" "2014-02-09" "2014-02-16"
## [25] "2014-02-23" "2014-03-02" "2014-03-09" "2014-03-16" "2014-03-23" "2014-03-26"
## [31] "2014-03-30" "2014-04-06" "2014-04-13" "2014-04-20" "2014-04-27" "2014-05-04"
## [37] "2014-05-11" "2014-05-18"
Para combinar objetos de clase zoo
no se pueden usar ts.intersect()
o ts.union()
que solo funcionan con objetos de clase ts()
. En su lugar deberemos utilizar merge()
.
A modo de ejemplo, podemos proceder como antes para construir el número medio de goles por partido marcados ahora por los equipos visitantes en cada jornada:
nMedioGolesVisit=with(liga1314,tapply(gVis,jornada,mean))
equipoVisitante=zoo(nMedioGolesVisit, order.by=fechasLiga)
Para combinar los números medios de goles por partido marcados por los equipos locales y los visitantes en un único objeto de clase zoo
utilizamos merge
:
goles1314=merge(equipoLocal,equipoVisitante)
Podemos representar ambas series gráficamente. Por defecto se genera una gráfica para cada serie:
plot(goles1314, main="Número medio de goles por partido durante la liga 2013-14",xlab="Mes")
Si deseamos una representación conjunta en un único gráfico (que en este caso permite visualizar mejor el comportamiento conjunto de ambas series) utilizamos la opción plot.type='single'
:
plot(goles1314, main="Número medio de goles por partido durante la liga 2013-14",xlab="Mes",
ylab="Numero de goles", plot.type="single", col=c("red","blue"),lty=c(1,2))
legend("topright",title="Equipos:",legend=c("Locales","Visitantes"),col=c("red","blue"),lty=c(1,2))
Como puede apreciarse en la gráfica, en general marcan más goles los equipos locales que los visitantes.
El paquete zoo
cuenta con algunas herramientas para rellenar valores perdidos en una serie temporal. Para conocer su funcionamiento consideraremos los datos del siguiente archivo, que contiene los valores medios diarios de presión atmosférica en el aeropuerto de Gran Canaria durante el mes de junio de 2014:
PAcsv=getURL("http://www.dma.ulpgc.es/profesores/personal/stat/datos/PAtmJun14.csv")
PAjun14=read.csv2(textConnection(PAcsv),encoding="UTF-8",stringsAsFactors=FALSE)
PAjun14
## fecha presAtm
## 1 2014-06-01 1018.73
## 2 2014-06-02 1019.08
## 3 2014-06-03 1019.44
## 4 2014-06-04 1018.15
## 5 2014-06-05 NA
## 6 2014-06-06 1016.53
## 7 2014-06-07 1018.29
## 8 2014-06-08 1020.27
## 9 2014-06-09 NA
## 10 2014-06-10 1019.40
## 11 2014-06-11 1017.65
## 12 2014-06-12 1016.83
## 13 2014-06-13 1015.46
## 14 2014-06-14 NA
## 15 2014-06-15 1016.10
## 16 2014-06-16 1017.14
## 17 2014-06-17 1017.59
## 18 2014-06-18 1019.30
## 19 2014-06-19 NA
## 20 2014-06-20 1019.46
## 21 2014-06-21 1020.32
## 22 2014-06-22 1021.46
## 23 2014-06-23 1022.33
## 24 2014-06-24 NA
## 25 2014-06-25 1021.33
## 26 2014-06-26 1018.97
## 27 2014-06-27 1019.11
## 28 2014-06-28 NA
## 29 2014-06-29 1018.63
## 30 2014-06-30 1016.80
En primer lugar convertimos la presión atmosférica en un objeto de clase zoo
:
presAtm=zoo(PAjun14$presAtm,order.by=as.Date(PAjun14$fecha,format="%Y-%m-%d"))
presAtm
## 2014-06-01 2014-06-02 2014-06-03 2014-06-04 2014-06-05 2014-06-06 2014-06-07 2014-06-08
## 1018.73 1019.08 1019.44 1018.15 NA 1016.53 1018.29 1020.27
## 2014-06-09 2014-06-10 2014-06-11 2014-06-12 2014-06-13 2014-06-14 2014-06-15 2014-06-16
## NA 1019.40 1017.65 1016.83 1015.46 NA 1016.10 1017.14
## 2014-06-17 2014-06-18 2014-06-19 2014-06-20 2014-06-21 2014-06-22 2014-06-23 2014-06-24
## 1017.59 1019.30 NA 1019.46 1020.32 1021.46 1022.33 NA
## 2014-06-25 2014-06-26 2014-06-27 2014-06-28 2014-06-29 2014-06-30
## 1021.33 1018.97 1019.11 NA 1018.63 1016.80
Podemos observar que faltan algunos días (concretamente los días 5, 9, 14, 19, 24 y 28). Existen tres métodos para que zoo
impute los valores perdidos:
na.approx()
: reemplaza los valores perdidos por una interpolación lineal calculada a partir de los valores adyacentes:na.approx(presAtm)
## 2014-06-01 2014-06-02 2014-06-03 2014-06-04 2014-06-05 2014-06-06 2014-06-07 2014-06-08
## 1018.73 1019.08 1019.44 1018.15 1017.34 1016.53 1018.29 1020.27
## 2014-06-09 2014-06-10 2014-06-11 2014-06-12 2014-06-13 2014-06-14 2014-06-15 2014-06-16
## 1019.84 1019.40 1017.65 1016.83 1015.46 1015.78 1016.10 1017.14
## 2014-06-17 2014-06-18 2014-06-19 2014-06-20 2014-06-21 2014-06-22 2014-06-23 2014-06-24
## 1017.59 1019.30 1019.38 1019.46 1020.32 1021.46 1022.33 1021.83
## 2014-06-25 2014-06-26 2014-06-27 2014-06-28 2014-06-29 2014-06-30
## 1021.33 1018.97 1019.11 1018.87 1018.63 1016.80
Si se especifica la opción maxgap=n
las secuencias de NA sucesivos de longitud mayor que n
se quedan como están y no se imputan.
na.locf()
: remplaza cada valor perdido por el valor no perdido anterior más reciente; en caso de que el primer valor de la serie sea un valor perdido, dicho valor se elimina. En nuestro ejemplo:na.locf(presAtm)
## 2014-06-01 2014-06-02 2014-06-03 2014-06-04 2014-06-05 2014-06-06 2014-06-07 2014-06-08
## 1018.73 1019.08 1019.44 1018.15 1018.15 1016.53 1018.29 1020.27
## 2014-06-09 2014-06-10 2014-06-11 2014-06-12 2014-06-13 2014-06-14 2014-06-15 2014-06-16
## 1020.27 1019.40 1017.65 1016.83 1015.46 1015.46 1016.10 1017.14
## 2014-06-17 2014-06-18 2014-06-19 2014-06-20 2014-06-21 2014-06-22 2014-06-23 2014-06-24
## 1017.59 1019.30 1019.30 1019.46 1020.32 1021.46 1022.33 1022.33
## 2014-06-25 2014-06-26 2014-06-27 2014-06-28 2014-06-29 2014-06-30
## 1021.33 1018.97 1019.11 1019.11 1018.63 1016.80
Si se utiliza la opción fromLast=TRUE
, cada valor perdido se sustituye por el inmediato valor no perdido posterior. Al igual que con na.approx()
Se puede especificar también un valor maxgap
si se desea que secuencias de NA de longitud mayor que dicho valor no sean imputadas.
na.spline()
: reemplaza los valores perdidos a partir de un spline cúbico ajustado a los datos:na.spline(presAtm)
## 2014-06-01 2014-06-02 2014-06-03 2014-06-04 2014-06-05 2014-06-06 2014-06-07 2014-06-08
## 1018.73 1019.08 1019.44 1018.15 1016.70 1016.53 1018.29 1020.27
## 2014-06-09 2014-06-10 2014-06-11 2014-06-12 2014-06-13 2014-06-14 2014-06-15 2014-06-16
## 1020.61 1019.40 1017.65 1016.83 1015.46 1015.22 1016.10 1017.14
## 2014-06-17 2014-06-18 2014-06-19 2014-06-20 2014-06-21 2014-06-22 2014-06-23 2014-06-24
## 1017.59 1019.30 1019.64 1019.46 1020.32 1021.46 1022.33 1022.57
## 2014-06-25 2014-06-26 2014-06-27 2014-06-28 2014-06-29 2014-06-30
## 1021.33 1018.97 1019.11 1019.33 1018.63 1016.80
© 2016 Angelo Santana, Carmen N. Hernández, Departamento de Matemáticas ULPGC