所以,我想要的是一个数据帧,其中在行上表示两个随机向量的组合。我不要重复的组合,例如; 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.table
和plyr
。
答案 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)
现在进行速度测试。首先使用您的数据,然后使用更大的向量。我将加载软件包microbenchmark
和ggplot2
来运行测试并可视化结果。
(结果未显示。)
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
工具。 (编辑以解决问题)。此方法执行以下操作:
unique
重复的元素,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创建。