我正在寻找一个类似于R的函数lag1
,lag2
并retain
在SAS中使用我可以与data.tables一起使用的函数.
我知道R中有类似的功能embed
,lag
但它们不会返回单个值或前一个值.它们返回一组完整的向量.
R中有什么东西我可以用data.table吗?
有关SAS功能的更多信息:
您必须意识到R的工作方式与SAS中的数据步骤非常不同.的lag
在SAS功能在数据步骤中使用,并且被用于内数据步骤的隐含的循环结构.这同样适用于对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
;
Run Code Online (Sandbox Code Playgroud)
在R中,您可以编写自己的滞后函数,如下所示:
mylag <- function(x,k) c(rep(NA,k),head(x,-k))
Run Code Online (Sandbox Code Playgroud)
该单行在向量的开头添加k倍NA,并从向量中删除最后的k个值.结果是lag1
SAS中给出的滞后矢量等.
这允许类似的东西:
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
)
Run Code Online (Sandbox Code Playgroud)
结果是:
> 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
Run Code Online (Sandbox Code Playgroud)
完全相同的data.table
对象也适用.这里重要的注意事项是重新思考你的策略:不要像使用SAS中的DATA步骤那样循环思考,而是在使用R时必须开始考虑向量和索引.
我想说的衣柜相当于retain
,lag1
和lag2
将是滞后功能在quantmod包。
使用它非常容易data.tables
。例如:
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']
Run Code Online (Sandbox Code Playgroud)
这产生以下结果:
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
Run Code Online (Sandbox Code Playgroud)
如您所见,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
Run Code Online (Sandbox Code Playgroud)
您有另一个要加入的 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
Run Code Online (Sandbox Code Playgroud)
常规合并会产生大量缺失值:
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
Run Code Online (Sandbox Code Playgroud)
但是,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
Run Code Online (Sandbox Code Playgroud)
这真是太酷了:旧的观察结果会及时向前滚动,直到被新的观察结果取代。如果要替换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
Run Code Online (Sandbox Code Playgroud)
这些滚动连接绝对令人难以置信,我从未见过它们在任何其他开源包中实现(?data.table
有关更多信息,请参阅参考资料)。关闭“SAS 大脑”并打开“R 大脑”需要一些时间,但是一旦您克服了最初的障碍,您就会发现该语言更具表现力。