我想在 R 中合并多个 OR 和 AND 条件。我认为x1 == 1 | x1 == 2可以合并为x1 %in% c(1, 2).我想知道如何将x1 == 1 | y1 == 1x1 == 1 & y1 == 1合并为更紧凑的R代码。

x1 <- c(1, 2, 3)
y1 <- c(1, 2, 4)

x1 == 1 | x1 == 2
#> [1]  TRUE  TRUE FALSE
x1 %in% c(1, 2)
#> [1]  TRUE  TRUE FALSE

x1 == 1 | y1 == 1
#> [1]  TRUE FALSE FALSE

intersect(x1, y1) == 1
#> [1]  TRUE FALSE
intersect(x1, y1) == 2
#> [1] FALSE  TRUE

intersect(x1, y1) %in% c(1, 2)
#> [1] TRUE TRUE

> x1 == 1 & y1 == 1
[1]  TRUE FALSE FALSE

5

  • 1
    感谢@r2evans 的评论。的输出x1 == 1 & y1 == 1TRUE FALSE FALSEall(c(x1, y1) == 1)给出输出FALSE。有什么想法吗?


    – 

  • 1
    抱歉,这是一个飞过的评论,没有帮助。


    – 

  • 我想不出有什么比这些原始操作更好或更快的代码高尔夫了。


    – 

  • 1
    你的向量是整数吗? IEx1*y1 == 1


    – 

  • 1
    NA如果发生,请小心,c(1, NA, 4) == 1 | c(1, NA, 4) == 2与 不同c(1, NA, 4) %in% c(1, 2)与 的`%in%`相关性大于与 的相关性?match`==`


    – 


2 个回答
2

创建一些数据

看起来不太x1 == 1 | y1 == 1冗长,让我们创建更多向量:

set.seed(1)
lapply(1:10, \(.) sample(10, 10, replace = TRUE)) |>
    setNames(paste0(c("x", "y"), c(1:5, 1:5))) |>
    list2env(.GlobalEnv)
ls()
#  [1] "x1" "x2" "x3" "x4" "x5" "y1" "y2" "y3" "y4" "y5"

现在写起来确实变得相当乏味:

x1 == 1 | y2 == 1 | x3 == 1 | y4 == 1 | x5 == 1 | y1 == 1 | x2 == 1 | y3 == 1 | x4 == 1 | y5 == 1 
#  [1] FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE

使用数据框

我们使用逐元素逻辑运算符,因此保证向量具有相同的长度。让我们将它们放入数据框中进行比较:

compare  <- function(..., op = c("==", "<", ">", ">=", "<=", "!="), compare_with = 1) {
    fun = match.fun(match.arg(op))
    rowSums(
        fun(data.frame(...), compare_with)
    ) > 0
}

然后我们可以这样做:

compare(x1, y2, x3, y4, x5, y1, x2, y3, x4, y5)
#  [1] FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE

或者,如果这仍然需要太多的输入,我们可以将向量放入列表中(无论如何这更好),并将其提供给函数:

# Create a list of x1:x5 and y1:y5
l  <- mget(ls(pattern = "[xy]\\d"))
compare(l)
#  [1] FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE  TRUE  TRUE

一些测试

==这也适用于其他运营商。

identical(
    compare(x1, y2, x3, y4, x5, y1, x2, y3, x4, y5, op = "==", compare_with = 1),
    x1 == 1 | y2 == 1 | x3 == 1 | y4 == 1 | x5 == 1 | y1 == 1 | x2 == 1 | y3 == 1 | x4 == 1 | y5 == 1 
)
# [1] TRUE

identical(
    compare(x1, y2, x3, y4, x5, y1, x2, y3, x4, y5, op = ">", compare_with = 9),
    x1 > 9 | y2 > 9 | x3 > 9 | y4 > 9 | x5 > 9 | y1 > 9 | x2 > 9 | y3 > 9 | x4 > 9 | y5 > 9 
)
# [1] TRUE

表现

使用数据框(而不是矩阵)的优点是它只是指向每个向量的指针列表。这意味着不会创建数据副本。此外,数据框支持按元素进行这些比较操作,而无需迭代列(或行),因此即使您的数据非常大,这也应该相当快。

1)以下检查 x1[i] 和 y1[i] 均为 1,即 AND。

x1 <- c(1, 2, 3, 1)
y1 <- c(1, 2, 4, 3)

paste(x1, y1) == "1 1"
## [1]  TRUE FALSE FALSE FALSE

2)如果我们知道向量由 >= 1 的整数组成,如问题中所示,那么我们可以使用 pmin 和 pmax。请注意,它们具有可选的 na.rm= 参数,可以将其设置为处理 NA。

pmin(x1, y1) == 1        # OR
## [1]  TRUE FALSE FALSE TRUE

pmax(x1, y1) == 1        # AND
## [1]  TRUE FALSE FALSE FALSE

所有上述内容都很容易推广到 2 个以上的向量。

3)只涉及x1的问题中的表达式可以稍微缩短

x1 %in% 1:2
## [1]  TRUE  TRUE FALSE  TRUE

4)我们可以将 x1 和 y1 的情况视为广义矩阵乘法,其中 * 替换为 ==,+ 替换为 | 之一。或者 & 。在 APL 语言中,这是 =.v 和 =.^ 。 (有关其他实现,请参阅和 blockmodeling::genMatrixMult。)

`%==.|%` <- function(x, y) apply(t(x) == y, 2, any)
`%==.&%` <- function(x, y) apply(t(x) == y, 2, all)

cbind(x1, y1) %==.&% c(1, 1)
## [1]  TRUE FALSE FALSE FALSE

cbind(x1, y1) %==.|% c(1, 1)
## [1]  TRUE FALSE FALSE  TRUE

4

  • 我的想法是定义中缀运算符,但如果数据大小合理,我认为cbind.data.frame(x1, y1)更好,因为它不会复制数据。


    – 


  • 在 R 中,矩阵乘法是在矩阵上完成的,而不是在数据帧上完成的,因此如果你想保持类比,输入需要是一个矩阵。


    – 

  • 我没明白你的意思——也许是因为我不知道 APL。您是说在某些情况下cbind(x1, y1) %==.&% c(1, 1)会给出不同的输出吗data.frame(x1, y1) %==.&% c(1, 1)?或者您是说由于与矩阵乘法在概念上相似而使用矩阵更好?或两者?


    – 

  • 尝试BOD %*% 1:2 其中 BOD 是内置数据框 您会收到错误,因为数据框不能作为矩阵乘法的参数。


    –