【问题标题】:How to get counts of intersections of six or more sets?如何获得六组或更多组的交叉点的计数?
【发布时间】:2024-01-10 10:02:01
【问题描述】:

我正在对多个集合进行分析,我一直在使用 VennDiagram 包,它工作得很好,但它最多只能处理 5 个集合,现在我需要查看 6 个或更多套。

理想情况下,我正在寻找一种可以使用 6 组或更多组执行此操作(如下)的东西,但它不一定必须具有绘图功能,只要可以检索计数即可:

我有什么想法可以将一组或多组添加到这五组中并仍然得到计数?

谢谢!

【问题讨论】:

  • 您的数据是如何表示的?您在这些集合中寻找的项目,以及这些集合本身?
  • 在这种情况下,它们是城市名称的向量(从销售数据库的数据框编译而来)。我正在寻找重叠等以了解市场覆盖率。从上图可以看出,几乎每个人都试图在相同的市场上进行销售。

标签: r set venn-diagram


【解决方案1】:

这是一个递归解决方案,用于查找维恩图中的所有交点。 sets 可以是一个列表,其中包含任意数量的集合以查找其交集。出于某种原因,您正在使用的包中的代码都是针对每个集合大小进行硬编码的,因此它不会扩展到任意交叉点。

## Build intersections, 'out' accumulates the result
intersects <- function(sets, out=NULL) {
    if (length(sets) < 2) return ( out )                               # return result
    len <- seq(length(sets))
    if (missing(out)) out <- list()                                    # initialize accumulator
    for (idx in split((inds <- combn(length(sets), 2)), col(inds))) {  # 2-way combinations
        ii <- len > idx[2] & !(len %in% idx)                           # indices to keep for next intersect
        out[[(n <- paste(names(sets[idx]), collapse="."))]] <- intersect(sets[[idx[1]]], sets[[idx[2]]])
        out <- intersects(append(out[n], sets[ii]), out=out)
    }
    out
}

该函数构建成对的交叉点。为了避免构建重复的解决方案,它只在索引大于连接的索引的集合上调用自己(代码中的ii)。结果是所有交叉点的列表。如果传递命名组件,则结果将按照约定“set1.set2”等命名。

结果

## Some sample data
set.seed(0)
sets <- setNames(lapply(1:3, function(.) sample(letters, 10)), letters[1:3])

## Manually check intersections
a.b <- intersect(sets[[1]], sets[[2]])
b.c <- intersect(sets[[2]], sets[[3]])
a.c <- intersect(sets[[1]], sets[[3]])
a.b.c <- intersect(a.b, sets[[3]])

## Compare
res <- intersects(sets)
all.equal(res[c("a.b","a.c","b.c","a.b.c")], list(a.b=a.b, a.c=a.c, b.c=b.c, a.b.c=a.b.c))
# TRUE

res
# $a.b
# [1] "g" "i" "n" "e" "r"
# 
# $a.b.c
# [1] "g"
# 
# $a.c
# [1] "x" "g"
# 
# $b.c
# [1] "f" "g"

## Get the counts of intersections
lengths(res)
# a.b a.b.c   a.c   b.c 
#   5     1     2     2 

或者,用数字

intersects(list(a=1:10, b=c(1, 5, 10), c=9:20))
# $a.b
# [1]  1  5 10
# $a.b.c
# [1] 10
# $a.c
# [1]  9 10
# $b.c
# [1] 10

【讨论】:

    【解决方案2】:

    这是一个尝试:

    list1 <- c("a","b","c","e")
    list2 <- c("a","b","c","e")
    list3 <- c("a","b")
    list4 <- c("a","b","g","h")
    list_names <- c("list1","list2","list3","list4")
    
    lapply(1:length(list_names),function(y){
    combinations <- combn(list_names,y)
    res<-as.list(apply(combinations,2,function(x){
        if(length(x)==1){
                p <- setdiff(get(x),unlist(sapply(setdiff(list_names,x),get)))
            }
    
        else if(length(x) < length(list_names)){
                p <- setdiff(Reduce(intersect,lapply(x,get)),Reduce(union,sapply(setdiff(list_names,x),get)))
            }
    
        else p <- Reduce(intersect,lapply(x,get))
    
        if(!identical(p,character(0))) p
        else NA
    }))
    
    if(y==length(list_names)) {
            res[[1]] <- unlist(res); 
            res<-res[1]
    }
    names(res) <- apply(combinations,2,paste,collapse="-")
    res
    })
    

    第一个 lapply 用于从 1 循环到您拥有的集合数。然后我取了所有可能的列表名称组合,一次取 y。这实际上生成了维恩图中的所有不同子区域。

    对于每个组合,输出是当前组合中列表的交集与不在组合中的其他列表的并集之间的差。

    最终的结果是一个长度列表,输入集合的数量。该列表的第一个元素包含每个列表中的唯一元素,第二个元素包含两个列表的任意组合中的唯一元素,等等。

    【讨论】:

      【解决方案3】:

      好的,这是一种方法,假设您将集合表示为向量列表,并且在这些集合中要搜索的项目也表示为向量:

      # Example data format
      sets <- list(v1 = 1:6, v2 = 1:8, v3 = 3:8)
      items <- c(2:7)
      
      # Search for items in each set
      result <- data.frame(searched = items)
      for (set in names(sets)) {
        result <- cbind(result, items %in% sets[[set]])
        names(result)[length(names(result))] <- set
      }
      
      # Count
      library(plyr)
      ddply(result, names(sets), function (i) {
        data.frame(count = nrow(i))
      })
      

      这为您提供了项目集中实际存在的所有组合:

           v1   v2    v3 count
      1 FALSE TRUE  TRUE     1
      2  TRUE TRUE FALSE     1
      3  TRUE TRUE  TRUE     4
      

      【讨论】:

      • 计数是多少?最后一行有 3 个 TRUE,但计数是 4..?我需要知道每个交叉点的元素数量
      • 也许我无法理解您的输出。对于您示例中的数据,我想知道 V_1 \cap V_2 = {1, 2} = 2 中的元素数, V_2 cap V_3 = {7, 8} = 2 中的元素数并且 V_1 \cap V_2 \cap V_3 = {3,4,5,6} = 4 中的元素数,并且所有其他交叉点都是空的。
      • 好的,我可能已经解决了一个更普遍的问题。把所有集合的总和放在变量items 下,你就会得到你需要的。上面的代码允许检查与任意其他集合相交的集合。因此,结果数据框中的一行显示了items 变量中有多少项属于 v_i,它们是 True。所以第 1 行告诉您 (v2,v3) 集中有 1 个项目。第 2 行表示 (v1, v2) 集中有 1 个项目。第 3 行表示 (v1, v2, v3) 集合中有项目。设置 (v1,v2) 我的意思是 v1 和 v2 的交集。如果你把 ` items
      • 我想我的问题标题也有点用词不当。我不是在寻找一种计算交叉点的方法,而是在寻找交叉点中元素的数量:)
      • 好吧,我的回复确实为您提供了每个交叉点的大小(count 列)和非空交叉点的数量(=data.frame 中的行数)。
      最近更新 更多