Более общая функция для количества совпадающих элементов среди n элементов списка

Я пытаюсь вычислить количество общих записей среди элементов списка:

temp<-list(element1=c("a","b","c"), element2=c("b","c","d"), 
           element3=c("d","e","f"), element4=c("a","c","z"))

Чтобы получить перекрытие между всеми попарными комбинациями элементов, эта функция работает:

calculate.overlap.2<-function(y){
  pw<-combn(y,2,FUN=function(x)sum(x[[1]]%in%x[[2]]))
  names(pw)<-combn(y,2,FUN=function(x)paste(names(x)[[1]],names(x)[[2]],sep="-"))
  return(pw)
}

Чтобы получить перекрытие между всеми трехсторонними комбинациями элементов, эта функция работает:

calculate.overlap.3<-function(y){
   pw<-combn(y,3,FUN=function(x)sum(x[[1]]%in%x[[2]]&x[[1]]%in%x[[3]]))
   names(pw)<-combn(y,3,FUN=function(x) paste(names(x)[[1]],names(x)[[2]],names(x)[[3]],sep="-"))
   return(pw)
}

но, как вы можете сказать по номерам внутри функции, это не изящное решение.

Было бы здорово обобщить эти две функции на единицу и иметь функцию в качестве входных элементов для каждой проверки перекрытия. То есть, вход number.of.elements.per.comparison=2 будет эквивалентен calculate.overlap.2 выше, а вход в функцию number.of.elements.per.comparison=3 будет таким же, как calculate.overlap.3.

Я чувствую, что есть очень элегантное решение, но я просто не вижу его.

Ответ 1

calculate.overlap <- function(y, i){
  pw <- combn(seq_along(y), i, FUN= function(x) {
    res <- length(Reduce(intersect, y[x]))
    names(res) <- paste(names(y[x]), collapse = "-")
    res
  }, simplify = FALSE)
  do.call(c, pw)
}

calculate.overlap(temp, 3)
#element1-element2-element3 element1-element2-element4 element1-element3-element4 element2-element3-element4 
#                         0                          1                          0                          0 

Ответ 2

Вот подход:

ix = lapply(seq_along(temp), function(u) combn(seq_along(temp), u))

lapply(ix, function(m){
    res = apply(m,2, function(v) length(Reduce(intersect, temp[v])))
    setNames(res, apply(m, 2, paste, collapse='-'))
})

#[[1]]
#1 2 3 4 
#3 3 3 3 

#[[2]]
#1-2 1-3 1-4 2-3 2-4 3-4 
#  2   0   2   1   1   0 

#[[3]]
#1-2-3 1-2-4 1-3-4 2-3-4 
#    0     1     0     0 

#[[4]]
#1-2-3-4 
#      0 

Ответ 3

В пакете VennDiagram есть функция с именем calculate.overlap, которая делает именно это. Вы даже можете просмотреть список и посмотреть, какие элементы находятся на каждом перекрестке, если вам нужно их увидеть. Вы можете делать перекрытия списка с до 5 суб-списками.

ссылка на пакет https://cran.r-project.org/web/packages/VennDiagram/index.html