如何在每个组内创建一个滞后变量?

我有 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


我想计算列的滞后版本 "value"

里面

每个级别 "groups".

结果应该是如此


# 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, 什么是有问题的。

什么是最有效的方法 base R, plyr, dplyr 和 data.table?
已邀请:

奔跑吧少年

赞同来自:

你可以这样做
data.table



library/data.table/
data[, lag.value:=c/NA, value[-.N]/, by=groups]
data
# time groups value lag.value
#1: 1 a 0.02779005 NA
#2: 2 a 0.88029938 0.02779005
#3: 3 a -1.69514201 0.88029938
#4: 1 b -1.27560288 NA
#5: 2 b -0.65976434 -1.27560288
#6: 3 b -1.37804943 -0.65976434
#7: 4 b 0.12041778 -1.37804943


对于几列:


nm1 <- grep/"^value", colnames/data/, value=TRUE/
nm2 <- paste/"lag", nm1, sep="."/
data[, /nm2/:=lapply/.SD, function/x/ c/NA, x[-.N]//, by=groups, .SDcols=nm1]
data
# time groups value value1 value2 lag.value lag.value1
#1: 1 b -0.6264538 0.7383247 1.12493092 NA NA
#2: 2 b 0.1836433 0.5757814 -0.04493361 -0.6264538 0.7383247
#3: 3 b -0.8356286 -0.3053884 -0.01619026 0.1836433 0.5757814
#4: 1 a 1.5952808 1.5117812 0.94383621 NA NA
#5: 2 a 0.3295078 0.3898432 0.82122120 1.5952808 1.5117812
#6: 3 a -0.8204684 -0.6212406 0.59390132 0.3295078 0.3898432
#7: 4 a 0.4874291 -2.2146999 0.91897737 -0.8204684 -0.6212406
# lag.value2
#1: NA
#2: 1.12493092
#3: -0.04493361
#4: NA
#5: 0.94383621
#6: 0.82122120
#7: 0.59390132


更新


data.table

版本 >=
v1.9.5

我们可以用
shift


type

作为
lag

或者
lead

. 使用默认类型。
lag

.


data[, /nm2/ := shift/.SD/, by=groups, .SDcols=nm1]
# time groups value value1 value2 lag.value lag.value1
#1: 1 b -0.6264538 0.7383247 1.12493092 NA NA
#2: 2 b 0.1836433 0.5757814 -0.04493361 -0.6264538 0.7383247
#3: 3 b -0.8356286 -0.3053884 -0.01619026 0.1836433 0.5757814
#4: 1 a 1.5952808 1.5117812 0.94383621 NA NA
#5: 2 a 0.3295078 0.3898432 0.82122120 1.5952808 1.5117812
#6: 3 a -0.8204684 -0.6212406 0.59390132 0.3295078 0.3898432
#7: 4 a 0.4874291 -2.2146999 0.91897737 -0.8204684 -0.6212406
# lag.value2
#1: NA
#2: 1.12493092
#3: -0.04493361
#4: NA
#5: 0.94383621
#6: 0.82122120
#7: 0.59390132


如果您需要相反,请使用
type=lead



nm3 <- paste/"lead", nm1, sep="."/


使用源数据集


data[, /nm3/ := shift/.SD, type='lead'/, by = groups, .SDcols=nm1]
# time groups value value1 value2 lead.value lead.value1
#1: 1 b -0.6264538 0.7383247 1.12493092 0.1836433 0.5757814
#2: 2 b 0.1836433 0.5757814 -0.04493361 -0.8356286 -0.3053884
#3: 3 b -0.8356286 -0.3053884 -0.01619026 NA NA
#4: 1 a 1.5952808 1.5117812 0.94383621 0.3295078 0.3898432
#5: 2 a 0.3295078 0.3898432 0.82122120 -0.8204684 -0.6212406
#6: 3 a -0.8204684 -0.6212406 0.59390132 0.4874291 -2.2146999
#7: 4 a 0.4874291 -2.2146999 0.91897737 NA NA
# lead.value2
#1: -0.04493361
#2: -0.01619026
#3: NA
#4: 0.82122120
#5: 0.59390132
#6: 0.91897737
#7: NA


数据


set.seed/1/
data <- data.table/time =c/1:3,1:4/,groups = c/rep/c/"b","a"/,c/3,4///,
value = rnorm/7/, value1=rnorm/7/, value2=rnorm/7//

莫问

赞同来自:

使用包
dplyr

:


library/dplyr/
data <-
data %>%
group_by/groups/ %>%
mutate/lag.value = dplyr::lag/value, n = 1, default = NA//





> data
Source: local data table [7 x 4]
Groups: groups

time groups value lag.value
1 1 a 0.07614866 NA
2 2 a -0.02784712 0.07614866
3 3 a 1.88612245 -0.02784712
4 1 b 0.26526825 NA
5 2 b 1.23820506 0.26526825
6 3 b 0.09276648 1.23820506
7 4 b -0.09253594 0.09276648


如所知) @BrianD,, 这隐含地假设该计数已由组排序。 如果没有,要么将其分成组,或使用参数
order_by


lag

. 另请注意,因为
https://coderoad.ru/28235074/
有一些版本 dplyr, 为确保安全,应明确指定参数和命名空间。

二哥

赞同来自:

在基地 R 这将是您的工作:


data$lag.value <- c/NA, data$value[-nrow/data/]/
data$lag.value[which/!duplicated/data$groups//] <- NA


第一个字符串添加了一串延迟 /+1/ 观察。 第二行校正每个组的第一个记录,因为延迟观察是指先前的组。

注意
data

有格式化
data.frame

, 不要使用
data.table

.

郭文康

赞同来自:

如果要确保避免使用数据的排序避免任何问题,则可以使用它 dplyr, 手动用类似的东西:


df <- data.frame/Names = c/rep/'Dan',50/,rep/'Dave',100//,
Dates = c/seq/1,100,by=2/,seq/1,100,by=1//,
Values = rnorm/150,0,1//

df <- df %>% group_by/Names/ %>% mutate/Rank=rank/Dates/,
RankDown=Rank-1/

df <- df %>% left_join/select/df,Rank,ValueDown=Values,Names/,by=c/'RankDown'='Rank','Names'/
/ %>% select/-Rank,-RankDown/

head/df/


或者,作为一个选项,我喜欢将它放在与所选分组变量的函数中的想法/出色地/, 朗格列 /例如,日期或其他/ 并选择滞后数。 它也需要它。 lazyeval, 和 dplyr.


groupLag <- function/mydf,grouping,ranking,lag/{
df <- mydf
groupL <- lapply/grouping,as.symbol/

names <- c/'Rank','RankDown'/
foos <- list/interp/~rank/var/,var=as.name/ranking//,~Rank-lag/

df <- df %>% group_by_/.dots=groupL/ %>% mutate_/.dots=setNames/foos,names//

selectedNames <- c/'Rank','Values',grouping/
df2 <- df %>% select_/.dots=selectedNames/
colnames/df2/ <- c/'Rank','ValueDown',grouping/

df <- df %>% left_join/df2,by=c/'RankDown'='Rank',grouping// %>% select/-Rank,-RankDown/

return/df/
}

groupLag/df,c/'Names'/,c/'Dates'/,1/

风见雨下

赞同来自:

我想添加以前的答案,提到了在一个重要的案例中提到了两种问题

当您不保证每组每个课程都有数据时

. 也就是说,你仍然经常分开的临时行,但可能会错过这里和那里。 我专注于改善解决方案的两种方式
dplyr

.

我们将从与您的数据开始使用相同的数据......


library/dplyr/
library/tidyr/

set.seed/1/
data_df = data.frame/time = c/1:3, 1:4/,
groups = c/rep/c/"b", "a"/, c/3, 4///,
value = rnorm/7//
data_df
#> time groups value
#> 1 1 b -0.6264538
#> 2 2 b 0.1836433
#> 3 3 b -0.8356286
#> 4 1 a 1.5952808
#> 5 2 a 0.3295078
#> 6 3 a -0.8204684
#> 7 4 a 0.4874291


... 但现在我们将删除几行


data_df = data_df[-c/2, 6/, ]
data_df
#> time groups value
#> 1 1 b -0.6264538
#> 3 3 b -0.8356286
#> 4 1 a 1.5952808
#> 5 2 a 0.3295078
#> 7 4 a 0.4874291


一个简单的解决方案
dplyr

不再工作了


data_df %>% 
arrange/groups, time/ %>%
group_by/groups/ %>%
mutate/lag.value = lag/value// %>%
ungroup//
#> # A tibble: 5 x 4
#> time groups value lag.value
#> <int> <fct> <dbl> <dbl>
#&gt; 1 1 a 1.60 NA
#&gt; 2 2 a 0.330 1.60
#&gt; 3 4 a 0.487 0.330
#&gt; 4 1 b -0.626 NA
#&gt; 5 3 b -0.836 -0.626


你看到了,虽然我们没有案件的含义
/group = 'a', time = '3'/

, 以上仍然显示了滞后的价值
/group = 'a', time = '4'/

, 这实际上是一个值
time = 2

.

正确的决定
dplyr


这个想法是我们添加了缺失 /小组,临时/ 组合。 它

效率低下

为了记忆 VERY, 当您有许多可能的组合时 /团体,时间/, 但值很少固定。


dplyr_correct_df = expand.grid/
groups = sort/unique/data_df$groups//,
time = seq/from = min/data_df$time/, to = max/data_df$time//
/ %&gt;%
left_join/data_df, by = c/"groups", "time"// %&gt;%
arrange/groups, time/ %&gt;%
group_by/groups/ %&gt;%
mutate/lag.value = lag/value// %&gt;%
ungroup//
dplyr_correct_df
#&gt; # A tibble: 8 x 4
#&gt; groups time value lag.value
#&gt; <fct> <int> <dbl> <dbl>
#&gt; 1 a 1 1.60 NA
#&gt; 2 a 2 0.330 1.60
#&gt; 3 a 3 NA 0.330
#&gt; 4 a 4 0.487 NA
#&gt; 5 b 1 -0.626 NA
#&gt; 6 b 2 NA -0.626
#&gt; 7 b 3 -0.836 NA
#&gt; 8 b 4 NA -0.836


请注意,我们现在有 NA 在
/group = 'a', time = '4'/

, 应该是预期的行为。 与此同样
/group = 'b', time = '3'/

.

乏味,也是使用课程的正确解决方案
zoo::zooreg


这一决定应该从内存的角度来看,当情况的数量非常大时,因为而不是填补缺失的情况 NA, 它使用索引。


library/zoo/

zooreg_correct_df = data_df %&gt;%
as_tibble// %&gt;%
# nest the data for each group
# should work for multiple groups variables
nest/-groups, .key = "zoo_ob"/ %&gt;%
mutate/zoo_ob = lapply/zoo_ob, function/d/ {

# create zooreg objects from the individual data.frames created by nest
z = zoo::zooreg/
data = select/d,-time/,
order.by = d$time,
frequency = 1
/ %&gt;%
# calculate lags
# we also ask for the 0'th order lag so that we keep the original value
zoo:::lag.zooreg/k = /-1/:0/ # note the sign convention is different

# recover df's from zooreg objects
cbind/
time = as.integer/zoo::index/z//,
zoo:::as.data.frame.zoo/z/
/

}// %&gt;%
unnest// %&gt;%
# format values
select/groups, time, value = value.lag0, lag.value = `value.lag-1`/ %&gt;%
arrange/groups, time/ %&gt;%
# eliminate additional periods created by lag
filter/time &lt;= max/data_df$time//
zooreg_correct_df
#&gt; # A tibble: 8 x 4
#&gt; groups time value lag.value
#&gt; <fct> <int> <dbl> <dbl>
#&gt; 1 a 1 1.60 NA
#&gt; 2 a 2 0.330 1.60
#&gt; 3 a 3 NA 0.330
#&gt; 4 a 4 0.487 NA
#&gt; 5 b 1 -0.626 NA
#&gt; 6 b 2 NA -0.626
#&gt; 7 b 3 -0.836 NA
#&gt; 8 b 4 NA -0.836


最后,让我们检查两个正确的解决方案实际上是相等的:


all.equal/dplyr_correct_df, zooreg_correct_df/
#&gt; [1] TRUE


</dbl></dbl></int></fct></dbl></dbl></int></fct></dbl></dbl></fct></int>

要回复问题请先登录注册