Atrasando uma série temporal agrupada

10

Eu tenho algumas dezenas de milhares de observações que estão em uma série temporal, mas agrupadas por locais. Por exemplo:

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

Eu quero ver se mês x 's observationAtem qualquer relação linear com o mês x + 1s observationB.

Eu pesquisei e encontrei uma zoofunção, mas não parece haver uma maneira de limitar o atraso por grupo. Então, se eu usei zoológico e ficado observationBpor 1 linha, eu ia acabar com a localização de A última observationBcomo a localização B da primeira observationB. Prefiro que o primeiro observationBde qualquer local seja NAou algum outro valor óbvio para indicar "não toque nesta linha".

Eu acho que o que estou dizendo é se existe uma maneira interna de fazer isso no R? Caso contrário, imagino que posso fazer isso com uma construção de loop padrão. Ou preciso mesmo manipular os dados?

Aren Cambre
fonte

Respostas:

23

Existem várias maneiras de obter uma variável atrasada dentro de um grupo. Primeiro, você deve classificar os dados, para que em cada grupo o tempo seja classificado de acordo.

Primeiro, vamos criar uma amostra data.frame:

> 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 nossa função de atraso:

 lg <- function(x)c(NA, x[1:(length(x)-1)])
  1. Em seguida, o atraso da variável dentro do grupo pode ser calculado 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 ddplydo pacote 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. Versão mais rápida usando data.tablefrom package 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 a lagfunção do pacote 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 a lagfunção do pacote 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

As duas últimas abordagens requerem conversão de data.framepara outro objeto, embora você não precise se preocupar com a classificação. Minha preferência pessoal é a última, que não estava disponível ao escrever a resposta inicialmente.

Atualização: o código data.table foi alterado para refletir os desenvolvimentos do pacote data.table, apontado por @Hibernating.

Atualização 2: Exemplo de dplyr adicionado .

mpiktas
fonte
Ótima explicação! Existe um pacote / função que possa lidar com séries temporais agrupadas com espaçamento irregular (painéis) e painéis desequilibrados?
Helix123
Todos os exemplos de código funcionariam para painéis desequilibrados. Para séries temporais com espaçamento irregular, o conceito de atraso é um pouco complicado, pois pode não existir para todos os grupos.
mpiktas
Você pode perguntar sobre atrasos para séries temporais irregulares no stackoverflow. Esses tipos de perguntas agora estão fora do tópico em stats.SE.
mpiktas
2

@ mpiktas Apenas para mencionar brevemente dois pequenos descuidos na versão 3 da sua resposta. Em primeiro lugar, a frase "versão mais rápida" foi claramente deixada por erro. Em segundo lugar, a palavra ": =" foi perdida no código. A fixação do último corrige o anterior: =)

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))

insira a descrição da imagem aqui

Hibernando
fonte
2

Em vez de seguir todas as tapplyetapas adicionais, eis uma maneira mais 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
fonte
2

Com dplyr

dt %>% group_by(location) %>% mutate(lvar=lag(var))
Mateus
fonte
0

Com o DataCombine:

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

Os dados também precisam ser classificados. Use em slideBy=-1vez disso para atrasos.

kitsune
fonte