Retrasado en una serie de tiempo agrupada

10

Tengo unas pocas decenas de miles de observaciones que están en una serie temporal pero agrupadas por ubicaciones. Por ejemplo:

location date     observationA observationB
---------------------------------------
 A       1-2010   22           12
 A       2-2010   26           15
 A       3-2010   45           16
 A       4-2010   46           27
 B       1-2010   167          48
 B       2-2010   134          56
 B       3-2010   201          53
 B       4-2010   207          42

Quiero ver si mes x 's observationAtiene ninguna relación lineal con el mes x +1 observationB.

Investigué un poco y encontré una zoofunción, pero no parece tener una forma de limitar el retraso por grupo. Entonces, si utilicé el zoológico y me retrasé observationB1 fila, terminaría con la última ubicación de A observationBcomo la ubicación de B primero observationB. Prefiero tener el primero observationBde cualquier ubicación NAo algún otro valor obvio para indicar "no toque esta fila".

Supongo que lo que quiero decir es si hay una forma integrada de hacer esto en R? Si no, imagino que puedo hacer esto con una construcción de bucle estándar. ¿O incluso necesito manipular los datos?

Aren Cambre
fuente

Respuestas:

23

Hay varias formas de obtener una variable retrasada dentro de un grupo. En primer lugar, debe ordenar los datos, de modo que en cada grupo el tiempo se ordene en consecuencia.

Primero, creemos un data.frame de muestra:

> set.seed(13)
> dt <- data.frame(location = rep(letters[1:2], each = 4), time = rep(1:4, 2), var = rnorm(8))
> dt
  location time        var
1        a    1  0.5543269
2        a    2 -0.2802719
3        a    3  1.7751634
4        a    4  0.1873201
5        b    1  1.1425261
6        b    2  0.4155261
7        b    3  1.2295066
8        b    4  0.2366797

Defina nuestra función de retraso:

 lg <- function(x)c(NA, x[1:(length(x)-1)])
  1. Luego, el retraso de la variable dentro del grupo se puede calcular usando tapply:

     > unlist(tapply(dt$var, dt$location, lg))
        a1         a2         a3         a4         b1         b2         b3         b4 
        NA  0.5543269 -0.2802719  1.7751634         NA  1.1425261  0.4155261  1.2295066
  2. Usando el ddplypaquete plyr :

    > ddply(dt, ~location, transform, lvar = lg(var))
      location time        var       lvar
    1        a    1 -0.1307015         NA
    2        a    2 -0.6365957 -0.1307015
    3        a    3 -0.6417577 -0.6365957
    4        a    4 -1.5191950 -0.6417577
    5        b    1 -1.6281638         NA
    6        b    2  0.8748671 -1.6281638
    7        b    3 -1.3343222  0.8748671
    8        b    4  1.5431753 -1.3343222  
  3. Versión más rápida usando data.tabledesde el paquete data.table

     > ddt <- data.table(dt)
     > ddt[,lvar := lg(var), by = c("location")]
         location time        var       lvar
    [1,]        a    1 -0.1307015         NA
    [2,]        a    2 -0.6365957 -0.1307015
    [3,]        a    3 -0.6417577 -0.6365957
    [4,]        a    4 -1.5191950 -0.6417577
    [5,]        b    1 -1.6281638         NA
    [6,]        b    2  0.8748671 -1.6281638
    [7,]        b    3 -1.3343222  0.8748671
    [8,]        b    4  1.5431753 -1.3343222
  4. Usando la lagfunción del paquete plm

     > pdt <- pdata.frame(dt)
     > lag(pdt$var)
       a-1        a-2        a-3        a-4        b-1        b-2        b-3        b-4 
        NA  0.5543269 -0.2802719  1.7751634         NA  1.1425261  0.4155261  1.2295066
  5. Usando la lagfunción del paquete dplyr

    > dt %>% group_by(location) %>% mutate(lvar = lag(var))        
    Source: local data frame [8 x 4]
    Groups: location        
      location time        var       lvar
    1        a    1  0.5543269         NA
    2        a    2 -0.2802719  0.5543269
    3        a    3  1.7751634 -0.2802719
    4        a    4  0.1873201  1.7751634
    5        b    1  1.1425261         NA
    6        b    2  0.4155261  1.1425261
    7        b    3  1.2295066  0.4155261
    8        b    4  0.2366797  1.2295066

Los dos últimos enfoques requieren la conversión de data.framea otro objeto, aunque no es necesario preocuparse por la clasificación. Mi preferencia personal es la última, que no estaba disponible al escribir la respuesta inicialmente.

Actualización: se modificó el código data.table para reflejar los desarrollos del paquete data.table, señalado por @Hibernating.

Actualización 2: ejemplo de dplyr agregado .

mpiktas
fuente
¡Gran explicación! ¿Existe un paquete / función que pueda tratar con series de tiempo agrupadas (paneles) y paneles no balanceados espaciados irregularmente?
Helix123
Todos los ejemplos de código funcionarían para paneles no balanceados. Para series temporales espaciadas irregularmente, el concepto de retraso es un poco complicado, ya que puede no existir para todos los grupos.
mpiktas
Puede preguntar sobre los retrasos para series temporales irregulares en stackoverflow. Este tipo de preguntas ahora están fuera de tema en las estadísticas. SE.
mpiktas
2

@ mpiktas Solo para mencionar brevemente dos pequeños descuidos en la versión 3 de su respuesta. En primer lugar, la frase "versión más rápida" claramente se ha dejado por error. En segundo lugar, la palabra ": =" se ha perdido en el código. Arreglar el último arregla el primero: =)

library(data.table);ddt <- data.table(dt)
f0<-function() plyr::ddply(dt,~location,transform,lvar=lg(var))
f1<-function() ddt[,transform(.SD,lvar=lg(var)),by=c("location")]
f2<-function() ddt[,lvar:=lg(var),by=location]
r0<-f0();r1<-f1();r2<-f2();all.equal(r0,r1,r2,check.attributes = FALSE)
boxplot(microbenchmark::microbenchmark(f0(),f1(),f2(),times=1000L))

ingrese la descripción de la imagen aquí

Hibernando
fuente
2

En lugar de seguir todos los tapplypasos adicionales, aquí hay una forma más rápida:

dt<-data.frame(location=rep(letters[1:2],each=4),time=rep(1:4,2),var=rnorm(8))
lg<-function(x)c(NA,x[1:(length(x)-1)])
dt$lg <- ave(dt$var, dt$location, FUN=lg)
Anirban Sengupta
fuente
2

Con dplyr

dt %>% group_by(location) %>% mutate(lvar=lag(var))
Mateo
fuente
0

Con DataCombine:

library(DataCombine)
slide(df, Var="observationB", TimeVar="date", GroupVar="location", NewVar="lead.observationB", 
slideBy = 1, keepInvalid = FALSE, reminder = FALSE)

Los datos también deben ordenarse. Use en slideBy=-1cambio para retrasos.

kitsune
fuente