2016-06-30 22 views
5

Voglio creare più ritardi di più variabili, quindi ho pensato di scrivere una funzione sarebbe utile. Il mio codice lancia un avvertimento ("Troncare vettore di lunghezza 1") e falsi risultati:debug: funzione per creare ritardi multipli per più colonne (dplyr)

library(dplyr) 
time <- c(2000:2009, 2000:2009) 
x <- c(1:10, 10:19) 
id <- c(1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2) 
df <- data.frame(id, time, x) 



three_lags <- function (data, column, group, ordervar) { 
    data <- data %>% 
    group_by_(group) %>% 
    mutate(a = lag(column, 1L, NA, order_by = ordervar), 
      b = lag(column, 2L, NA, order_by = ordervar), 
      c = lag(column, 3L, NA, order_by = ordervar)) 
    } 

df_lags <- three_lags(data=df, column=x, group=id, ordervar=time) %>% 
    arrange(id, time) 

Inoltre mi sono chiesto se ci potrebbe essere una soluzione più elegante utilizzando mutate_each, ma non ho avuto quello per funzionare neanche. Naturalmente posso semplicemente scrivere un lungo codice con una linea per ogni nuova variabile ritardata, ma Id mi piace evitarlo.

EDIT: risposta dplyr

di akrun funziona, ma richiede molto tempo per calcolare per grandi frame di dati. La soluzione che utilizza data.table sembra essere più efficiente. Quindi un dplyr o un'altra soluzione che consente anche l'implementazione per più colonne & diversi ritardi deve ancora essere trovato.

EDIT 2:

Per più colonne e gruppi (ad esempio "ID") la seguente soluzione sembra molto adatta a me, grazie alla sua semplicità. Il codice può ovviamente essere abbreviato, ma passo dopo passo:

df <- arrange(df, time) 

df.lag <- shift(df[,1:24], n=1:3, give.names = T) ##column indexes of columns to be lagged as "[,startcol:endcol]", "n=1:3" sepcifies the number of lags (lag1, lag2 and lag3 in this case) 

df.result <- bind_cols(df, df.lag) 
+0

Funziona perfettamente! Devo solo leggere su 'data.table' per essere in grado di manipolarlo correttamente e pensato per gli altri che - come me - non sono programmatori molto esperti. Le soluzioni' dplyr' sono più facili da comprendere – yoland

+0

Ho aggiornato con 'data. table' solution nel caso in cui ci siano molte colonne che vuoi fare 'shift' – akrun

risposta

4

possiamo usare shift da data.table che può assumere valori multipli per 'n'

library(data.table) 
setDT(df)[order(time), c("a", "b", "c") := shift(x, 1:3) , id][order(id, time)] 

Supponiamo, abbiamo bisogno di fare questo su più colonne

df$y <- df$x 
setDT(df)[order(time), paste0(rep(c("x", "y"), each =3), 
       c("a", "b", "c")) :=shift(.SD, 1:3), id, .SDcols = x:y] 

Il shift possono essere utilizzati anche in t egli dplyr

library(dplyr) 
df %>% 
    group_by(id) %>% 
    arrange(id, time) %>% 
    do(data.frame(., setNames(shift(.$x, 1:3), c("a", "b", "c")))) 
# id time  x  a  b  c 
# <dbl> <int> <int> <int> <int> <int> 
#1  1 2000  1 NA NA NA 
#2  1 2001  2  1 NA NA 
#3  1 2002  3  2  1 NA 
#4  1 2003  4  3  2  1 
#5  1 2004  5  4  3  2 
#6  1 2005  6  5  4  3 
#7  1 2006  7  6  5  4 
#8  1 2007  8  7  6  5 
#9  1 2008  9  8  7  6 
#10  1 2009 10  9  8  7 
#11  2 2000 10 NA NA NA 
#12  2 2001 11 10 NA NA 
#13  2 2002 12 11 10 NA 
#14  2 2003 13 12 11 10 
#15  2 2004 14 13 12 11 
#16  2 2005 15 14 13 12 
#17  2 2006 16 15 14 13 
#18  2 2007 17 16 15 14 
#19  2 2008 18 17 16 15 
#20  2 2009 19 18 17 16 
+1

Grazie, funziona ed è chiaramente più efficiente! Lascio la domanda aperta per ora – yoland

+0

Il codice dplyr produce 6 colonne invece di 3, nonostante questo abbia il vantaggio di assegnare nomi sensibili alle nuove colonne – yoland

+0

@yoland Fornisce solo 3 colonne. Si prega di verificare se si sta utilizzando il set di dati originale o quello dopo il 'data.table' convertito uno. – akrun

Problemi correlati