我有一个data.table:
set.seed(1)
data <- data.table(time = c(1:3, 1:4),
groups = c(rep(c("b", "a"), c(3, 4))),
value = rnorm(7))
data
# groups time value
# 1: b 1 -0.6264538
# 2: b 2 0.1836433
# 3: b 3 -0.8356286
# 4: a 1 1.5952808
# 5: a 2 0.3295078
# 6: a 3 -0.8204684
# 7: a 4 0.4874291
我想在"groups"的每个级别内计算"value"列的滞后版本 .
结果应该是这样的
# groups time value lag.value
# 1 a 1 1.5952808 NA
# 2 a 2 0.3295078 1.5952808
# 3 a 3 -0.8204684 0.3295078
# 4 a 4 0.4874291 -0.8204684
# 5 b 1 -0.6264538 NA
# 6 b 2 0.1836433 -0.6264538
# 7 b 3 -0.8356286 0.1836433
我试图直接使用 lag
:
data$lag.value <- lag(data$value)
......显然不行 .
我也尝试过:
unlist(tapply(data$value, data$groups, lag))
a1 a2 a3 a4 b1 b2 b3
NA -0.1162932 0.4420753 2.1505440 NA 0.5894583 -0.2890288
这几乎是我想要的 . 但是,生成的向量的排序与data.table中的排序不同,这是有问题的 .
在基础R,plyr,dplyr和data.table中执行此操作的最有效方法是什么?
5 回答
你可以在
data.table
内做到这一点对于多列:
更新
从
data.table
版本> =v1.9.5
,我们可以使用shift
和type
作为lag
或lead
. 默认情况下,类型为lag
.如果您需要反向,请使用
type=lead
使用原始数据集
数据
使用包
dplyr
:给
正如@BrianD所指出的,这隐含地假设值已经按组排序 . 如果不是,请按组排序,或使用
lag
中的order_by
参数 . 另请注意,由于existing issue具有某些版本的dplyr,为了安全起见,应明确给出参数和命名空间 .在基地R,这将完成工作:
第一行添加了一串滞后(1)观测值 . 第二个字符串校正每个组的第一个条目,因为滞后观察来自前一个组 .
请注意
data
的格式为data.frame
,不使用data.table
.如果您想确保在排序数据时避免任何问题,可以使用dplyr手动执行此操作,例如:
或者我喜欢把它放在一个带有所选分组变量,排序列(如Date或其他)和所选滞后数的函数中的想法 . 这也需要lazyeval以及dplyr .
我想通过两种方式来补充之前的答案,我在重要的案例 when you are not guaranteed that each group has data for every time period 中处理这个问题 . 也就是说,你仍然有一个有规律的间隔时间序列,但是这里和那里可能会有缺失 . 我将重点介绍两种改进
dplyr
解决方案的方法 .我们从您使用的相同数据开始...
...但现在我们删除了几行
简单的dplyr解决方案不再有效
你看,虽然我们没有案例
(group = 'a', time = '3')
的值,但在(group = 'a', time = '4')
的情况下,上面仍然显示滞后值,这实际上是time = 2
的值 .正确的dplyr解决方案
我们的想法是添加缺失的(组,时间)组合 . 当你有很多可能的(组,时间)组合时,这是低效率的,但是稀疏地捕获了这些值 .
请注意,我们现在在
(group = 'a', time = '4')
处有一个NA,这应该是预期的行为 . 与(group = 'b', time = '3')
相同 .繁琐但也正确的解决方案使用类zoo :: zooreg
在案例数量非常大的情况下,此解决方案应该在内存方面更好地工作,因为它不使用NA来填充缺失的案例,而是使用索引 .
最后,让我们检查两个正确的解决方案是否真的相同: