R.n 另一列数据框中的前一个元素
R. n Previous Elements in a data frame of another column
我想添加一个新列,其中包含另一列中前 n 个元素的向量(或列表)。分组后计算。
这里是一个 n=2 的例子。输入:
v0 = c(rep("a",5),rep("b",5))
v1 = 1:10
DF1 <- data.frame(v0,v1)
> DF1
v0 v1
1 a 1
2 a 2
3 a 3
4 a 4
5 a 5
6 b 6
7 b 7
8 b 8
9 b 9
10 b 10
输出:新列应该是整数向量(或列表)并包含以下值:
> DF2_L
v0 v1 myL
1 a 1 NA, NA
2 a 2 1, NA
3 a 3 2, 1
4 a 4 3, 2
5 a 5 4, 3
6 b 6 5, 4
7 b 7 6, 5
8 b 8 7, 6
9 b 9 8, 7
10 b 10 9, 8
一个简单的解决方案是
DF2 <- DF1 %>% group_by(v0) %>%
mutate(i1=lag(v1,1), i2=lag(v1,2),
myL = mapply(c, i1, i2, SIMPLIFY = F))%>%
select(-c(i1,i2))
但是这只是一个简化的 table。对于我的计算 n 是 36。这意味着我需要为 lag(v1,1)、lag(v1,2) ... lag(v1,36) 创建 36 个新的“虚拟”列并删除它们,将这些值组合成一个列表。这不方便。必须换一种方式。
我想使用 rollapply。使用 F = list 但我收到错误消息
t <- DF1 %>% group_by(v0) %>%
mutate( myL= rollapply(lag(v1),
2, fill=NA, align="right",
list))
Error: Problem with `mutate()` input `myL`.
x “x” : attempt to define invalid zoo object
i Input `myL` is `rollapply(lag(v1), 2, fill = NA, align = "right", list)`.
i The error occurred in group 1: v0 = "a".
Run `rlang::last_error()` to see where the error occurred.
当我使用 FUN = c.我将每个元素作为单独的列
t <- DF1 %>% group_by(v0) %>%
mutate( myL= rollapply(lag(v1),
2, fill=NA, align="right",
c))
v0 v1 myL[,1] [,2]
<fct> <int> <int> <int>
1 a 1 NA NA
2 a 2 NA 1
3 a 3 1 2
4 a 4 2 3
5 a 5 3 4
6 b 6 NA NA
7 b 7 NA 6
8 b 8 6 7
9 b 9 7 8
10 b 10 8 9
这符合你的要求吗?
v0 = c(rep("a",5),rep("b",5))
v1 = 1:10
DF1 <- data.frame(v0,v1)
n <- 2
bind_cols(DF1,
map_dfc(1:n,
~ lag(DF1$v1, .x))) %>% #simple loop creating lagged columns
group_by(v0, v1) %>% # the variables we don't want to include
nest() %>%
mutate(my_list = list(set_names(unlist(data), NULL))) #make each tibble into an unnamed vector
# A tibble: 10 x 4
# Groups: v0, v1 [10]
# v0 v1 data my_list
# <chr> <int> <list> <list>
# 1 a 1 <tibble [1 x 2]> <int [2]>
# 2 a 2 <tibble [1 x 2]> <int [2]>
# 3 a 3 <tibble [1 x 2]> <int [2]>
# 4 a 4 <tibble [1 x 2]> <int [2]>
# 5 a 5 <tibble [1 x 2]> <int [2]>
# 6 b 6 <tibble [1 x 2]> <int [2]>
# 7 b 7 <tibble [1 x 2]> <int [2]>
# 8 b 8 <tibble [1 x 2]> <int [2]>
# 9 b 9 <tibble [1 x 2]> <int [2]>
#10 b 10 <tibble [1 x 2]> <int [2]>
xx$my_list
# [[1]]
# [1] NA NA
#
# [[2]]
# [1] 1 NA
#
# [[3]]
# [1] 2 1
#
# [[4]]
# [1] 3 2
#
# [[5]]
# [1] 4 3
#
# [[6]]
# [1] 5 4
#
# [[7]]
# [1] 6 5
#
# [[8]]
# [1] 7 6
#
# [[9]]
# [1] 8 7
#
# [[10]]
# [1] 9 8
编辑:我实际上不确定你想要什么,如果你只想要串联滞后值的向量,那么这样做会更清楚:
lagged_cols <- map_dfc(1:n,
~ lag(DF1$v1, .x))
apply(lagged_cols, 1, paste, collapse=" ")
# [1] "NA NA" "1 NA" "2 1" "3 2" "4 3" "5 4" "6 5" "7 6" "8 7"
# [10] "9 8"
首先注意问题中的t
并没有将两个元素放在t
的不同列中。 t
有3列,不是4列,但第3列是矩阵。
dim(t)
## [1] 10 3
dim(t[[3]])
## [1] 10 2
滚动应用
要使用 c
获取整数向量列表 运行 rollapply
的列,然后将结果矩阵拆分为列表:
library(dplyr)
library(zoo)
k <- 2
out <- DF1 %>%
group_by(v0) %>%
mutate(v2 = rollapply(c(rep(NA, k), v1), list(-seq(k)), c) %>%
split(1:n()) %>%
unname) %>%
ungroup
str(out)
给予:
tibble [10 x 3] (S3: tbl_df/tbl/data.frame)
$ v0: chr [1:10] "a" "a" "a" "a" ...
$ v1: int [1:10] 1 2 3 4 5 6 7 8 9 10
$ v2:List of 10
..$ : int [1:2] NA NA
..$ : int [1:2] 1 NA
..$ : int [1:2] 2 1
..$ : int [1:2] 3 2
..$ : int [1:2] 4 3
..$ : int [1:2] NA NA
..$ : int [1:2] 6 NA
..$ : int [1:2] 7 6
..$ : int [1:2] 8 7
..$ : int [1:2] 9 8
lag.zoo
类似的方法是转换为动物园并使用 lag.zoo
。它可以处理多个滞后。之后我们使用 coredata
从 zoo 转换回矩阵。
请注意,dplyr 会覆盖基础 lag
泛型,它会禁用其他包中的所有 lag
方法,因此请务必在加载 dplyr 时排除 dplyr 的 lag
。如下面的代码所示。如果需要,仍然可以使用 dplyr 的 lag
dplyr::lag
。交替使用下面的 stats::lag
以确保调度 lag.zoo
。
结果与上面的 rollapply
相同。
library(dplyr, exclude = "lag") # important!
library(zoo)
k <- 2
out <- DF1 %>%
group_by(v0) %>%
mutate(v2 = lag(zoo(c(rep(NA, k-1), v1)), -seq(2)) %>%
coredata %>%
split(1:n()) %>%
unname) %>%
ungroup
toString
另一种可能性(不等同)是使用 toString
创建一个字符串列。每个单元格都是一个字符串(不是字符向量)。
k <- 2
DF1 %>%
group_by(v0) %>%
mutate(v2 = rollapply(c(rep(NA, k), v1), list(-seq(k)), toString)) %>%
ungroup
给予:
# A tibble: 10 x 3
v0 v1 v2
<chr> <int> <chr>
1 a 1 NA, NA
2 a 2 1, NA
3 a 3 2, 1
4 a 4 3, 2
5 a 5 4, 3
6 b 6 NA, NA
7 b 7 6, NA
8 b 8 7, 6
9 b 9 8, 7
10 b 10 9, 8
一个data.table
解决方案:
library(data.table)
setDT(DF1)
DF1[, myL := sapply(transpose(shift(v1, n=1:2)), toString), by = v0]
# v0 v1 myL
# 1: a 1 NA, NA
# 2: a 2 1, NA
# 3: a 3 2, 1
# 4: a 4 3, 2
# 5: a 5 4, 3
# 6: b 6 NA, NA
# 7: b 7 6, NA
# 8: b 8 7, 6
# 9: b 9 8, 7
# 10: b 10 9, 8
这导致列是向量列表:
# > sapply(DF1, class)
# v0 v1 myL
# "character" "integer" "list"
备注
- 您可以替换函数
c
来获取列表列表(list
)、字符串列表(toString
)等
- 如果您不想使用
data.table
,您可以使用 setDF()
将结果变为 data.frame
。
- 也可以在常规
dplyr
设置中工作:
DF1 %>% group_by(v0) %>% mutate(myL = lapply(transpose(shift(v1, n=1:2)), c))
我想添加一个新列,其中包含另一列中前 n 个元素的向量(或列表)。分组后计算。
这里是一个 n=2 的例子。输入:
v0 = c(rep("a",5),rep("b",5))
v1 = 1:10
DF1 <- data.frame(v0,v1)
> DF1
v0 v1
1 a 1
2 a 2
3 a 3
4 a 4
5 a 5
6 b 6
7 b 7
8 b 8
9 b 9
10 b 10
输出:新列应该是整数向量(或列表)并包含以下值:
> DF2_L
v0 v1 myL
1 a 1 NA, NA
2 a 2 1, NA
3 a 3 2, 1
4 a 4 3, 2
5 a 5 4, 3
6 b 6 5, 4
7 b 7 6, 5
8 b 8 7, 6
9 b 9 8, 7
10 b 10 9, 8
一个简单的解决方案是
DF2 <- DF1 %>% group_by(v0) %>%
mutate(i1=lag(v1,1), i2=lag(v1,2),
myL = mapply(c, i1, i2, SIMPLIFY = F))%>%
select(-c(i1,i2))
但是这只是一个简化的 table。对于我的计算 n 是 36。这意味着我需要为 lag(v1,1)、lag(v1,2) ... lag(v1,36) 创建 36 个新的“虚拟”列并删除它们,将这些值组合成一个列表。这不方便。必须换一种方式。
我想使用 rollapply。使用 F = list 但我收到错误消息
t <- DF1 %>% group_by(v0) %>%
mutate( myL= rollapply(lag(v1),
2, fill=NA, align="right",
list))
Error: Problem with `mutate()` input `myL`.
x “x” : attempt to define invalid zoo object
i Input `myL` is `rollapply(lag(v1), 2, fill = NA, align = "right", list)`.
i The error occurred in group 1: v0 = "a".
Run `rlang::last_error()` to see where the error occurred.
当我使用 FUN = c.我将每个元素作为单独的列
t <- DF1 %>% group_by(v0) %>%
mutate( myL= rollapply(lag(v1),
2, fill=NA, align="right",
c))
v0 v1 myL[,1] [,2]
<fct> <int> <int> <int>
1 a 1 NA NA
2 a 2 NA 1
3 a 3 1 2
4 a 4 2 3
5 a 5 3 4
6 b 6 NA NA
7 b 7 NA 6
8 b 8 6 7
9 b 9 7 8
10 b 10 8 9
这符合你的要求吗?
v0 = c(rep("a",5),rep("b",5))
v1 = 1:10
DF1 <- data.frame(v0,v1)
n <- 2
bind_cols(DF1,
map_dfc(1:n,
~ lag(DF1$v1, .x))) %>% #simple loop creating lagged columns
group_by(v0, v1) %>% # the variables we don't want to include
nest() %>%
mutate(my_list = list(set_names(unlist(data), NULL))) #make each tibble into an unnamed vector
# A tibble: 10 x 4
# Groups: v0, v1 [10]
# v0 v1 data my_list
# <chr> <int> <list> <list>
# 1 a 1 <tibble [1 x 2]> <int [2]>
# 2 a 2 <tibble [1 x 2]> <int [2]>
# 3 a 3 <tibble [1 x 2]> <int [2]>
# 4 a 4 <tibble [1 x 2]> <int [2]>
# 5 a 5 <tibble [1 x 2]> <int [2]>
# 6 b 6 <tibble [1 x 2]> <int [2]>
# 7 b 7 <tibble [1 x 2]> <int [2]>
# 8 b 8 <tibble [1 x 2]> <int [2]>
# 9 b 9 <tibble [1 x 2]> <int [2]>
#10 b 10 <tibble [1 x 2]> <int [2]>
xx$my_list
# [[1]]
# [1] NA NA
#
# [[2]]
# [1] 1 NA
#
# [[3]]
# [1] 2 1
#
# [[4]]
# [1] 3 2
#
# [[5]]
# [1] 4 3
#
# [[6]]
# [1] 5 4
#
# [[7]]
# [1] 6 5
#
# [[8]]
# [1] 7 6
#
# [[9]]
# [1] 8 7
#
# [[10]]
# [1] 9 8
编辑:我实际上不确定你想要什么,如果你只想要串联滞后值的向量,那么这样做会更清楚:
lagged_cols <- map_dfc(1:n,
~ lag(DF1$v1, .x))
apply(lagged_cols, 1, paste, collapse=" ")
# [1] "NA NA" "1 NA" "2 1" "3 2" "4 3" "5 4" "6 5" "7 6" "8 7"
# [10] "9 8"
首先注意问题中的t
并没有将两个元素放在t
的不同列中。 t
有3列,不是4列,但第3列是矩阵。
dim(t)
## [1] 10 3
dim(t[[3]])
## [1] 10 2
滚动应用
要使用 c
获取整数向量列表 运行 rollapply
的列,然后将结果矩阵拆分为列表:
library(dplyr)
library(zoo)
k <- 2
out <- DF1 %>%
group_by(v0) %>%
mutate(v2 = rollapply(c(rep(NA, k), v1), list(-seq(k)), c) %>%
split(1:n()) %>%
unname) %>%
ungroup
str(out)
给予:
tibble [10 x 3] (S3: tbl_df/tbl/data.frame)
$ v0: chr [1:10] "a" "a" "a" "a" ...
$ v1: int [1:10] 1 2 3 4 5 6 7 8 9 10
$ v2:List of 10
..$ : int [1:2] NA NA
..$ : int [1:2] 1 NA
..$ : int [1:2] 2 1
..$ : int [1:2] 3 2
..$ : int [1:2] 4 3
..$ : int [1:2] NA NA
..$ : int [1:2] 6 NA
..$ : int [1:2] 7 6
..$ : int [1:2] 8 7
..$ : int [1:2] 9 8
lag.zoo
类似的方法是转换为动物园并使用 lag.zoo
。它可以处理多个滞后。之后我们使用 coredata
从 zoo 转换回矩阵。
请注意,dplyr 会覆盖基础 lag
泛型,它会禁用其他包中的所有 lag
方法,因此请务必在加载 dplyr 时排除 dplyr 的 lag
。如下面的代码所示。如果需要,仍然可以使用 dplyr 的 lag
dplyr::lag
。交替使用下面的 stats::lag
以确保调度 lag.zoo
。
结果与上面的 rollapply
相同。
library(dplyr, exclude = "lag") # important!
library(zoo)
k <- 2
out <- DF1 %>%
group_by(v0) %>%
mutate(v2 = lag(zoo(c(rep(NA, k-1), v1)), -seq(2)) %>%
coredata %>%
split(1:n()) %>%
unname) %>%
ungroup
toString
另一种可能性(不等同)是使用 toString
创建一个字符串列。每个单元格都是一个字符串(不是字符向量)。
k <- 2
DF1 %>%
group_by(v0) %>%
mutate(v2 = rollapply(c(rep(NA, k), v1), list(-seq(k)), toString)) %>%
ungroup
给予:
# A tibble: 10 x 3
v0 v1 v2
<chr> <int> <chr>
1 a 1 NA, NA
2 a 2 1, NA
3 a 3 2, 1
4 a 4 3, 2
5 a 5 4, 3
6 b 6 NA, NA
7 b 7 6, NA
8 b 8 7, 6
9 b 9 8, 7
10 b 10 9, 8
一个data.table
解决方案:
library(data.table)
setDT(DF1)
DF1[, myL := sapply(transpose(shift(v1, n=1:2)), toString), by = v0]
# v0 v1 myL
# 1: a 1 NA, NA
# 2: a 2 1, NA
# 3: a 3 2, 1
# 4: a 4 3, 2
# 5: a 5 4, 3
# 6: b 6 NA, NA
# 7: b 7 6, NA
# 8: b 8 7, 6
# 9: b 9 8, 7
# 10: b 10 9, 8
这导致列是向量列表:
# > sapply(DF1, class)
# v0 v1 myL
# "character" "integer" "list"
备注
- 您可以替换函数
c
来获取列表列表(list
)、字符串列表(toString
)等 - 如果您不想使用
data.table
,您可以使用setDF()
将结果变为data.frame
。 - 也可以在常规
dplyr
设置中工作:
DF1 %>% group_by(v0) %>% mutate(myL = lapply(transpose(shift(v1, n=1:2)), c))