我在R中寻找一个类似于SAS中的lag1
,lag2
和retain
函数的函数,我可以将它与data.tables一起使用。
我知道R中有embed
和lag
等函数,但它们不会返回单个值或前一个值。它们返回一组完整的向量。
R中有什么东西我可以用data.table吗?
有关SAS功能的更多信息:
答案 0 :(得分:9)
您必须意识到R的工作方式与SAS中的数据步骤非常不同。 SAS中的lag
函数用于数据步骤,并在 中使用该数据步骤的隐式循环结构。 retain
函数也是如此,它只是在进行数据循环时保持值不变。
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)
我会说相当于retain
,lag1
和lag2
的衣柜将是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