R создать рекурсивную переменную по группам в data.table - PullRequest
0 голосов
/ 09 ноября 2018

У меня есть data.table, как это (за исключением того, что у меня есть еще много наблюдений):

name  id       time start rate payment
Anna 100 2000-01-01   100    4      15
Anna 100 2000-02-01   100    4      20
Anna 100 2000-03-01   100    4      25
Jenny 250 2008-01-01   200    5      10
Jenny 250 2008-02-01   200    5      20
Jenny 250 2008-03-01   200    5      30
Jenny 250 2008-04-01   200    5      35

Я хотел бы создать новую переменную с именем, например, new_var по группе (name, id), которая будет равна start переменной для первого наблюдения в каждой (name, id) группе, а затем будет равна ее предыдущему значению умножается на (1 + rate) минус payment. То есть для name = Анна и id = 100, new_var[1] = 100, new_var[2] = 100 * (1 + 4) -20 = 480 и new_var[3] = 480 * (1 + 4) - 25 = 2375, где 480 - значение new_var[2]. Поэтому весь data.table с этой новой переменной будет выглядеть так:

name  id       time start rate payment new_var
Anna 100 2000-01-01   100    4      15     100
Anna 100 2000-02-01   100    4      20     480
Anna 100 2000-03-01   100    4      25    2375
Jenny 250 2008-01-01   200    5      10     200
Jenny 250 2008-02-01   200    5      20    1180
Jenny 250 2008-03-01   200    5      30    7050
Jenny 250 2008-04-01   200    5      35   42265

Можно ли как-то этого добиться, желательно без петли?

Ответы [ 2 ]

0 голосов
/ 09 ноября 2018

Я немного устала от численных подходов, но для некоторого разнообразия.

> aTbl[, start := as.numeric(start)]
> aTbl[, end := start]
> aTbl[, rowid := rowid(name, id)]
> aTbl
    name  id       time start rate payment end rowid
1:  Anna 100 2000-01-01   100    4      15 100     1
2:  Anna 100 2000-02-01   100    4      20 100     2
3:  Anna 100 2000-03-01   100    4      25 100     3
4: Jenny 250 2008-01-01   200    5      10 200     1
5: Jenny 250 2008-02-01   200    5      20 200     2
6: Jenny 250 2008-03-01   200    5      30 200     3
7: Jenny 250 2008-04-01   200    5      35 200     4

> for (i in c(1:250)) {
          aTbl[, endPrev := shift(end)]
          aTbl[rowid == 1, endPrev := NA]
          aTbl[, endNew := endPrev * (1 + rate) - payment]
          aTbl[, end :=  end + .1 * (endNew - end)]
          aTbl[is.na(end), end := start]
          aTbl
  }

> aTbl[, endNew := NULL]
> aTbl[, endPrev := NULL]
> setnames(aTbl, 'end', 'new_var')
> aTbl[, rowid := NULL]

> aTbl
    name  id       time start rate payment new_var
1:  Anna 100 2000-01-01   100    4      15     100
2:  Anna 100 2000-02-01   100    4      20     480
3:  Anna 100 2000-03-01   100    4      25    2375
4: Jenny 250 2008-01-01   200    5      10     200
5: Jenny 250 2008-02-01   200    5      20    1180
6: Jenny 250 2008-03-01   200    5      30    7050
7: Jenny 250 2008-04-01   200    5      35   42265
>
0 голосов
/ 09 ноября 2018

Я не знаю, как избежать цикла, но вы можете использовать его внутри data.table, и я думаю, что он все равно будет эффективен:

### DT re-created with the following code
DT <- data.table(
        name = c("Anna","Anna","Anna","Jenny","Jenny","Jenny","Jenny"),
        id = c(100L,100L,100L,250L,250L,250L,250L), 
        time = as.Date(c("2000-01-01","2000-02-01","2000-03-01","2008-01-01","2008-02-01",
                         "2008-03-01","2008-04-01")),
        start = c(100,100,100,200,200,200,200), 
        rate = c(4,4,4,5,5,5,5),
        payment = c(15,20,25,10,20,30,35))
###

computeNewVar <- function(subDT){
  v <- subDT$start
  if(nrow(subDT)>1){
    for(i in 2:nrow(subDT)){
      v[i] <- v[i-1] * (1+subDT$rate[i]) - subDT$payment[i]
    }
  }
  v
}

DT[,new_var:=computeNewVar(.SD),by=.(name,id)]

Результат:

> DT
    name  id       time start rate payment new_var
1:  Anna 100 2000-01-01   100    4      15     100
2:  Anna 100 2000-02-01   100    4      20     480
3:  Anna 100 2000-03-01   100    4      25    2375
4: Jenny 250 2008-01-01   200    5      10     200
5: Jenny 250 2008-02-01   200    5      20    1180
6: Jenny 250 2008-03-01   200    5      30    7050
7: Jenny 250 2008-04-01   200    5      35   42265
...