Retard sur une série chronologique groupée

10

J'ai quelques dizaines de milliers d'observations qui sont dans une série chronologique mais regroupées par emplacements. Par exemple:

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

Je veux voir si le mois x l » observationAa une relation linéaire avec le mois x +1 observationB.

J'ai fait quelques recherches et trouvé une zoofonction, mais elle ne semble pas avoir un moyen de limiter le décalage par groupe. Donc , si je zoo et avec décalage observationBpar 1 rang, je finirais l'emplacement A ce dernier observationBque l' emplacement B premier observationB. Je préfère avoir le premier observationBde n'importe quel emplacement NAou une autre valeur évidente pour indiquer "ne touchez pas cette ligne".

Je suppose que ce que je veux en venir est de savoir s'il existe une manière intégrée de faire cela dans R? Sinon, j'imagine que je peux y arriver avec une construction de boucle standard. Ou dois-je même manipuler les données?

Aren Cambre
la source

Réponses:

23

Il existe plusieurs façons d'obtenir une variable retardée au sein d'un groupe. Tout d'abord, vous devez trier les données, de sorte que dans chaque groupe, l'heure soit triée en conséquence.

Créons d'abord un exemple de 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

Définissez notre fonction de décalage:

 lg <- function(x)c(NA, x[1:(length(x)-1)])
  1. Ensuite, le décalage de la variable au sein du groupe peut être calculé en utilisant 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. Utilisation ddplydu package 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. Version plus rapide à l'aide data.tabledu 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. Utilisation de la lagfonction du package 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. Utilisation de la lagfonction du package 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
    

Les deux dernières approches nécessitent une conversion de data.framevers un autre objet, bien que vous n'ayez pas à vous soucier du tri. Ma préférence personnelle est la dernière, qui n'était pas disponible lors de la rédaction initiale de la réponse.

Mise à jour: modification du code data.table pour refléter les développements du package data.table, signalés par @Hibernating.

Mise à jour 2: ajout de l' exemple dplyr .

mpiktas
la source
Grande explication! Existe-t-il un ensemble / une fonction qui peut traiter des séries chronologiques groupées (panneaux) irrégulièrement espacées et des panneaux non équilibrés?
Helix123
Tous les exemples de code fonctionneraient pour les panneaux non équilibrés. Pour les séries temporelles irrégulièrement espacées, le concept de décalage est un peu compliqué, car il peut ne pas exister pour tous les groupes.
mpiktas
Vous pouvez demander des décalages pour les séries chronologiques irrégulières dans stackoverflow. Ces types de questions sont désormais hors sujet dans stats.SE.
mpiktas
2

@ mpiktas Juste pour mentionner brièvement deux petits oublis dans la version 3 de votre réponse. Premièrement, l'expression "version plus rapide" a clairement été laissée par erreur. Deuxièmement, le mot ": =" a été omis dans le code. La fixation de ce dernier corrige le premier: =)

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

entrez la description de l'image ici

Hibernation
la source
2

Plutôt que de passer par toutes les tapplyétapes supplémentaires, voici un moyen plus rapide:

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
la source
2

Avec dplyr

dt %>% group_by(location) %>% mutate(lvar=lag(var))
Matthieu
la source
0

Avec DataCombine:

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

Les données doivent également être triées. Utilisez slideBy=-1plutôt pour les retards.

kitsune
la source