r - 如何执行像 `%in%` 这样的成对操作并为向量列表设置操作

标签 r

这个问题的动机是 How can I quickly see if any elements of multiple vectors are equal in R? ,但不相同/重复。

作为一个小例子,假设我们有一个包含 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% 这样的成对二元运算并设置操作说 intersect , union , setdiff ?

假设我们想要成对 "%in%" ,如何进一步执行any()/all()/which()每对内?

注意:我不想使用 combn() .

最佳答案

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

例如,成对应用 "%in%"操作,我们使用

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%"本身不是矢量化的,我们使用 Vectorized("%in%") .我们也需要SIMPLIFY = FALSE ,所以 FUN为每对返回一个长度为 1 的列表 (x[[i]], y[[j]]) .这很重要,因为 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)成为“ list ”。阅读 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

设置操作如 intersect , unionsetequal也是我们可以类似处理的对称操作。

示例 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() ,我们也可以使用 R 表达式来获得 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
#  ...

关于r - 如何执行像 `%in%` 这样的成对操作并为向量列表设置操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39066356/

相关文章:

r - 合并 2 个具有不同列名的数据框

r - 是否有 R 函数在另一个向量中查找向量?

r - 如何直接将R中的write.csv执行为tar.gz格式?

r - 使用组内完整的 dplyr 填充 data.frame 中的缺失值

r - 如何在 R 的时间序列中滞后日期索引?

r - 从 h2o 中的 csv 导入选定的列

r - 根据另一个数据帧中的匹配条件将列添加到 R 中的数据帧

根据列匹配返回其他行中存在的值

r - 一次使用多个变量透视更长的时间

r - 将 XTS 对象转换为 data.frame