R中的保留和滞后功能为SAS

时间:2013-12-17 14:35:48

标签: r data.table

我在R中寻找一个类似于SAS中的lag1lag2retain函数的函数,我可以将它与data.tables一起使用。

我知道R中有embedlag等函数,但它们不会返回单个值或前一个值。它们返回一组完整的向量。

R中有什么东西我可以用data.table吗?

有关SAS功能的更多信息:

4 个答案:

答案 0 :(得分:9)

您必须意识到R的工作方式与SAS中的数据步骤非常不同。 SAS中的lag函数用于数据步骤,并在 中使用该数据步骤的隐式循环结构。 retain函数也是如此,它只是在进行数据循环时保持值不变。

另一方面,R完全矢量化。这意味着您必须重新考虑您想要做的事情,并相应地进行调整。

  • retain在R中简直无用,因为R默认循环参数。如果你想明确地这样做,你可以看看例如rep()来构造一个具有常数值和一定长度的向量。
  • lag是使用索引的问题,只是在向量中移动所有值的位置。为了保持相同长度的向量,您需要添加一些NA并删除一些额外的值。

一个简单示例:此SAS代码滞后于变量x并添加具有常量值的变量year

data one;
   retain year 2013;
   input x @@;
   y=lag1(x);
   z=lag2(x);
   datalines;
1 2 3 4 5 6
;

在R中,您可以编写自己的滞后函数,如下所示:

mylag <- function(x,k) c(rep(NA,k),head(x,-k))

此单行在向量的开头添加k倍NA,并从向量中删除最后的k个值。结果是由SAS中的lag1等给出的滞后向量。

这允许类似:

nrs <- 1:6 # equivalent to datalines
one <- data.frame(
   x = nrs,
   y = mylag(nrs,1),
   z = mylag(nrs,2),
   year = 2013  # R automatically loops, so no extra command needed
)

结果是:

> one
  x  y  z year
1 1 NA NA 2013
2 2  1 NA 2013
3 3  2  1 2013
4 4  3  2 2013
5 5  4  3 2013
6 6  5  4 2013

data.table对象完全相同。这里重要的注意事项是重新思考你的策略:不要像使用SAS中的DATA步骤那样循环思考,而是在使用R时必须开始考虑向量和索引。

答案 1 :(得分:3)

我会说相当于retainlag1lag2的衣柜将是Lag function中的quantmod package

使用data.tables非常容易。 E.g:

library(data.table)
library(quantmod)
d <- data.table(v1=c(rep('a', 10), rep('b', 10)), v2=1:20)
setkeyv(d, 'v1')
d[,new_var := Lag(v2, 1), by='v1']
d[,new_var2 := v2-Lag(v2, 3), by='v1']
d[,new_var3 := Next(v2, 2), by='v1']

这产生以下结果:

print(d)
    v1 v2 new_var new_var2 new_var3
 1:  a  1      NA       NA        3
 2:  a  2       1       NA        4
 3:  a  3       2       NA        5
 4:  a  4       3        3        6
 5:  a  5       4        3        7
 6:  a  6       5        3        8
 7:  a  7       6        3        9
 8:  a  8       7        3       10
 9:  a  9       8        3       NA
10:  a 10       9        3       NA
11:  b 11      NA       NA       13
12:  b 12      11       NA       14
13:  b 13      12       NA       15
14:  b 14      13        3       16
15:  b 15      14        3       17
16:  b 16      15        3       18
17:  b 17      16        3       19
18:  b 18      17        3       20
19:  b 19      18        3       NA
20:  b 20      19        3       NA

正如您所看到的,Lag可让您回顾过去,Next可让您向前看。这两个函数都很好,因为它们使用NA填充结果,使其具有与输入相同的长度。

如果您希望获得更高级,更高性能,则可以查看与data.table对象的滚动连接。这与你所要求的有点不同,但在概念上是相关的,而且我必须分享这么强大和令人敬畏。

从data.table开始:

library(data.table)
library(quantmod)
set.seed(42)
d1 <- data.table(
    id=c(rep('a', 10), rep('b', 10)), 
    time=rep(1:10,2), 
    value=runif(20))
setkeyv(d1, c('id', 'time'))
print(d1)

    id time     value
 1:  a    1 0.9148060
 2:  a    2 0.9370754
 3:  a    3 0.2861395
 4:  a    4 0.8304476
 5:  a    5 0.6417455
 6:  a    6 0.5190959
 7:  a    7 0.7365883
 8:  a    8 0.1346666
 9:  a    9 0.6569923
10:  a   10 0.7050648
11:  b    1 0.4577418
12:  b    2 0.7191123
13:  b    3 0.9346722
14:  b    4 0.2554288
15:  b    5 0.4622928
16:  b    6 0.9400145
17:  b    7 0.9782264
18:  b    8 0.1174874
19:  b    9 0.4749971
20:  b   10 0.5603327

您要加入另一个data.table,但并非所有时间索引都出现在第二个表中:

d2 <- data.table(
        id=sample(c('a', 'b'), 5, replace=TRUE), 
        time=sample(1:10, 5), 
        value2=runif(5))
setkeyv(d2, c('id', 'time'))
print(d2)
   id time      value2
1:  a    4 0.811055141
2:  a   10 0.003948339
3:  b    6 0.737595618
4:  b    8 0.388108283
5:  b    9 0.685169729

定期合并会产生大量缺失值:

d2[d1,,roll=FALSE]
    id time      value2     value
 1:  a    1          NA 0.9148060
 2:  a    2          NA 0.9370754
 3:  a    3          NA 0.2861395
 4:  a    4 0.811055141 0.8304476
 5:  a    5          NA 0.6417455
 6:  a    6          NA 0.5190959
 7:  a    7          NA 0.7365883
 8:  a    8          NA 0.1346666
 9:  a    9          NA 0.6569923
10:  a   10 0.003948339 0.7050648
11:  b    1          NA 0.4577418
12:  b    2          NA 0.7191123
13:  b    3          NA 0.9346722
14:  b    4          NA 0.2554288
15:  b    5          NA 0.4622928
16:  b    6 0.737595618 0.9400145
17:  b    7          NA 0.9782264
18:  b    8 0.388108283 0.1174874
19:  b    9 0.685169729 0.4749971
20:  b   10          NA 0.5603327

但是,data.table允许您在主要索引中向前滚动二级索引!

d2[d1,,roll=TRUE]
    id time      value2     value
 1:  a    1          NA 0.9148060
 2:  a    2          NA 0.9370754
 3:  a    3          NA 0.2861395
 4:  a    4 0.811055141 0.8304476
 5:  a    5 0.811055141 0.6417455
 6:  a    6 0.811055141 0.5190959
 7:  a    7 0.811055141 0.7365883
 8:  a    8 0.811055141 0.1346666
 9:  a    9 0.811055141 0.6569923
10:  a   10 0.003948339 0.7050648
11:  b    1          NA 0.4577418
12:  b    2          NA 0.7191123
13:  b    3          NA 0.9346722
14:  b    4          NA 0.2554288
15:  b    5          NA 0.4622928
16:  b    6 0.737595618 0.9400145
17:  b    7 0.737595618 0.9782264
18:  b    8 0.388108283 0.1174874
19:  b    9 0.685169729 0.4749971
20:  b   10 0.685169729 0.5603327

这非常酷:旧的观察结果及时推进,直到它们被新的观察取代。如果要在系列的开始处替换NA值,可以通过向后滚动第一个观察点来实现:

d2[d1,,roll=TRUE, rollends=c(TRUE, TRUE)]
    id time      value2     value
 1:  a    1 0.811055141 0.9148060
 2:  a    2 0.811055141 0.9370754
 3:  a    3 0.811055141 0.2861395
 4:  a    4 0.811055141 0.8304476
 5:  a    5 0.811055141 0.6417455
 6:  a    6 0.811055141 0.5190959
 7:  a    7 0.811055141 0.7365883
 8:  a    8 0.811055141 0.1346666
 9:  a    9 0.811055141 0.6569923
10:  a   10 0.003948339 0.7050648
11:  b    1 0.737595618 0.4577418
12:  b    2 0.737595618 0.7191123
13:  b    3 0.737595618 0.9346722
14:  b    4 0.737595618 0.2554288
15:  b    5 0.737595618 0.4622928
16:  b    6 0.737595618 0.9400145
17:  b    7 0.737595618 0.9782264
18:  b    8 0.388108283 0.1174874
19:  b    9 0.685169729 0.4749971
20:  b   10 0.685169729 0.5603327

这些滚动连接绝对令人难以置信,我从未见过它们在任何其他开源软件包中实现(有关详细信息,请参阅?data.table)。关闭你的“SAS大脑”并打开你的“R大脑”需要一段时间,但是一旦你克服了那个初始的驼峰,你会发现这种语言更具表现力。

答案 2 :(得分:0)

保留,试试这个:

retain<-function(x,event,outside=NA)
{
  indices <- c(1,which(event==TRUE), nrow(df)+1)
  values <- c(outside,x[event==TRUE])
  y<- rep(values, diff(indices)) 
}

使用数据:我想在w == b

时保留该值
df <- data.frame(w = c("a","b","c","a","b","c"), x = 1:6, y = c(1,1,2,2,2,3), stringsAsFactors = FALSE)
df$z<-retain(df$x-df$y,df$w=="b")
df

与此相反,这在SAS中并不存在:

obtain<-function(x,event,outside=NA)
{
  indices <- c(0,which(event==TRUE), nrow(df))
  values <- c(x[event==TRUE],outside)
  y<- rep(values, diff(indices)) 
}

这是一个例子。我想提前获得w == b

的值
df$z2<-obtain(df$x-df$y,df$w=="b")
df

感谢Julien的帮助。

答案 3 :(得分:0)

这里有一个例子:用sqldf累积值:

> w_cum <-
 sqldf("select t1.id, t1.SomeNumt, SUM(t2.SomeNumt) as cum_sum
       from w_cum       t1
       inner join w_cum t2 on t1.id >= t2.id
       group by t1.id, t1.SomeNumt
       order by t1.id

&#34)

   id SomeNumt cum_sum
  • 1 11 11
  • 2 12 23
  • 3 13 36
  • 4 14 50
  • 5 15 65
  • 6 16 81
  • 7 17 98
  • 8 18 116
  • 9 19 135
  • 10 20 155