这是一个难题。
假设您有一个数据框和一个列表。列表中的元素与df中的行一样多:
dd <- data.frame(ID=1:3, Name=LETTERS[1:3])
dl <- map(4:6, rnorm) %>% set_names(letters[1:3])
是否有一种简单的方法(最好使用dplyr / tidyverse)来制作长格式,以使列表中的元素与数据帧的相应行结合在一起?这是我脑子里用不太优雅的方式说明的内容:
rows <- map(1:length(dl), ~ rep(., length(dl[[.]]))) %>% unlist()
dd <- dd[rows,]
dd$value <- unlist(dl)
如您所见,对于dl
中的每个向量,我们都将对应的行重复了多次以容纳每个值。
答案 0 :(得分:10)
在基数R
中,您可以使用stack
,后跟merge
来获得结果:
res <- merge(stack(dl), dd, by.x="ind", by.y="Name")
head(res)
# ind values ID
#1 A -0.79616693 1
#2 A 0.37720953 1
#3 A 1.30273712 1
#4 A 0.19483859 1
#5 B 0.18770716 2
#6 B -0.02226917 2
NB: 我假设dl
的名称应该是大写字母,但如果确实是小写字母,则需要改行以下行:
res <- merge(stack(setNames(dl, toupper(names(dl)))), dd, by.x="ind", by.y="Name")
答案 1 :(得分:7)
由于已经提供了dplyr解决方案,因此另一个选择是使用data.table分组为dl
中的每个Name
值dd
子集
library(data.table)
setDT(dd)
dd[, .(values = dl[[tolower(Name)]]), by = .(ID, Name)]
# ID Name values
# 1: 1 A -1.09633600
# 2: 1 A -1.26238190
# 3: 1 A 1.15220845
# 4: 1 A -1.45741071
# 5: 2 B -0.49318131
# 6: 2 B 0.59912670
# 7: 2 B -0.73117632
# 8: 2 B -1.09646143
# 9: 2 B -0.79409753
# 10: 3 C -0.08205888
# 11: 3 C 0.21503398
# 12: 3 C -1.17541571
# 13: 3 C -0.10020616
# 14: 3 C -1.01152362
# 15: 3 C -1.03693337
答案 2 :(得分:5)
我们可以创建一个list
列和unnest
library(tidyverse)
dd %>%
mutate(value = dl) %>%
unnest
# ID Name value
#1 1 A 1.57984385
#2 1 A 0.66831102
#3 1 A -0.45472145
#4 1 A 2.33807619
#5 2 B 1.56716709
#6 2 B 0.74982763
#7 2 B 0.07025534
#8 2 B 1.31174561
#9 2 B 0.57901536
#10 3 C -1.36629653
#11 3 C -0.66437155
#12 3 C 2.12506187
#13 3 C 1.20220402
#14 3 C 0.10687018
#15 3 C 0.15973401
请注意,如果条件基于代码的紧凑性,那么我们删除%>%
unnest(mutate(dd, value = dl))
或者另一个选择是uncount
和mutate
dd %>%
uncount(lengths(dl)) %>%
mutate(value = flatten_dbl(unname(dl)))
如果需要基于'dl'名称的联接
enframe(dl, name = 'Name') %>%
mutate(Name = toupper(Name)) %>%
left_join(dd) %>%
unnest
在base R
中,我们可以rep
将“ dd”的行与“ dl”的lengths
和“ transform
”相切,以将“值”创建为{{1 }} ed'dl'
unlist