【问题标题】:How can I compare two lists and output "hits" into a dataframe如何比较两个列表并将“命中”输出到数据框中
【发布时间】:2017-12-28 15:03:21
【问题描述】:

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

  • 问题 1

我有两个列表(两个 igraph 对象),一个包含 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]] 中的所有元素也在y[[i]] 中找到时)添加到一个新的数据帧。我尝试使用all()%in% 循环,但这不起作用:

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

这将返回 12 个FALSE 命中。检查单个组件,它应该可以工作,因为:

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

按原样返回TRUE,并且:

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

按应有的方式返回 FALSE。我哪里错了?

  • 问题 2

我已经看到了一些将循环结果输出到 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 语句。我觉得这应该很容易执行,而且我应该能够自己解决。不过,感谢您抽出宝贵时间,并对这篇文章感到抱歉。

【问题讨论】:

    标签: r list loops for-loop igraph


    【解决方案1】:

    你错了

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

    【讨论】:

    • 是的。谢谢你=D。这给了我一个包含约 400 个索引对、循环和社区的列表,所以只需整理这个列表即可。
    【解决方案2】:

    问题的最后一部分,循环和社区标签的创建,可以使用stringi::stri_join()(或在 cmets 中指出的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
    > 
    

    【讨论】:

    • 如果这就是目标,那么就不需要你做的所有事情了,你也可以为循环做sapply(x,paste,collapse="_"),为社区做sapply(y,paste,collapse="_")。但是再读一遍这个问题。这个答案完全没有帮助
    【解决方案3】:

    你可以使用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"
    

    【讨论】:

    • 谢谢你,我喜欢这个想法和结果矩阵!不过我最终没有使用它,因为我觉得它对于我的实际数据中的结果数量来说很笨拙
    • 虽然你仍然可以投票,因为它解决了问题
    • 我做到了 ;) 但我的名声太低,无法计算
    猜你喜欢
    • 2021-09-17
    • 2018-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多