问题描述
我想添加一个新列,其中包含来自另一列的前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))
但是,这只是一个简化表。对于我的计算,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),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),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,.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
rollapply
要获取作为整数矢量列表的列,请使用rollapply
运行c
,然后将结果矩阵分成一个列表:
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
。如下面的代码所示。如果需要,可以通过使用lag
来使用dplyr的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,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
,则可以使用data.frame
将结果转换为setDF()
。 - 也可以在常规
dplyr
设置下使用:
DF1 %>% group_by(v0) %>% mutate(myL = lapply(transpose(shift(v1,c))