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

Jan*_*ary 6 r tidyverse

这是一个难题。

假设您有一个数据框和一个列表。列表中的元素与df中的行一样多:

dd <- data.frame(ID=1:3, Name=LETTERS[1:3])
dl <- map(4:6, rnorm) %>% set_names(letters[1:3])
Run Code Online (Sandbox Code Playgroud)

是否有一种简单的方法(最好使用dplyr / tidyverse)来制作长格式,以使列表中的元素与数据帧的相应行连接在一起?这是我心目中不太优雅的方式:

rows <- map(1:length(dl), ~ rep(., length(dl[[.]]))) %>% unlist()
dd <- dd[rows,]
dd$value <- unlist(dl)
Run Code Online (Sandbox Code Playgroud)

如您所见,对于中的每个向量dl,我们都会根据需要将对应的行复制多次,以容纳每个值。

Cat*_*ath 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
Run Code Online (Sandbox Code Playgroud)

注意:我以为名称dl应该是大写的,但是如果它们确实是小写的,则需要改用以下行:

res <- merge(stack(setNames(dl, toupper(names(dl)))), dd, by.x="ind", by.y="Name")
Run Code Online (Sandbox Code Playgroud)


Ice*_*can 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
Run Code Online (Sandbox Code Playgroud)


akr*_*run 5

我们可以创建一个listunnest

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
Run Code Online (Sandbox Code Playgroud)

请注意,如果条件基于代码的紧凑性,则如果删除 %>%

unnest(mutate(dd, value = dl))
Run Code Online (Sandbox Code Playgroud)

或者另一个选择是uncountmutate

dd %>% 
   uncount(lengths(dl)) %>%
   mutate(value = flatten_dbl(unname(dl)))
Run Code Online (Sandbox Code Playgroud)

如果需要基于“ dl”名称的联接

enframe(dl, name = 'Name') %>%
     mutate(Name = toupper(Name)) %>% 
     left_join(dd) %>% 
     unnest
Run Code Online (Sandbox Code Playgroud)

在中base R,我们可以rep将'dd'与lengths'dl' 的行连接起来,transform并将'value'创建为ed'dl unlist'

transform(dd[rep(seq_len(nrow(dd)), lengths(dl)),], value = unlist(dl))
Run Code Online (Sandbox Code Playgroud)