2016-08-21 35 views
4

此问题由How can I quickly see if any elements of multiple vectors are equal in R?驱动,但不完全相同/重复。如何执行配对操作(如'%in%')并设置操作列表向量

作为一个小例子,假设我们有4个矢量的列表:

set.seed(0) 
lst <- list(vec1 = sample(1:10, 2, TRUE), vec2 = sample(1:10, 3, TRUE), 
      vec3 = sample(1:10, 4, TRUE), vec4 = sample(1:10, 5, TRUE)) 

我们如何执行成对二进制运算像%in%和设置操作说intersectunionsetdiff

假设我们想要配对"%in%",我们怎样才能在每一对中进一步执行any()/all()/which()

注意:我不想使用combn()

+1

也许不能直接适用,但在这里,在类似案件中,经典的'表/(T)crossprod'方法可以透露一些成对的关系 - 'crossprod( table(val = unlist(lst,,FALSE),vec = rep(seq_along(lst),lengths(lst))))'。尽管通过制表所有内存限制可能会造成问题 –

回答

4

我们可以使用outer(x, y, FUN)xy不需要是像数值向量/矩阵那样的“数字”输入;像“list”/“矩阵列表”这样的矢量输入也是允许的。

例如,我们用

z <- outer(lst, lst, FUN = Vectorize("%in%", SIMPLIFY = FALSE, USE.NAMES = FALSE)) 
#  vec1  vec2  vec3  vec4  
#vec1 Logical,2 Logical,2 Logical,2 Logical,2 
#vec2 Logical,3 Logical,3 Logical,3 Logical,3 
#vec3 Logical,4 Logical,4 Logical,4 Logical,4 
#vec4 Logical,5 Logical,5 Logical,5 Logical,5 

由于"%in%"本身不是矢量申请配对"%in%"操作,我们使用Vectorized("%in%")。我们还需要SIMPLIFY = FALSE,以便FUN为每对(x[[i]], y[[j]])返回一个长度为1的列表。这一点很重要,因为outer作品,如:

y[[4]] | FUN(x[[1]], y[[4]]) FUN(x[[2]], y[[4]]) FUN(x[[1]], y[[4]]) FUN(x[[2]], y[[4]]) 
y[[3]] | FUN(x[[1]], y[[3]]) FUN(x[[2]], y[[3]]) FUN(x[[1]], y[[3]]) FUN(x[[2]], y[[4]]) 
y[[2]] | FUN(x[[1]], y[[2]]) FUN(x[[2]], y[[2]]) FUN(x[[1]], y[[2]]) FUN(x[[2]], y[[4]]) 
y[[1]] | FUN(x[[1]], y[[1]]) FUN(x[[2]], y[[1]]) FUN(x[[1]], y[[1]]) FUN(x[[2]], y[[4]]) 
     ------------------- ------------------- ------------------- ------------------- 
     x[[1]]    x[[2]]    x[[3]]    x[[4]] 

必须确信length(FUN(x, y)) == length(x) * length(y)。虽然如果SIMPLIFY = FALSE,这并不一定成立。

以上结果z是“矩阵列表”,其中class(z)为“矩阵”,但typeof(z)为“列表”。请阅读Why is this matrix not numeric?了解更多信息。


如果我们想进一步施加一定的汇总函数的z每个元素,我们可以使用lapply。这里我会举两个例子。

实施例1:应用any()

由于any(a %in% b)any(b %in% a)为相同的,即,操作是对称的,我们只需要具有z下三角的工作:

lz <- z[lower.tri(z)] 

lapply返回一个未命名的列表,但为了便于阅读,我们需要一个命名列表。我们可以利用矩阵索引(i, j)姓名:

ind <- which(lower.tri(z), arr.ind = TRUE) 
NAME <- paste(ind[,1], ind[,2], sep = ":") 
any_lz <- setNames(lapply(lz, any), NAME) 

#List of 6 
# $ 2:1: logi FALSE 
# $ 3:1: logi TRUE 
# $ 4:1: logi TRUE 
# $ 3:2: logi TRUE 
# $ 4:2: logi FALSE 
# $ 4:3: logi TRUE 

Set操作像intersectunionsetequal也是我们能与工作同样对称操作。

例2:应用which()

which(a %in% b)不是对称的操作,所以我们必须用全矩阵工作。

NAME <- paste(1:nrow(z), rep(1:nrow(z), each = ncol(z)), sep = ":") 
which_z <- setNames(lapply(z, which), NAME) 

# List of 16 
# $ 1:1: int [1:2] 1 2 
# $ 2:1: int(0) 
# $ 3:1: int [1:2] 1 2 
# $ 4:1: int 3 
# $ 1:2: int(0) 
# $ 2:2: int [1:3] 1 2 3 
# ... 

setdiff这样的设置操作也是不对称的,可以类似地处理。


替代

除了使用outer(),我们也可以使用ř表达式来获得z上方。同样,我采取二元运算"%in%"为例:

op <- "'%in%'" ## operator 

lst_name <- names(lst) 
op_call <- paste0(op, "(", lst_name, ", ", rep(lst_name, each = length(lst)), ")") 
# [1] "'%in%'(vec1, vec1)" "'%in%'(vec2, vec1)" "'%in%'(vec3, vec1)" 
# [4] "'%in%'(vec4, vec1)" "'%in%'(vec1, vec2)" "'%in%'(vec2, vec2)" 
# ... 

然后我们可以在lst分析和评估这些表达式。我们可能会使用组合索引结果列表中的名称:

NAME <- paste(1:length(lst), rep(1:length(lst), each = length(lst)), sep = ":") 
z <- setNames(lapply(parse(text = op_call), eval, lst), NAME) 

# List of 16 
# $ 1:1: logi [1:2] TRUE TRUE 
# $ 2:1: logi [1:3] FALSE FALSE FALSE 
# $ 3:1: logi [1:4] TRUE TRUE FALSE FALSE 
# $ 4:1: logi [1:5] FALSE FALSE TRUE FALSE FALSE 
# $ 1:2: logi [1:2] FALSE FALSE 
# ...