如何比较两个列表并将 "hits" 输出到数据框中

How can I compare two lists and output "hits" into a dataframe

我试图在这里和 google 上找到答案,但没有成功,我已经为这个问题苦苦挣扎了几天,所以非常感谢帮助。我正在分析一个网络,看看周期是否倾向于在谨慎的社区内或它们之间,或者没有模式。我的数据是一个循环列表(三个节点形成一个循环)和一个社区列表(可变数量的节点)。我有两个问题,1) 如何比较两个列表,以及 2) 如何以可读的方式输出比较结果:

我有两个列表(都是 igraph objects),一个包含 678 个项目(每个 3 个元素,所有字符),另一个包含 11 个项目,每个项目具有不同数量的元素。示例:

x1 <- as.character(c(1,3,5))
x2 <- as.character(c(2,4,6))
x3 <- as.character(c(7,8,9))
x4 <- as.character(c(10,11,12))
x <- list(x1, x2, x3, x4)

y1 <- as.character(c(1,2,3,4,5))
y2 <- as.character(c(2,3,4,5))
y3 <- as.character(c(1,2,3,4,5,7,8,9))
y <- list(y1, y2, y3)

给予:

> x
[[1]]
[1] "1" "3" "5"

[[2]]
[1] "2" "4" "6"

[[3]]
[1] "7" "8" "9"

[[4]]
[1] "10" "11" "12"

> y
[[1]]
[1] "1" "2" "3" "4" "5"

[[2]]
[1] "2" "3" "4" "5"

[[3]]
[1] "1" "2" "3" "4" "5" "7" "8" "9"

我想将 x 中的每个组件与 y 中的每个组件进行比较并添加每个命中(即当 x[[i]] 中的所有元素也在 [=20= 中找到时]) 到一个新的数据框。我尝试使用 all()%in% 进行循环,但这没有用:

for (i in 1:length(x)) {
  for (j in 1:length(y)) {
    hits <- all(y[[j]] %in% x[[i]]) == TRUE
    print(hits)
      }
    }

这 returns 12 FALSE 命中。检查单个组件,它应该有效,因为:

all(x[[1]] %in% y[[1]])

Returns TRUE 应该的,并且:

all(x[[1]] %in% y[[2]])

Returns FALSE 应该的。我哪里错了?

我看到了一些将循环结果输出到 df 的解决方案,但这并不是我所需要的。我想要的输出是一个数据框,它告诉我每个周期在哪个社区。由于只有 11 个社区,它可以只让我参考列表组件的索引,但我还没有找到执行此操作的方法。我也可以只使用 paste() 将社区的节点名称连接成一个标题。无论哪种方式,这是我需要的输出:

  cycle       community
1 1_3_5       1_2_3_4_5
2 1_3_5 1_2_3_4_5_7_8_9
3 7_8_9 1_2_3_4_5_7_8_9

我猜是某种 if 语句。我觉得这应该很容易执行,而且我应该能够自己解决。不过,感谢您抽出宝贵时间,对这篇文章感到抱歉。

你弄错了

for (i in 1:length(x)) {
    for (j in 1:length(y)) {
    # hits <- all(y[[j]] %in% x[[i]]) == TRUE
    hits <- all(x[[i]] %in% y[[j]]) == TRUE
    print(hits)
    }
}

对于第二部分,您可以存储命中的索引以备后用。

a <- list()
for (i in 1:length(x)) {
    for (j in 1:length(y)) {
    # hits <- all(y[[j]] %in% x[[i]]) == TRUE
    hits <- all(x[[i]] %in% y[[j]]) == TRUE
    if(hits == TRUE){
        a[[length(a)+1]] <- c(i,j)
        }
    }
}

问题的最后一部分,即循环和社区标签的创建,可以使用 stringi::stri_join()(或评论中指出的 paste())来完成。整理 Jt Miclat 的答案中创建的列表的最后一步如下,使用列表 a 中的索引为 cyclecommunity 提取适当的字符串,生成数据帧,然后rbind() 结果到单个数据框。

# combine with cycle & community tags 
cycles <- sapply(x,paste,collapse="_")
communities <- sapply(y,paste,collapse="_")
b <- lapply(a,function(x){
     cycle <- cycles[x[1]]
     community <- communities[x[2]]
     data.frame(x=x[1],y=x[2],cycle=cycle,community=community,
                stringsAsFactors=FALSE)
})
df <- do.call(rbind,b)
df

...输出:

> df <- do.call(rbind,b)
> df
  x y cycle       community
1 1 1 1_3_5       1_2_3_4_5
2 1 3 1_3_5 1_2_3_4_5_7_8_9
3 3 3 7_8_9 1_2_3_4_5_7_8_9
> 

你可以利用 outer:

  outer(x,y,function(w,z)Map(function(i,j)all(i%in%j),w,z))->results
      [,1]  [,2]  [,3]
[1,]  TRUE FALSE  TRUE
[2,] FALSE FALSE FALSE
[3,] FALSE FALSE  TRUE
[4,] FALSE FALSE FALSE

x 是行,而 y 是列,所以要检查 all(x[[1]]%in%y[[2]]),只需检查第 1 行第 2 列,即元素 [1,2] 等。

然后您可以使用 apply 和自己创建的函数:

 fun<-function(i)c(paste(x[[i[1]]],collapse ="_"), paste(y[[i[2]]],collapse ="_"))
 t(apply(which(result==T,T),1,fun))
     [,1]    [,2]             
[1,] "1_3_5" "1_2_3_4_5"      
[2,] "1_3_5" "1_2_3_4_5_7_8_9"
[3,] "7_8_9" "1_2_3_4_5_7_8_9"