2014-09-03 3 views
10

Я хотел бы создать переменную, содержащую значение переменной в предыдущем году в группе.Создайте переменную с запаздыванием в данных несбалансированной панели в R

 id date  value 
1  1 1992   4.1 
2  1  NA   4.5 
3  1 1991   3.3 
4  1 1990   5.3 
5  1 1994   3.0 
6  2 1992   3.2 
7  2 1991   5.2 

value_lagged должны отсутствовать, когда в прошлом году отсутствует в группе - либо потому, что это первая дата в пределах группы (как в строке 4, 7), или потому, что существуют пробелы в год в данных (как в строке 5). Кроме того, value_lagged должно отсутствовать, когда отсутствует текущее время (как в строке 2).

Это дает:

 id date value value_lagged 
1  1 1992  4.1    3.3 
2  1  NA  4.5    NA 
3  1 1991  3.3    5.3 
4  1 1990  5.3    NA 
5  1 1994  3.0    NA 
6  2 1992  3.2    5.2 
7  2 1991  5.2    NA 

В настоящем время, в R, я использую data.table пакет

DT = data.table(id = c(1,1,1,1,1,2,2), 
       date = c(1992,NA,1991,1990,1994,1992,1991), 
       value = c(4.1,4.5,3.3,5.3,3.0,3.2,5.2) 
       ) 
setkey(DT, id, date) 
DT[, value_lagged := DT[J(id, date-1), value], ] 
DT[is.na(date), value_lagged := NA, ] 

Это быстро, но это, кажется, несколько ошибки склонной ко мне. Я хотел бы знать, есть ли лучшие альтернативы, используя data.table, dplyr или любой другой пакет. Большое спасибо!


В Stata, можно было бы сделать:

tsset id date 
    gen value_lagged=L.value 
+0

Если вы специально не хотите, чтобы строки с отсутствующим ** значением ** не имели соответствующего запаздывающего значения, вы, вероятно, хотели использовать 'is.na (date)' not 'is.na (значение)' –

+0

yes, corrected , Благодарю. – Matthew

+0

@Matthew кажется, что у вас уже есть достойное решение - что именно вы хотите улучшить? – eddi

ответ

6

Использование функции tlagв группах определенных id

tlag <- function(x, n = 1L, time) { 
    index <- match(time - n, time, incomparables = NA) 
    x[index] 
} 

df %>% group_by(id) %>% mutate(value_lagged = tlag(value, 1, time = date)) 
+0

'N = 2e6L' довольно мало. 0.1 против 0,23 секунды не так уж впечатляет. Не могли бы вы попробовать «2e7L» или даже «2e8L»? – Arun

+0

Это не впечатляет. Дело в том, что действительно нужно иметь более читаемое решение, и оказывается, что нет стоимости производительности на 2e6. Я только что запустил тест: отставание все еще * немного * быстрее на 1e7, но чистая data.table в два раза быстрее на 1e8 – Matthew

+1

Проблема с * читабельностью * заключается в том, что она не является надлежащей мерой; варьируется от одного к другому. Я очень люблю чистое решение data.table, например :). – Arun

7

я бы, вероятно, решить это с помощью объединения:

library(dplyr) 

df <- data.frame(
    id = c(1, 1, 1, 1, 1, 2, 2), 
    date = c(1992, NA, 1991, 1990, 1994, 1992, 1991), 
    value = c(4.1, 4.5, 3.3, 5.3, 3.0, 3.2, 5.2) 
) 


last_year <- df %>% 
    filter(!is.na(date)) %>% 
    mutate(date = date + 1, lagged_value = value, value = NULL) 

df %>% 
    left_join(last_year) 
#> Joining by: c("id", "date") 
#> id date value lagged_value 
#> 1 1 1992 4.1   3.3 
#> 2 1 NA 4.5   NA 
#> 3 1 1991 3.3   5.3 
#> 4 1 1990 5.3   NA 
#> 5 1 1994 3.0   NA 
#> 6 2 1992 3.2   5.2 
#> 7 2 1991 5.2   NA 
3

Использование 1.9.5, где присоединяется не нужны ключи, которые будут установлены, это может быть сделано следующим образом:

require(data.table) # v1.9.5+ 
DT[!is.na(date), value_lagged := 
     .SD[.(id = id, date = date - 1), value, on = c("id", "date")]] 
# id date value value_lagged 
# 1: 1 1992 4.1   3.3 
# 2: 1 NA 4.5   NA 
# 3: 1 1991 3.3   5.3 
# 4: 1 1990 5.3   NA 
# 5: 1 1994 3.0   NA 
# 6: 2 1992 3.2   5.2 
# 7: 2 1991 5.2   NA 

Это изменение вашей идеи. Хитрость заключается в том, чтобы использовать is.na() непосредственно в i и использовать .SD в j вместо DT. Я использовал on= синтаксис, но эту же идею, конечно же, можно сделать, установив ключи. ,

+0

Привет! С data.table 1.9.5, установленным 11-sep-2015, это дает ошибку «Ошибка в' .data.table' (.SD,. (Id = id, date = date - 1), value, on = c ("id",: unused argument (on = c ("id", "date")) " – JBJ

+0

@JBJ Используйте' remove.packages() 'для удаления, повторной установки и повторной попытки. – Arun