R-是否存在可以快速在两个向量之间生成唯一集合的向量化方式/预制函数?

时间:2018-10-05 18:31:56

标签: r performance unique vectorization combinations

所以,我想要的是一个数据帧,其中在行上表示两个随机向量的组合。我不要重复的组合,例如; 1,2; 2,1。仅其中之一。以及组合不能自我重复; 1,1。

现在我有了这个简单的for循环,但这并不理想;

unique_combos <- function(v1, v2) {
    df <- data.frame(matrix(ncol=2))
    counter = 0
    for (name1 in v1) {
        for (name2 in v2) {
            if (name1 != name2){
                counter = counter + 1
                df[counter,] <- c(name1, name2)
            }
        }
    }
    return(df)
}

# example usage;
> v1 <- c(1,2,3,4)
> v2 <- c(3,4,5,6)
> unique_combos(v1, v2)
   X1 X2
1   1  3
2   1  4
3   1  5
4   1  6
5   2  3
6   2  4
7   2  5
8   2  6
9   3  4
10  3  5
11  3  6
12  4  3
13  4  5
14  4  6
> 

任何矢量化方法可以做到这一点吗?最好也针对性能。 除此之外,我想指出向量可以是任意长度,并且将包含随机变量。

Edit1-我的功能无法正常工作!;我不要3-4 4-3组合。

Edit2-@Ryan和@Frank的最终解决方案(谢谢大家!);

unique_combos <- function(v1, v2) {
  intermediate <- unique(CJ(v1, v2)[V1 > V2, c("V1", "V2") := .(V2, V1)])
  return(intermediate[V1 != V2])

*注意;这确实使用了软件包data.tableplyr

3 个答案:

答案 0 :(得分:2)

根本不需要循环。
您可以使用expand.grid并在一条指令中使用重复的data.frame。然后使用逻辑索引仅保留不同的行。

unique_combos2 <- function(v1, v2) {
  e <- expand.grid(v1, v2)
  e <- e[e[[1]] < e[[2]], ]
  e[order(e[[1]]), ]
}


u1 <- unique_combos(v1, v2)
u2 <- unique_combos2(v1, v2)

现在进行速度测试。首先使用您的数据,然后使用更大的向量。我将加载软件包microbenchmarkggplot2来运行测试并可视化结果。

(结果未显示。)

library(microbenchmark)
library(ggplot2)

mb1 <- microbenchmark(
  u1 = unique_combos(v1, v2),
  u2 = unique_combos2(v1, v2)
)

mb1
autoplot(mb1)

w1 <- 1:20
w2 <- sample(100, 30)

mb2 <- microbenchmark(
  u1 = unique_combos(w1, w2),
  u2 = unique_combos2(w1, w2)
)

mb2
autoplot(mb2)

答案 1 :(得分:2)

除非您的矢量很大,否则此处的速度差异可能不会产生任何实际影响,但是由于您将“性能”作为标签,因此这是一种稍快的方法。

library(data.table)
CJ(v1, v2)[V1 != V2]

基准:

注意: CJ默认情况下将按v1进行排序,而v1中的unique_combos2进行排序需要花费很多时间,因此我删除了该部分,因为尚不清楚您是否需要它。 / p>

unique_combos2 <- function(v1, v2) {
  e <- expand.grid(v1, v2)
  e <- e[e[[1]] != e[[2]], ]
  e
}
unique_combos3 <- function(v1, v2) CJ(v1, v2)[V1 != V2]

w1 <- sample(200)
w2 <- sample(200)
mb2 <- microbenchmark(
  u2 = unique_combos2(w1, w2),
  u3 = unique_combos3(w1, w2)
)

# Unit: milliseconds
#  expr      min       lq      mean   median       uq        max neval cld
#    u2 5.513842 5.942765 10.969386 6.692507 8.158763 368.180211   100   b
#    u3 1.140513 1.443076  1.898202 1.711384 2.139075   8.397942   100  a 

编辑:要删除重复的对而不考虑顺序,请在注释中使用@Frank的解决方案,该解决方案可以在调用unique

之前对所有行进行有效排序
unique(CJ(v1, v2)[V1 > V2, c("V1", "V2") := .(V2, V1)])

答案 2 :(得分:1)

这是一种tidyverse的方式,主要是使用purrr工具。 (编辑以解决问题)。此方法执行以下操作:

  1. 获取向量乘积集的列表,过滤它们相等的情况,
  2. 将列表元素转换为排序的整数矢量,并丢弃所有与unique重复的元素,
  3. transpose返回到列列表结构,simplify将列转换为向量,然后放回到数据框中。

非常愿意看看是否有人可以提出一种浓缩某些步骤的方法!

v1 <- c(1,2,3,4)
v2 <- c(3,4,5,6)
library(tidyverse)
cross2(v1, v2, .filter = `==`) %>%
  map(~ sort(as.integer(.))) %>%
  unique %>%
  transpose(.names = c("x", "y")) %>%
  simplify_all %>%
  as_tibble()
#> # A tibble: 13 x 2
#>        x     y
#>    <int> <int>
#>  1     1     3
#>  2     2     3
#>  3     3     4
#>  4     1     4
#>  5     2     4
#>  6     1     5
#>  7     2     5
#>  8     3     5
#>  9     4     5
#> 10     1     6
#> 11     2     6
#> 12     3     6
#> 13     4     6

reprex package(v0.2.0)于2018-10-05创建。