如何计算 R 中列表的笛卡尔幂



我想在 R 中生成任意集合的笛卡尔。 例如,在Python中,我会通过以下方式执行此操作:

from itertools import product
c = [1, 2, 3]
n = 2
l = list(product(c, repeat=n))

这将产生以下输出。

[(1, 1)
(1, 2)
(1, 3)
(2, 1)
(2, 2)
(2, 3)
(3, 1)
(3, 2)
(3, 3)]

我很陌生,所以我想知道是否有一个内置函数可以用来实现这一目标。请注意,我对增加功率特别感兴趣(在 Python 中重复参数(。

建议的解决方案忽略顺序。你会注意到,expand.grid每次迭代都会迭代最左边的元素,这不会产生与 python 的itertools.product生成器相同的顺序。观察:

s <- c(1, 2, 3)
n <- 2
do.call("expand.grid", rep(list(s), n))
Var1 Var2
1    1    1
2    2    1
3    3    1
4    1    2    <-- This is the second result using python's product
5    2    2
6    3    2
7    1    3    <-- This is the third result using python's product
8    2    3
9    3    3

与 python 解决方案的输出相比:

from itertools import product
c = [1, 2, 3]
n = 2
list(product(c, repeat=n))
[(1, 1),
(1, 2),
(1, 3),
(2, 1),
(2, 2),
(2, 3),
(3, 1),
(3, 2),
(3, 3)]

来自 itertools.product(( 文档(强调我的(:

嵌套循环像里程表一样循环,最右边的元素在每次迭代中前进。此模式创建词典排序,以便在对输入的可迭代对象进行排序时,按排序顺序发出产品元组。

将此与本答案顶部(即最左边(所述内容进行比较。

幸运的是,在R(或任何语言(中生成完全相同的输出相对容易,因为这些只是重复的排列。如果你想像python一样构建自己的生成器,该算法相对简单,如文档所示(即"大致相当于生成器表达式中的嵌套 for 循环"(。

有一些包能够按照所需的顺序相当有效地生成这些。它们是gtoolsarrangementsRcppAlgos*

以下是所有三个的代码:

gtools::permutations(3, 2, repeats.allowed = T)
arrangements::permutations(3, 2, replace = T)
RcppAlgos::permuteGeneral(3, 2, T)

好处是,这些解决方案比使用expand.grid更有效:

system.time(do.call("expand.grid", rep(list(1:7), 8)))
user  system elapsed 
0.375   0.007   0.382
system.time(RcppAlgos::permuteGeneral(7, 8, T))
user  system elapsed 
0.057   0.032   0.088
RcppAlgos::permuteCount(7, 8, T)
[1] 5764801

事实上,它们甚至比python解决方案更快:

import time
def getTime():
start = time.time()
list(product([1, 2, 3, 4, 5, 6, 7], repeat = 8))
end = time.time()
print(end - start)
getTime()
0.9604620933532715

公平地说,itertools旨在迭代,因此具有内存效率,而不是真正打算一次生成所有结果。

*我是RcppAlgos的作者

感谢@G.Grothendieck解决这个问题!

s <- c(1, 2, 3)
n <- 2
do.call("expand.grid", rep(list(s), n))

这是给出正确结果的 R 代码。

最新更新