【问题标题】:How to return the unique elements between vectors while retaining the source vector of these unique elements?如何在保留这些唯一元素的源向量的同时返回向量之间的唯一元素?
【发布时间】:2020-11-13 11:40:10
【问题描述】:

例如,我在一个列表中有 5 个向量:

A <- c(1,2,3,4,5)

B <- c(1,2,3,4,5,6)

C <- c(5,6,7,8,9)

D <- c(8,9)

实际上,我有 100 个这些向量,但我只给出了 5 个向量以实现可重复性。 我的目标是:

  1. 识别来自向量的唯一元素。例如,vector A 不应该返回任何内容,因为它的所有元素都是vector B 的一部分,但是vector B 确实贡献了一个额外的独特元素,那就是6Vector C 应该给我7,8,9,因为c(5,6) 已经包含在vector B 中。 Vector D 应该什么都不返回,因为它的所有元素都是 C 的一部分
  2. 从哪个向量中识别哪个元素是唯一的
  3. 找出哪些向量是其他更大向量的子集。例如,vector DC 的子集,vector Avector B 的子集。

到目前为止,我找到的唯一解决方案是:

Reduce(setdiff, list("my_vectors"))

但是它不允许我从哪个向量中识别出哪个元素是唯一的。例如,Reduce(setdiff, list(A,B)) 会返回6,但我不知道6 来自哪里(AB)?

我的困难在于这是一个大规模的问题,我没有 5 个向量,我有 100 个向量,所以我无法找到可持续的解决方案。任何提示都表示赞赏。

编辑:我的向量在一个列表中

【问题讨论】:

  • 向量是在.GlobalEnv 中还是在列表中?
  • 它们在一个列表中。所以我有一个向量列表。
  • 在您的示例中,没有独占密码。
  • 这没有很好的定义:例如 A 不应该返回任何东西,因为 B 包含 A 中的所有元素,但 B 应该返回 6。但是,6 也包含在 C 中。所以这里唯一真正唯一的你有的元素是 C 中的 7 对吗?
  • 没错。这是相当模棱两可的。

标签: r list vector unique data-mining


【解决方案1】:

假设您的数据是这样存储的:

my_vectors <- list(
  A = c(1,2,3,4,5),
  B = c(1,2,3,4,5,6),
  C = c(5,6,7,8,9),
  D = c(8,9)
)

如果你使用accumulate = TRUE 来调用Reduce,你也会得到每个中间结果。我们可以将它与union 一起使用来逐步建立总集(注意我设置了init = c() 以确保我们开始为空):

acc <- Reduce(union, my_vectors, init = c(), accumulate = T)

然后,我们可以使用这个构建列表获取每个项目的setdiff

lapply(1:length(my_vectors), function(i) setdiff(my_vectors[[i]], acc[[i]]))

这给了

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

[[2]]
[1] 6

[[3]]
[1] 7 8 9

[[4]]
numeric(0)

如果需要,您可以稍后应用 my_vectors 的名称。

【讨论】:

    【解决方案2】:

    第一种天真的方法是 for 循环,只是为了有一个可行的解决方案。 该函数返回一个包含 unqiue 元素和数据框的列表,描述唯一元素(第一个外观)来自 vectorList 中的哪个向量。

    A <- c(1,2,3,4,5)
    B <- c(1,2,3,4,5,6)
    C <- c(5,6,7,8,9)
    D <- c(8,9)
    
    vectorList <- list(A,B,C,D)
    
    ff <- function(vectorList) {
      uniques <- unique(vectorList[[1]])
      comingFromDf <- data.frame(values=uniques)
      comingFromDf$source <- 1
      
      for(k in 2:length(vectorList)) {
        vec <- vectorList[[k]]
        newUniques <- vec[!(vec %in% uniques)]
        if(length(newUniques)) {
          newUniques <- unique(newUniques)
          toAdd <- data.frame(values=newUniques)
          toAdd$source <- k
          comingFromDf <- rbind(comingFromDf,toAdd)
          uniques <- c(uniques,newUniques)
        }
      }
      
      list(uniqueElements = uniques,
           comingFromInfo = comingFromDf)
    }
    
    ff(vectorList)
    

    我不知道您需要该函数的性能如何,但即使有 200 个长度为 1000 的向量,它似乎也很快退出(我不知道您的尺寸):

    bigVectorList <- lapply(1:200, function(k) {
      sample(1:1e6,1000)
    })
    
    microbenchmark::microbenchmark(ff(bigVectorList),times=10)
    #Unit: milliseconds
    #              expr      min       lq     mean   median      uq      max neval
    #ff(bigVectorList) 619.5148 624.8351 639.7535 633.2326 647.118 685.0387    10
    

    在我的机器上,花了半秒多一点,也许对你来说就足够了。由于该函数仅包含向量和数据框,因此很容易在 C++ 中重新实现它并使用 Rcpp。这应该比R中的for循环实现要快得多。此外,您可以考虑在Reduce-function中使用accumulate-argument来保存中间计算结果。

    【讨论】:

      【解决方案3】:

      这是tidyverse 解决方案。

      lag(accumulate(l, union)) 跟踪到目前为止看到的所有元素。此列表与原始列表之间的差异产生了新出现的元素。

      library(tidyverse)
      
      l <- lst(A, B, C, D)
      
      map2(l, lag(accumulate(l, union)), setdiff)
      #> $A
      #> [1] 1 2 3 4 5
      #> 
      #> $B
      #> [1] 6
      #> 
      #> $C
      #> [1] 7 8 9
      #> 
      #> $D
      #> numeric(0)
      

      这是您关于查找哪些向量是其他更大向量的子集的其他问题的答案。

      expand_grid 将获得向量的所有组合。过滤它以找出哪个向量是任何其他向量的子集。

      l %>%
        enframe() %>%
        expand_grid(a = ., b = .) %>%
        filter(
          a$name != b$name,
          map2_lgl(a$value, b$value, ~all(.x %in% .y))
        ) %>%
        transmute(this_vector = a$name, is_a_subset_of_this_vector = b$name)
      #> # A tibble: 2 x 2
      #>   this_vector is_a_subset_of_this_vector
      #>   <chr>       <chr>                     
      #> 1 A           B                         
      #> 2 D           C 
      

      【讨论】:

        【解决方案4】:

        这里只有一个真正独特的元素,即7 in C。下面将返回唯一元素及其成员身份

        mylist <- list("A"=A,"B"=B,"C"=C,"D"=D) #better for 100's of vectors
        myres <- !unlist(lapply(1:length(mylist), function(x) unlist(mylist[x]) %in% unlist(mylist[-x])))
        result <- as.numeric(unlist(mylist)[myres])
        member <- sapply(mylist, function(x) result %in% x)
        membername <- names(mylist[member])
        result
        membername
        > result
         7 
        > membername
        [1] "C"
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-09-25
          • 2022-11-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多