R 中 N 个元素与 q 个元素的组合

2023-12-19

I have N=6元素和q=3元素符号为0,1,2.

我想创建的所有向量N=6元素与2元素等于0, 2元素等于1 and 2元素等于2在所有可能的位置。

这些向量的数量等于combn(6,2)*combn(4,2)*combn(2,2)=90.

这是构建这些的代码90矩阵中的向量F:

N=6
x<-c(1:N)
#########################################
A<-combn(x,2)
B<-matrix(0,ncol(A),length(x)) 
for( i in 1:ncol(A) ) 
{ 
y<-rep(0,N) 
y[A[1:nrow(A),i]]<-1 
B[i,]<-y 
}
######################################
E<-matrix(0,nrow(B),length(x)-nrow(A))  
for( i in 1:nrow(B) ) 
{ 
q=0 
for( j in 1:ncol(B) ) 
{ 
if( B[i,j]!=1 )  
{ 
q=q+1 
E[i,q]<-j 
}}}
########################################
ASD<-combn(E[i,],2) 
F<-matrix(0,nrow(B)*ncol(ASD),length(x)) 
q=0 
for( i in 1:nrow(B) ) 
{ 
ASD<-combn(E[i,],2) 
for( j in 1:ncol(ASD) ) 
{ 
B[i,ASD[1:nrow(ASD),j]]<-2 
q=q+1 
F[q,]<-B[i,] 
B[i,ASD[1:nrow(ASD),j]]<-0 
}}

还有其他不太复杂的方法吗?


这是开发版本包中的超快单衬RcppAlgos.

devtools::install_github("jwood000/RcppAlgos")
library(RcppAlgos)    

myPerms <– permuteGeneral(3,6,TRUE,"prod","==",36) - 1L

myPerms
     [,1] [,2] [,3] [,4] [,5] [,6]
[1,]    0    0    1    1    2    2
[2,]    0    0    1    2    1    2
[3,]    0    0    1    2    2    1
[4,]    0    0    2    1    1    2
[5,]    0    0    2    1    2    1
[6,]    0    0    2    2    1    1
.
.
.
      [,1] [,2] [,3] [,4] [,5] [,6]
[85,]    2    2    0    0    1    1
[86,]    2    2    0    1    0    1
[87,]    2    2    0    1    1    0
[88,]    2    2    1    0    0    1
[89,]    2    2    1    0    1    0
[90,]    2    2    1    1    0    0

以下是一些基准rcppAlgo, r2eOne, r2eTwo, and OPFun是每个方法的代码的函数包装器。

microbenchmark(rcppAlgo(),r2eOne(),r2eTwo(),OPFun(N=6) unit = "relative")
Unit: relative
      expr       min        lq      mean   median        uq      max neval
rcppAlgo()   1.00000   1.00000   1.00000   1.0000   1.00000 1.000000   100
  r2eOne() 471.56007 473.26487 194.01669 267.9402 274.46604 8.373630   100
  r2eTwo()  50.71091  48.84173  24.01617  27.8441  34.02326 2.044374   100
OPFun(N=6)  37.35899  24.38966  22.38029  19.7059  19.51935 31.18059   100

解释

由于OP正在寻找具有特定频率的数字的特定组合,我们可以利用算术基本定理 https://en.wikipedia.org/wiki/Fundamental_theorem_of_arithmetic,它指出每个数字都可以写成素数的唯一组合的乘积。我们得到了集合0, 1, 2加 1 给出集合1, 2, 3。我们这样做是为了避免在购买产品时出现很多零。

现在,我们的任务是找到所有组合,使每个元素恰好出现两次。这意味着当我们将产品应用于我们的目标组合后,我们得到1*1*2*2*3*3 = 36 (N.B. 1不是质数,但可以忽略,因为1*n = n for all n)。现在问题很简单了。

我们只需找到所有组合,使得产品等于36然后减去1回到我们原来的一组数字,瞧!

通用解决方案

下面,我们有一个通用解决方案,可用于查找给定向量的所有排列,其中每个元素重复特定次数。

library(RcppAlgos) ## for primeSieve and permuteGeneral
MakePerms <- function(v, numReps, myCap = NULL) {
    m <- sum(numReps)
    n <- length(v)

    ## Generate some primes using prime
    ## number theorem; fudging a bit to
    ## ensure we get n-1 prime numbers
    myPs <- primeSieve(2*n*log(n))[1:(n-1)]

    ## Set up vector that will be tested
    myV <- c(1L, myPs)
    target <- prod(myV^numReps)
    ps <- permuteGeneral(myV, m, TRUE, "prod", "==", target, myCap)
    for (j in 1:n) {ps[ps == myV[j]] <- v[j]}

    ps
}

它在很大程度上依赖于算术基本定理的素因式分解的唯一性和一点索引(不像上面的小例子那么简单,但仍然只有 7 行,而且仍然超级快)。

我们首先创建第一个向量n-1素数并粘上1去完成myV。然后我们提出每个元素myV每个元素所需的重复次数由下式给出numReps并拿走产品以获得我们的target价值。这里有些例子:

  1. v = c(10,13,267,1) and numReps = c(3,1,2,5)-->>myV = c(1,2,3,5)-->>target = 1^3 * 2^1 * 3^2 * 5^5 = 56250
  2. v = 0:5 and numReps = c(1,2,1,2,2,2)-->>myV = c(1,2,3,5,7,11)-->>target = 1^1 * 2^2 * 3^1 * 5^2 * 7^2 * 11^2 = 1778700
  3. 操作示例:v = c(0,1,2) and numReps = c(2,2,2)-->>myV = c(1,2,3)-->>target = 1^2 * 2^2 * 3^2 = 36

在我们找到所有其乘积等于的排列之后target值,我们只需映射原始向量的内容v使用索引生成的矩阵。

例如,如果您设置N = 8在OP的例子中你得到了所有排列c(0,1,2) with 0准确地重复4次,以及1 and 2重复两次。

   t1 <- OPFun(N=8)
   t2 <- MakePerms(0:2, c(4,2,2))

   all.equal(t1[do.call(order, as.data.frame(t1)), ],
             t2[do.call(order, as.data.frame(t2)), ])
   [1] TRUE

   microbenchmark(fun2(8), MakePerms(0:2, c(4,2,2)), unit = "relative")
   Unit: relative
                         expr      min       lq     mean   median       uq      max neval
                     OPFun(8) 23.25099 22.56178 18.64762 19.52436 18.37387 10.90934   100
   MakePerms(0:2, c(4, 2, 2))  1.00000  1.00000  1.00000  1.00000  1.00000  1.00000   100

应该注意的是,可能的排列数量快速增长,因此像这样的尝试MakePerms(0:5, rep(2, 6))将失败,因为 的排列总数0:5 12 times is 12^6 = 2,985,984 > 2^31 - 1(即矩阵的最大行数Rcpp)。然而,我们并不期望所有这些都符合我们的标准,所以如果我们设定一个上限,比如说10^7,我们就会成功。观察:

a <- MakePerms(0:5, rep(2, 6), 10^7)
nrow(a)
7484400

set.seed(17)
a[sample(nrow(a), 10), ]
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10] [,11] [,12]
 [1,]    0    5    3    3    1    2    4    4    5     1     0     2
 [2,]    5    4    2    1    1    0    3    4    5     2     3     0
 [3,]    2    4    5    3    5    1    3    0    1     0     4     2
 [4,]    4    3    3    1    2    5    0    5    4     1     0     2
 [5,]    2    2    5    3    4    1    0    3    5     1     0     4
 [6,]    3    1    1    5    0    3    2    0    2     4     4     5
 [7,]    1    1    4    2    0    5    4    0    3     5     3     2
 [8,]    1    0    4    2    4    2    5    1    3     0     5     3
 [9,]    4    3    4    1    5    0    0    2    2     1     3     5
[10,]    1    0    5    3    2    0    1    4    3     4     2     5

指某东西的用途myCap也可以大大提高效率。

microbenchmark(withOutCap = MakePerms(0:5, c(1,2,1,2,1,2)),
               withCap = MakePerms(0:5, c(1,2,1,2,1,2), 10^5),
               times = 15) 
Unit: milliseconds
      expr       min       lq      mean    median        uq      max neval
withOutCap 219.64847 246.4718 275.04672 282.52829 299.33816 311.2031    15
   withCap  22.56437  30.6904  33.30469  31.70443  37.50858  41.6095    15

identical(MakePerms(0:5, c(1,2,1,2,1,2)), MakePerms(0:5, c(1,2,1,2,1,2), 10^5)) 
[1] TRUE

iterpc解决方案

似乎到目前为止提供的答案都是严格学术性的,因为@StéphaneLaurent 提供的答案要优越得多。超级通用,一条线,而且超级快!!

          microbenchmark(iter = getall(iterpc(c(2,2,2), labels=c(0,1,2), ordered=TRUE)),
                  rcppAlg = MakePerms(0:2, c(2,2,2)))
   Unit: microseconds
      expr     min       lq      mean  median       uq      max neval
      iter 428.885 453.2975 592.53164 540.154 683.9585 1165.772   100
   rcppAlg  62.418  74.5205  93.44926  81.749 108.4660  216.454   100

随着排列数量的增加,故事也会发生变化。观察:

   microbenchmark(iter = getall(iterpc(c(2,2,2,2), labels=c(0,1,2,3), ordered=TRUE)),
                  rcppAlg = MakePerms(0:3, c(2,2,2,2)),
                  rcppAlgCap = MakePerms(0:3, c(2,2,2,2), 5000))
   Unit: microseconds
         expr     min        lq     mean    median       uq       max neval
         iter 877.246 1052.7060 1394.636 1150.0895 1265.088  8914.980   100
      rcppAlg 964.446 1449.7115 2084.944 1787.9350 1906.242 10921.156   100

如果您使用myCap, MakePerms是有点快。这并不重要,因为随着iterpc解决方案,您甚至不必考虑会得到多少结果。很不错!!

Update

新版本的RcppAlgos(我是该书的作者)刚刚在 CRAN 上发布。现在还有一个额外的论据permuteGeneral called freqs它允许多重集的排列,这正是OP正在寻找的。

microbenchmark(iter = getall(iterpc(c(2,2,2,2), labels=0:3, ordered=TRUE)),
               newRcppAlgos = permuteGeneral(0:3, freqs = c(2,2,2,2)))
Unit: microseconds
        expr     min       lq      mean   median      uq      max neval
        iter 457.442 482.8365 609.98678 508.6150 572.581 4037.048   100
newRcppAlgos  33.159  43.3975  56.40026  48.5665  58.194  625.691   100

microbenchmark(iter = getall(iterpc(c(5,4,3,2), labels=0:3, ordered=TRUE)),
                 newRcppAlgos = permuteGeneral(0:3, freqs = c(5,4,3,2)))
Unit: milliseconds
        expr       min        lq     mean    median       uq      max neval
        iter 480.25976 552.54343 567.9155 565.23066 579.0258 751.8556   100
newRcppAlgos  83.41194  87.03957 104.6279  95.67596 107.3572 181.1119   100

identical(getall(iterpc(c(5,4,3,2), labels=0:3, ordered=TRUE)),
            permuteGeneral(0:3, freqs = c(5,4,3,2)))
[1] TRUE

nrow(permuteGeneral(0:3, freqs = c(5,4,3,2)))
[1] 2522520

Update 2

正如@StéphaneLaurent 指出的那样,该包arrangements已作为替代品发布iterpc(参见@RandyLai 的评论)。它效率更高,能够处理更广泛的组合问题(例如分区)。以下是较大示例的基准:

microbenchmark(arrangements = permutations(x = 0:3, freq = c(5,4,3,2)),
               RcppAlgos = permuteGeneral(0:3, freqs = c(5,4,3,2)))
Unit: milliseconds
        expr      min       lq     mean    median       uq      max neval
arrangements 97.10078 98.67154 113.5953 100.56261 131.3244 163.8912   100
   RcppAlgos 92.13122 93.84818 108.1845  95.72691 101.2647 165.7248   100

...几乎相同的结果。

一个巨大的好处是arrangements是一次获得一个排列(或成块)的能力getnext。这允许用户生成超过2^31 - 1结果并总体上提供了更大的灵活性。

有关此类问题的更多信息,请参见R,我写了一个广泛的概述 https://stackoverflow.com/a/47983855/4408538对于这个问题:R:有/无替换以及不同/非不同项目/多重集的排列和组合 https://stackoverflow.com/q/22569176/4408538.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

R 中 N 个元素与 q 个元素的组合 的相关文章

  • PostgreSQL 在递归查询中找到所有可能的组合(排列)

    输入是一个长度为 n 的数组 我需要生成数组元素的所有可能组合 包括输入数组中元素较少的所有组合 IN j A B C OUT k A AB AC ABC ACB B BA BC BAC BCA 随着重复 所以AB BA 我尝试过这样的事情
  • 如何绘制每条线之间具有特定距离的图形

    实际上 我尝试绘制一个图形 但它将所有列 线 放在一起并显示 因此它不具有代表性 我尝试制作模拟数据并向您展示我如何绘制它 并向您展示我想要的内容 我不知道如何制作像下面所示的示例的数据 但我在这里做了什么 set seed 1 M lt
  • 如何从 R 数据框中提取关键字

    我是 R 中文本挖掘的新手 我想从数据框的列中删除停用词 即提取关键字 并将这些关键字放入新列中 我尝试制作一个语料库 但它对我没有帮助 df C3是我目前拥有的 我想添加栏目df C4 但我无法让它工作 df lt structure l
  • 如何将同一行中以逗号分隔的值拆分到R中的不同行

    我有一些数据来自谷歌表格 https forms gle rGQQL3tvA1PrE4dD8我想拆分以逗号分隔的答案 and 复制参与者的 ID 数据如下 gt head data names Q2 Q3 Q4 1 PART 1 fruit
  • 如何在 R 中将字符串解析为层次结构或树

    有没有办法将表示组的字符串解析为 R 中的层次结构 假设我的小组结构如下 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 3 1 1 3 1 1 1 3 2 1 1 3 3 1 2 1 2 1 1 2 1 1 1 2 1 2 1
  • 排序因素与水平

    有人能解释一下 R 中 ordered 参数的用途吗 R says ordered逻辑标志来确定级别是否应被视为有序 按给定的顺序 所以如果我有一个名为名称的因素并设置ordered TRUE names lt factor c fred
  • 不同 R/lme4 版本的单一拟合结果不匹配

    我试图将 R 版本 3 5 3 lme4 1 1 18 1 的随机效应估计与 R 版本 4 1 1 lme4 1 1 27 1 相匹配 然而 当存在奇异拟合时 这两个版本之间的随机效应存在微小差异 我对奇点警告很满意 但令人费解的是不同版本
  • R- 将某些列从 0 标准化为 1,其值等于 0

    我最近开始使用 are 我想扩展我的数据矩阵 我在这里找到了一种方法在两点之间缩放系列 https stackoverflow com questions 5468280 scale a series between two points
  • R 将多个值与向量进行比较并返回向量[重复]

    这个问题在这里已经有答案了 我有一个向量 A 对于 A 的每个元素 我想检查它是否等于第二个向量 Targets 中的任何元素 我想要一个逻辑值向量 其长度为 A 作为返回 也提到了同样的问题here http r 789695 n4 na
  • dplyr 返回每个组的全局平均值,而不是每个组的平均值

    有人可以解释一下我在这里做错了什么 library dplyr temp lt data frame a c 1 2 3 1 2 3 1 2 3 b c 1 2 3 1 2 3 1 2 3 temp gt group by temp 1 g
  • 如何在ubuntu的conda环境中更改Rstudio中的R版本

    我在基本系统中安装了 R 4 3 和 Rstudio 在 conda 环境中安装了旧版本的 R 4 2 3 命令which R返回环境中安装的 R 的目录 home 用户 miniconda3 envs anndata2ri pip bin
  • 将第 N 行上的 NA 行插入 data.frames 列表,其中 N 来自列表

    经过几个小时后 我发现自己无法解决以下问题 我有一个数据框列表 我想分别向每个 DF 插入 而不是替换 一行或多行 NA 始终至少一行 要插入的 NA 数量存储在单独的列表中 为了说明这一点 我有以下两个列表 list of datafra
  • 如何在knitr和RStudio中为word和html设置不同的全局选项?

    我正在使用 RStudio 0 98 932 和 knitr 1 6 想要为word和html设置不同的全局knitr选项 例如 想要将word的fig width和fig height设置为6 html的fig width和fig hei
  • 一段 R 代码会影响 foreach 输出中的随机数吗?

    我使用运行模拟foreach and doParallel并与随机数 名为random在代码中 简而言之 我模拟一个足球联赛 随机生成所有比赛的获胜者以及相应的结果 在dt base没有比赛进行 在dt ex1 and dt ex24场比赛
  • 获取函数的命名空间

    我正在开发一个包 我希望在其中向对象添加编辑历史记录 该包允许其他包注册用于编辑对象的函数 我正在寻找一种方法来记录注册用于编辑的函数的包的版本 问题是 给定一个函数 如何从导出的位置获取包 我的想法是调查它的搜索路径 但是search 仅
  • R、Rcpp 与 Armadillo 中矩阵 rowSums() 与 colSums() 的效率

    背景 来自 R 编程 我正在扩展到 C C 形式的编译代码Rcpp 作为循环交换 以及一般的 C C 效果的实践练习 我实现了 R 的等效项rowSums and colSums 矩阵的函数Rcpp 我知道它们以 Rcpp 糖的形式存在 并
  • purrr::可能函数可能无法与map2_chr函数一起使用

    我怀疑这是 purrr 包中的错误 但想先在 StackOverflow 中检查我的逻辑 在我看来 possibly功能在内部不起作用map2 chr功能 我正在使用 purrr 版本 0 2 5 考虑这个例子 library dplyr
  • 警告消息 - 来自 dummies 包的 dummy

    我正在使用 dummies 包为分类变量生成虚拟变量 其中一些变量具有两个以上类别 testdf lt data frame A as factor c 1 2 2 3 3 1 B c A B A B C C C c D D E D D E
  • 在R中循环子文件夹

    我正在 R 环境中包含多个子文件夹的文件夹中工作 我想要循环遍历多个子文件夹 然后在每个子文件夹中调用 R 脚本来执行 我想出了下面的代码 但我的代码似乎添加了 到子文件夹列表 我收到错误 文件中的错误 文件名 r 编码 编码 无效的 描述
  • 如何在 Shiny 中提取动态生成的输入值?

    我正在创建一个闪亮的应用程序 它将根据客户的不同功能为客户生成分数 在我闪亮的应用程序中 我提供了 checkboxGroupInput 来选择所需的功能 根据所选功能 应用程序将动态地将 numericInput 添加到 Web ui 以

随机推荐