【问题标题】:How to calculate the Cartesian Power of a list in R如何计算R中列表的笛卡尔幂
【发布时间】:2020-04-15 14:26:15
【问题描述】:

我想在 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)]

我对 R 很陌生,所以我想知道是否有一个内置函数可以用来实现这一点。请注意,我对提高功率(Python 中的重复参数)特别感兴趣。

【问题讨论】:

  • do.call("expand.grid", rep(list(1:3), 2)) 给出了问题中显示的输出。 rdocumentation.org/packages/rje/versions/1.10.10/topics/… 提供电源组。 t(combn(1:3, 2)) 给出长度为 2 的独特组合。
  • 不会expand.grid(1:3,1:3) 达到基本相同的结果吗?
  • @G.Grothendieck expand.grid 函数不足以处理任意集合,例如 c(1, 3, 7)。有解决办法吗?
  • @Base_R_Best_R 我想明确控制为任意集合计算产品的次数。所以这也意味着例如 expand.grid(c(1,4,9), c(1,4,9), c(1,4,9)) 。我正在寻找一个带有参数 n 的函数,它指定计算产品的次数。

标签: r algorithm set cartesian-product


【解决方案1】:

建议的解决方案忽略顺序。您会注意到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的作者

【讨论】:

    【解决方案2】:

    感谢@G.Grothendieck 解决问题!

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

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

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-02-08
    • 2017-04-26
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多