使用dplyr将数据框和列表转换为长格式

时间:2019-07-08 14:07:39

标签: r tidyverse

这是一个难题。

假设您有一个数据框和一个列表。列表中的元素与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中的每个向量,我们都将对应的行重复了多次以容纳每个值。

3 个答案:

答案 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中的每个Namedd子集

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))

或者另一个选择是uncountmutate

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