首页 > 解决方案 > 测试一个向量是否是另一个向量的最有效的方法

问题描述

我目前的解决方案是测试一个向量是否包含与另一个向量相同的值,而不管顺序如何

test_perm <- function(a, b) identical(sort(a), sort(b))
test_perm(1:4, 4:1) # TRUE
test_perm(1:4, 1:4) # TRUE
test_perm(1:4, 1:5) # FALSE
test_perm(4:1, 4:1) # TRUE

被迫排序ab首先感觉有点不对,所以我想知道规范的方式是什么,即R如果我最关心速度,推荐的方式是什么?

(感谢@sindri 的评论小更新)

标签: r

解决方案


这里有两种策略,包benchmark()中的函数提供了基准数据rbenchmark

# Your strategy using identical(). Note that I sort a and b in case a is not ordered.
set.seed(123)
a <- sample(1:1000, 100, replace = FALSE)
b <- sample(1:1000, 100, replace = FALSE)
identical(sort(a), sort(b))
> FALSE

# using anti_join() from dplyr. Anti-join returns the rows in a that are not in b.
library(dplyr)
set.seed(123)
a <- sample(1:1000, 100, replace = FALSE)
b <- sample(1:1000, 100, replace = FALSE)
diff <- anti_join(data.frame(a), data.frame(b), by = c("a" = "b"))
nrow(diff) == 0  # if all rows in a are in b, diff should have zero rows
> FALSE

现在这里是基准数据:

library(rbenchmark)
set.seed(123)
a <- sample(1:1000, 100)
b <- sample(1:1000, 100)

benchmark( 
  "sort_identical" = {
    identical(sort(a), sort(b))
  },
  "anti_join" = {
    require(dplyr)
    diff <- anti_join(data.frame(a), data.frame(b), by = c("a" = "b"))
    nrow(diff) == 0
  },
  replications = 1000,
  columns = c("test", "replications", "elapsed",
          "relative", "user.self", "sys.self")
  )

            test replications elapsed relative user.self sys.self
2      anti_join         1000    2.47   22.455      2.41        0
1 sort_identical         1000    0.11    1.000      0.11        0

实际的基准测试数据将取决于您的系统资源,但identical()与我的其他想法相比,您在排序后使用的方法非常快anti_join()。希望您也可以从这个答案中得出结论,您可以自己测试代码的速度。我碰巧喜欢这个rbenchmark包裹,但这个microbenchmark包裹也很好。

因为它是一个通用的基本 R 函数,所以我们可以期待sort()它的表现非常好。但是,如果您阅读排序的帮助文件,您会发现它实际上使用内部通用原始函数xtfrm()对数值数据进行排序。如果你能保证你的数据是数字的,你可以通过xtfrm()直接调用来提高速度。xtfrm()其他类型的数据可能会更慢。

set.seed(123)
a <- sample(1:1000, 100)
b <- sample(1:1000, 100)

benchmark( 
  "sort" = {
    identical(sort(a), sort(b))
  },
  "xtfrm" = {
    identical(xtfrm(a), xtfrm(b))
  },
  replications = 1000,
  columns = c("test", "replications", "elapsed",
              "relative", "user.self", "sys.self")
  )

   test replications elapsed relative user.self sys.self
1  sort         1000    0.11       11      0.10        0
2 xtfrm         1000    0.01        1      0.01        0

推荐阅读