从列表元素的成对组合构建数据框

Mar*_*ark 2 r list dataframe

我有一个清单list。此列表的前 5 个元素是:

[[1]]
[1] "#solarpanels" "#solar"      

[[2]]
[1] "#Nuclear" "#Wind"    "#solar"  

[[3]]
[1] "#solar"

[[4]]
[1] "#steel"           "#windenergy"      "#solarenergy"     "#carbonfootprint"

[[5]]
[1] "#solar" "#wind"
Run Code Online (Sandbox Code Playgroud)

我想删除元素,[[3]]因为只包含一个元素。此外,我想为列表的每一行构建一个包含所有可能组合的数据框。例如,具有两列(例如第一个 named A,第二个B)的数据框,例如:

A                  B
"#solarpanels"     "#solar"
"#Nuclear"         "#Wind"  
"#Nuclear"         "#solar"
"#steel"           "#windenergy"
"#steel"           "#solarenergy"
"#steel"           "#carbonfootprint"
"#windenergy"      "#carbonfootprint"
"#windenergy"      "#solarenergy"
"#solarenergy"     "#carbonfootprint"
"#solar"           "#wind"
Run Code Online (Sandbox Code Playgroud)

我尝试过(仅针对一个元素)

for (i in 1:(length(list[[4]])-1)) {
  df$from = rep(list[[4]][i],length(list[[4]])-i)
  df$to = list[[4]][(i+1):length(list[[4]])]
}
Run Code Online (Sandbox Code Playgroud)

在哪里

df=data.frame(A=character(), 
                    B=character(),
                    stringsAsFactors=FALSE) 
Run Code Online (Sandbox Code Playgroud)

但我得到了

data.frame`(`*tmp*`, A, value = c("#steel", "#steel",  : 
 replacement has 3 rows, data has 0
Run Code Online (Sandbox Code Playgroud)

i=1

Mic*_*ico 8

你的数据第一:

l = list(
  c("#solarpanels", "#solar"),
  c("#Nuclear", "#Wind", "#solar"),
  "#solar",
  c("#steel", "#windenergy", "#solarenergy", "#carbonfootprint"),
  c("#solar", "#wind")
)
Run Code Online (Sandbox Code Playgroud)

这是一个两行版本:

l = l[lengths(l) > 1L]
data.frame(do.call(rbind, unlist(lapply(l, combn, 2L, simplify = FALSE), recursive = FALSE)))
#              X1               X2
# 1  #solarpanels           #solar
# 2      #Nuclear            #Wind
# 3      #Nuclear           #solar
# 4         #Wind           #solar
# 5        #steel      #windenergy
# 6        #steel     #solarenergy
# 7        #steel #carbonfootprint
# 8   #windenergy     #solarenergy
# 9   #windenergy #carbonfootprint
# 10 #solarenergy #carbonfootprint
# 11       #solar            #wind
Run Code Online (Sandbox Code Playgroud)

更慢,为了清楚起见:

combn(x, k)返回大小的每一个可能的(无序的)子集kx; 你所追求的是来自列表中每个元素的对。默认情况下,它以matrixp = choose(length(x), k)列的形式返回它,但这对您的用例来说不是一种有用的格式;simplify = FALSE将每个子集作为 a 的新元素返回list

所以lapply(l, combn, 2L, simplify = FALSE)看起来像:

# [[1]]
# [[1]][[1]]
# [1] "#solarpanels" "#solar"      
# 
# 
# [[2]]
# [[2]][[1]]
# [1] "#Nuclear" "#Wind"   
# 
# [[2]][[2]]
# [1] "#Nuclear" "#solar"  
Run Code Online (Sandbox Code Playgroud)

(我们必须过滤lfirst的长度为 1 的元素,因为2从长度为 1 的对象中请求元素是错误的,因此是第一行)

lapply(.)一点是您问题的症结所在;其余的只是将输出(已经包含所有正确数据)转换为一种data.frame格式。

首先,lapply输出是嵌套的——它listlists的一个。list长度为 2 的向量更统一;unlist(., recusive=FALSE)通过取消嵌套列表的第一级来实现这一点(使用recursive=TRUE,我们会得到一个很大的长向量并失去配对结构;我们可以使用它,但我认为可能有点不自然)。

接下来,我们将长度为 2 的向量列表转换为矩阵(着眼于最终目标——2 列矩阵很容易转换为 a data.frame);list- >matrix在完成basedo.call(rbind, .)

最后我们把它传给data.frame等等

在 中data.table,我会在一个命令中稍微清洁一点

setDT(transpose(
  unlist(lapply(l[lengths(l) > 1L], combn, 2L, simplify = FALSE), recursive = FALSE)
))[]
Run Code Online (Sandbox Code Playgroud)

鉴于您可能不太关心中间输出,这也是一个使用的好地方magrittr

library(magrittr)
l[lengths(l) > 1L] %>%
  lapply(combn, 2L, simplify = FALSE) %>% 
  unlist(recursive = FALSE) %>%
  do.call(rbind, . ) %>%
  data.frame
Run Code Online (Sandbox Code Playgroud)

它更具可读性,但在这种情况下,很高兴看到这data.frame是预先的最终目标,否则unlist&do.call步骤的意图可能会模糊不清。