【问题标题】:Compare two character vectors in R比较 R 中的两个字符向量
【发布时间】:2013-07-11 15:57:53
【问题描述】:

我有两个 ID 字符向量。

我想比较这两个字符向量,特别是我对以下数字感兴趣:

  • A 和 B 中有多少个 ID
  • A 中有多少个 ID 而 B 中没有
  • B 中有多少个 ID 而 A 中没有

我也想画维恩图。

【问题讨论】:

  • ??intersect??setdiff...
  • 这不是对 R 中“列表”一词的错误使用吗?这只是两个向量。这根本不一样。
  • @Florian 我同意“列表”在 R 术语中是错误的,但这是 OP 认为正确的。如果其他人有同样的错误想法并从谷歌搜索,他们可以正确地登陆这里。出于这个原因,我通常会保守地纠正问题中的错误术语。无论如何,如果您正在疯狂编辑,请记住一些事情。 (顺便说一句,我在下面的答案中使用“set”,因为从概念上讲,这就是这里处理向量的方式。)

标签: r venn-diagram


【解决方案1】:

这里有一些基本的尝试:

> A = c("Dog", "Cat", "Mouse")
> B = c("Tiger","Lion","Cat")
> A %in% B
[1] FALSE  TRUE FALSE
> intersect(A,B)
[1] "Cat"
> setdiff(A,B)
[1] "Dog"   "Mouse"
> setdiff(B,A)
[1] "Tiger" "Lion" 

同样,您可以简单地得到计数:

> length(intersect(A,B))
[1] 1
> length(setdiff(A,B))
[1] 2
> length(setdiff(B,A))
[1] 2

【讨论】:

    【解决方案2】:

    我通常处理大型集合,所以我使用表格而不是维恩图:

    xtab_set <- function(A,B){
        both    <-  union(A,B)
        inA     <-  both %in% A
        inB     <-  both %in% B
        return(table(inA,inB))
    }
    
    set.seed(1)
    A <- sample(letters[1:20],10,replace=TRUE)
    B <- sample(letters[1:20],10,replace=TRUE)
    xtab_set(A,B)
    
    #        inB
    # inA     FALSE TRUE
    #   FALSE     0    5
    #   TRUE      6    3
    

    【讨论】:

    • 啊,我没有意识到维恩图包含计数...我认为它们应该显示项目本身。
    【解决方案3】:

    还有另一种方式,使用 %in% 和公共元素的布尔向量代替 intersectsetdiff。我认为您实际上想要比较两个 vectors,而不是两个 lists - list 是一个可以包含任何类型元素的 R 类,而向量总是只包含一种类型的元素,因此更容易比较真正相等的元素。在这里,元素被转换为字符串,因为这是最不灵活的元素类型。

    first <- c(1:3, letters[1:6], "foo", "bar")
    second <- c(2:4, letters[5:8], "bar", "asd")
    
    both <- first[first %in% second] # in both, same as call: intersect(first, second)
    onlyfirst <- first[!first %in% second] # only in 'first', same as: setdiff(first, second)
    onlysecond <- second[!second %in% first] # only in 'second', same as: setdiff(second, first)
    length(both)
    length(onlyfirst)
    length(onlysecond)
    
    #> both
    #[1] "2"   "3"   "e"   "f"   "bar"
    #> onlyfirst
    #[1] "1"   "a"   "b"   "c"   "d"   "foo"
    #> onlysecond
    #[1] "4"   "g"   "h"   "asd"
    #> length(both)
    #[1] 5
    #> length(onlyfirst)
    #[1] 6
    #> length(onlysecond)
    #[1] 4
    
    # If you don't have the 'gplots' package, type: install.packages("gplots")
    require("gplots")
    venn(list(first.vector = first, second.vector = second))
    

    如前所述,在 R 中绘制维恩图有多种选择。这是使用 gplots 的输出。

    【讨论】:

      【解决方案4】:

      使用sqldf:速度较慢但非常适合混合类型的数据帧:

      t1 <- as.data.frame(1:10)
      t2 <- as.data.frame(5:15)
      sqldf1 <- sqldf('SELECT * FROM t1 EXCEPT SELECT * FROM t2') # subset from t1 not in t2 
      sqldf2 <- sqldf('SELECT * FROM t2 EXCEPT SELECT * FROM t1') # subset from t2 not in t1 
      sqldf3 <- sqldf('SELECT * FROM t1 UNION SELECT * FROM t2') # UNION t1 and t2
      
      sqldf1  X1_10
      1
      2
      3
      4
      sqldf2   X5_15
      11
      12
      13
      14
      15
      sqldf3   X1_10
      1
      2 
      3 
      4 
      5 
      6 
      7
      8
      9
      10
      11
      12
      13      
      14
      15
      

      【讨论】:

        【解决方案5】:

        使用与上述答案之一相同的示例数据。

        A = c("Dog", "Cat", "Mouse")
        B = c("Tiger","Lion","Cat")
        
        match(A,B)
        [1] NA  3 NA
        

        match 函数返回一个向量,该向量的位置位于B 中,而所有值位于A 中。所以,catA 中的第二个元素,是B 中的第三个元素。没有其他匹配项。

        要获取AB中的匹配值,可以这样做:

        m <- match(A,B)
        A[!is.na(m)]
        "Cat"
        B[m[!is.na(m)]]
        "Cat"
        

        获取AB中不匹配的值:

        A[is.na(m)]
        "Dog"   "Mouse"
        B[which(is.na(m))]
        "Tiger" "Cat"
        

        此外,您可以使用length() 获取匹配和不匹配值的总数。

        【讨论】:

          【解决方案6】:

          如果A 是一个data.table,其字段a 的类型为list,条目本身是基本类型的向量,例如创建如下

          A<-data.table(a=c(list(c("abc","def","123")),list(c("ghi","zyx"))),d=c(9,8))
          

          B 是一个带有原始条目向量的列表,例如创建如下

          B<-list(c("ghi","zyx"))
          

          并且您正在尝试查找A$a 的哪个(如果有)元素与B 匹配

          A[sapply(a,identical,unlist(B))]
          

          如果你只想要a中的条目

          A[sapply(a,identical,unlist(B)),a]
          

          如果你想要a的匹配索引

          A[,which(sapply(a,identical,unlist(B)))]
          

          如果 B 本身是一个与 A 具有相同结构的 data.table,例如

          B<-data.table(b=c(list(c("zyx","ghi")),list(c("abc","def",123))),z=c(5,7))
          

          并且您正在寻找两个列表的一列的交集,您需要相同顺序的向量元素。

          # give the entry in A for in which A$a matches B$b
          A[,`:=`(res=unlist(sapply(list(a),function(x,y){
                                                x %in% unlist(lapply(y,as.vector,mode="character"))
                                            },list(B[,b]),simplify=FALSE)))
            ][res==TRUE
            ][,res:=NULL][] 
          
          # get T/F for each index of A
          A[,sapply(list(a),function(x,y){
                                x %in% unlist(lapply(y,as.vector,mode="character"))
                            },list(B[,b]),simplify=FALSE)]
          

          请注意,您不能做这么简单的事情

          setkey(A,a)
          setkey(B,b)
          A[B]
          

          加入 A&B,因为您无法在 data.table 1.12.2 中键入 list 类型的字段

          同样,你不能问

          A[a==B[,b]]
          

          即使 A 和 B 相同,因为 == 运算符尚未在 R 中为类型 list 实现

          【讨论】:

          • Base R + data.table 没有名为 simplify 的函数。也许将所需的 library() 调用放在其他代码之前?
          • 感谢您的收获。看起来它是 purrr 的一部分,它是 hadley tidyverse 的一个组成部分。在这种情况下,它似乎只是对unlist 的调用,因此将替换
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-08-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-03
          • 2010-12-25
          相关资源
          最近更新 更多