比较R中的两个字符向量

gk7wooem  于 2023-05-26  发布在  其他
关注(0)|答案(7)|浏览(179)

我有两个ID的特征向量。
我想比较两个字符向量,特别是我对以下数字感兴趣:

  • A和B中有多少个ID
  • 有多少个ID在A中但不在B中
  • 有多少个ID在B而不在A

我也喜欢画一张维恩图。

xv8emn3q

xv8emn3q1#

以下是一些基本的尝试:

> 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
ffdz8vbo

ffdz8vbo2#

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

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
zbq4xfa0

zbq4xfa03#

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

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的输出。

vsmadaxz

vsmadaxz4#

使用sqldf:较慢,但非常适合混合类型的 Dataframe :

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
wribegjk

wribegjk5#

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

A = c("Dog", "Cat", "Mouse")
B = c("Tiger","Lion","Cat")

match(A,B)
[1] NA  3 NA

match函数返回一个向量,其中包含A中所有值在B中的位置。因此,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()来获取匹配和不匹配值的总数。

xkftehaa

xkftehaa6#

如果A是一个数据表,其字段a为列表类型,其条目本身为原始类型的向量,例如创建如下

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具有相同结构的数据表,例如

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]

因为你不能在数据中键入list类型的字段。表1.12.2
同样,你不能问

A[a==B[,b]]

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

xqkwcwgp

xqkwcwgp7#

您可以在r控制台中输入help(sets),以查看使用base r命令的不同set操作的文档:并集、交集、(不对称!)两个向量上的差异、相等和隶属关系。
文档中的示例:

(x <- c(sort(sample(1:20, 9)), NA))
(y <- c(sort(sample(3:23, 7)), NA))
union(x, y)
intersect(x, y)
setdiff(x, y)
setdiff(y, x)
setequal(x, y)

## True for all possible x & y :
setequal( union(x, y),
          c(setdiff(x, y), intersect(x, y), setdiff(y, x)))

is.element(x, y) # length 10
is.element(y, x) # length  8

相关问题