R:以P的倍数生成N个权值的所有排列

时间:2022-05-22 14:57:35

I need to create a function (in R) which:
- given N possible variables to attribute weights to;
- creates all possible permuations of weights (summing to 100%);
- subject to the constraint that weights must occur in multiples of P (usually 1%)

我需要创建一个函数(在R中):-给定N个可能的变量来赋予权重;-创建所有可能的权重排列(总和为100%);-受约束,权重必须以P(通常为1%)的倍数出现

Obviously, as N and P are inversely related - i.e. I can't specify N=7, and P=0.4. However, I'd like to be able to specify integer solutions only, i.e. P=0.01.

显然,由于N和P是反比相关的——也就是说,我不能指定N=7, P=0.4。但是,我想只指定整数解,即P=0.01。

Sorry if this is a well-known problem - I'm not a math person, and I've searched using terms I know, but didn't find anything close enough.

对不起,如果这是一个众所周知的问题——我不是一个数学的人,我已经用我知道的术语搜索了,但是没有找到足够接近的东西。

I'd post the code I've written, but.. it's not impressive or insightful.

我想把我写的代码贴出来,但是……这并没有什么深刻的见解。

Thanks for any help!

感谢任何帮助!

2 个解决方案

#1


5  

Assuming the order of the weights matters, these are compositions; if they don't then these are partitions. In either case, they are restricted by the number of parts, what you have called N, though the code which follows uses numparts. There is also the question of whether weights of 0 are allowed.

假设权重的顺序很重要,这些就是组合;如果没有,那么这些就是分区。无论哪种情况,它们都受部件数量的限制,也就是你所说的N,尽管后面的代码使用numparts。还有一个问题是是否允许权值为0。

Since you want weights to add up to 1, you need 1/p to be an integer, which in the following code is sumparts; it does not depend on the number of weights. Once you have the compositions, you can multiply them by p, i.e. divide by n, to get your weights.

因为您希望权重相加为1,所以需要1/p是一个整数,在下面的代码中,这个整数就是和;它不依赖于权重的多少。一旦你有了这些成分,你可以把它们乘以p,也就是除以n,得到权重。

R has a partitions package to generate such compositions or restricted partitions. The following code should be self explanatory: each column in the matrix is a set of weights. I have taken seven weights and p=0.1 or 10%, and prohibited weights of 0: this gives 84 possibilities; allowing weights of 0 would mean 8008 possibilities. With p=0.01 or 1% there would be 1,120,529,256 possibilities without weights of 0, and 1,705,904,746 with. If order does not matter, use restrictedparts instead of compositions.

R有一个分区包来生成这样的组合或受限制的分区。下面的代码应该是自解释的:矩阵中的每一列都是一组权重。我取了7个权重,p=0。1或10%,禁止的权重为0:这给出了84种可能性;允许权值为0意味着有8008种可能。如果p=0.01或1%,则可能会有1,120,529,256种可能性,而没有0的权重,以及1,705,904,746。如果订单不重要,使用限制部件而不是组合部件。

> library(partitions)
> numparts <- 7  # number of weights
> sumparts <- 10  # reciprocal of p
> weights <- compositions(n=sumparts, m=numparts, include.zero=FALSE)/sumparts
> weights

[1,] 0.4 0.3 0.2 0.1 0.3 0.2 0.1 0.2 0.1 0.1 0.3 0.2 0.1 0.2 0.1 0.1 0.2 0.1 0.1
[2,] 0.1 0.2 0.3 0.4 0.1 0.2 0.3 0.1 0.2 0.1 0.1 0.2 0.3 0.1 0.2 0.1 0.1 0.2 0.1
[3,] 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.1 0.1 0.1 0.2 0.2 0.3 0.1 0.1 0.2
[4,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2 0.2 0.3 0.3 0.3
[5,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
[6,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
[7,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1

[1,] 0.1 0.3 0.2 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.3 0.2 0.1
[2,] 0.1 0.1 0.2 0.3 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.3
[3,] 0.1 0.1 0.1 0.1 0.2 0.2 0.3 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.1
[4,] 0.4 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1
[5,] 0.1 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.3 0.3 0.3 0.3 0.4 0.1 0.1 0.1
[6,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2
[7,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1

[1,] 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.1 0.3
[2,] 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.1
[3,] 0.2 0.2 0.3 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1
[4,] 0.1 0.1 0.1 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1
[5,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.1 0.2 0.1 0.1
[6,] 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.3 0.3 0.3 0.3 0.3 0.4 0.1
[7,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2

[1,] 0.2 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1
[2,] 0.2 0.3 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1
[3,] 0.1 0.1 0.2 0.2 0.3 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1
[4,] 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1
[5,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.1 0.2
[6,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2
[7,] 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2

[1,] 0.1 0.2 0.1 0.1 0.1 0.1 0.1 0.1
[2,] 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.1
[3,] 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1
[4,] 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1
[5,] 0.1 0.1 0.1 0.1 0.1 0.2 0.1 0.1
[6,] 0.3 0.1 0.1 0.1 0.1 0.1 0.2 0.1
[7,] 0.2 0.3 0.3 0.3 0.3 0.3 0.3 0.4

#2


1  

EDIT : function is updated, as it gave some results twice.

编辑:函数会被更新,因为它会给一些结果两次。

You can try this function, based on recursive calculation. It will give you all possible combinations, regardless of the order. I've done it this way, as you otherwise get a multiple of the rows with all possible permutations.

您可以尝试这个函数,基于递归计算。它会给你所有可能的组合,不管顺序如何。我是这样做的,否则你会得到所有可能排列的行数的倍数。

The calculation is based on integers. The minimum weight P is set as 1, and Pint becomes the number of weight units that can be divided. max.W will be the maximum amount of units that can be given to one variable.

计算是基于整数的。最小重量P设为1,品脱为可以除以的重量单位数。max。W是可以给一个变量的最大单位量。

The algorithm goes as follows :

算法如下:

  • if N=2, then make all possible combinations for the given minimum and maximum weight.

    如果N=2,那么在给定的最小和最大重量下进行所有可能的组合。

  • if N > 2, apply this algorithm for N = 1 to ceiling(max.weight / N), with the maximum weight specified as the current maximum weight +1 minus N, and the minimum weight as N.

    如果N > 2,将这个算法应用于N = 1到上限(最大值)。重量/ N),最大重量指定为当前最大重量+1减N,最小重量为N。

This gives you all possible combinations of integers. Multiplication with P gives the original weights.

这就给出了所有可能的整数组合。与P相乘得到原来的权重。

Or in function :

或功能:

myfunc <- function(N,P){
  if(100%%(P*100) !=0){
    stop("100% cannot be divided in portions of P")
  }
  Pint <- 100/(P*100)
  max.W <- Pint- N + 1

  combs <- function(n,max.w,min){
    mw <- max.w + 1

    if(n==2){

      w <- seq.int(min,floor((mw)/2))
      out <- cbind(w,mw-w)

    } else if (n > 2){

      x <- lapply(1:ceiling(max.w/n),function(i){

        newcombs <- combs(n-1,mw-i,i)
        cbind(newcombs,rep(i,nrow(newcombs)))

      })

      out <- do.call("rbind",x)
    }
    colnames(out) <-rownames(out) <- NULL
    out
  }  
  res <- combs(N,max.W)
  apply(res,1,sort)*P
}

This gives the combinations in columns of a matrix :

这就给出了矩阵列的组合:

> Y <- myfunc(3,0.1)
> Y
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,]  0.1  0.1  0.1  0.1  0.2  0.2  0.2  0.3
[2,]  0.1  0.2  0.3  0.4  0.2  0.3  0.4  0.3
[3,]  0.8  0.7  0.6  0.5  0.6  0.5  0.4  0.4

Be warned! with the testcase you gave (7 variables, jumps of 0.01), you'll be calculating a very long time for the huge amounts of possibilities. With N=7 and P=0.04, you have already 3555 possible combinations. With N=0.2, that becomes 336,443 possibilities. And you have to take into account every possible permutation of these combinations if that is what you're after.

警告!使用您提供的测试用例(7个变量,跳数为0.01),您将为大量的可能性计算很长时间。对于N=7和P=0.04,已经有3555种可能的组合。N=0。2时,有336,443种可能。你必须考虑这些组合的每一个可能的排列如果这是你想要的。

#1


5  

Assuming the order of the weights matters, these are compositions; if they don't then these are partitions. In either case, they are restricted by the number of parts, what you have called N, though the code which follows uses numparts. There is also the question of whether weights of 0 are allowed.

假设权重的顺序很重要,这些就是组合;如果没有,那么这些就是分区。无论哪种情况,它们都受部件数量的限制,也就是你所说的N,尽管后面的代码使用numparts。还有一个问题是是否允许权值为0。

Since you want weights to add up to 1, you need 1/p to be an integer, which in the following code is sumparts; it does not depend on the number of weights. Once you have the compositions, you can multiply them by p, i.e. divide by n, to get your weights.

因为您希望权重相加为1,所以需要1/p是一个整数,在下面的代码中,这个整数就是和;它不依赖于权重的多少。一旦你有了这些成分,你可以把它们乘以p,也就是除以n,得到权重。

R has a partitions package to generate such compositions or restricted partitions. The following code should be self explanatory: each column in the matrix is a set of weights. I have taken seven weights and p=0.1 or 10%, and prohibited weights of 0: this gives 84 possibilities; allowing weights of 0 would mean 8008 possibilities. With p=0.01 or 1% there would be 1,120,529,256 possibilities without weights of 0, and 1,705,904,746 with. If order does not matter, use restrictedparts instead of compositions.

R有一个分区包来生成这样的组合或受限制的分区。下面的代码应该是自解释的:矩阵中的每一列都是一组权重。我取了7个权重,p=0。1或10%,禁止的权重为0:这给出了84种可能性;允许权值为0意味着有8008种可能。如果p=0.01或1%,则可能会有1,120,529,256种可能性,而没有0的权重,以及1,705,904,746。如果订单不重要,使用限制部件而不是组合部件。

> library(partitions)
> numparts <- 7  # number of weights
> sumparts <- 10  # reciprocal of p
> weights <- compositions(n=sumparts, m=numparts, include.zero=FALSE)/sumparts
> weights

[1,] 0.4 0.3 0.2 0.1 0.3 0.2 0.1 0.2 0.1 0.1 0.3 0.2 0.1 0.2 0.1 0.1 0.2 0.1 0.1
[2,] 0.1 0.2 0.3 0.4 0.1 0.2 0.3 0.1 0.2 0.1 0.1 0.2 0.3 0.1 0.2 0.1 0.1 0.2 0.1
[3,] 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.3 0.3 0.4 0.1 0.1 0.1 0.2 0.2 0.3 0.1 0.1 0.2
[4,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2 0.2 0.3 0.3 0.3
[5,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
[6,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1
[7,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1

[1,] 0.1 0.3 0.2 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.3 0.2 0.1
[2,] 0.1 0.1 0.2 0.3 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.3
[3,] 0.1 0.1 0.1 0.1 0.2 0.2 0.3 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.1
[4,] 0.4 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1
[5,] 0.1 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.3 0.3 0.3 0.3 0.4 0.1 0.1 0.1
[6,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2
[7,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1

[1,] 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.1 0.3
[2,] 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.1
[3,] 0.2 0.2 0.3 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1
[4,] 0.1 0.1 0.1 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1
[5,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.1 0.2 0.1 0.1
[6,] 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.3 0.3 0.3 0.3 0.3 0.4 0.1
[7,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2

[1,] 0.2 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1
[2,] 0.2 0.3 0.1 0.2 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1
[3,] 0.1 0.1 0.2 0.2 0.3 0.1 0.1 0.2 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1 0.1
[4,] 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.2 0.1
[5,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.3 0.1 0.1 0.1 0.1 0.2
[6,] 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.2 0.2 0.2 0.2
[7,] 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2 0.2

[1,] 0.1 0.2 0.1 0.1 0.1 0.1 0.1 0.1
[2,] 0.1 0.1 0.2 0.1 0.1 0.1 0.1 0.1
[3,] 0.1 0.1 0.1 0.2 0.1 0.1 0.1 0.1
[4,] 0.1 0.1 0.1 0.1 0.2 0.1 0.1 0.1
[5,] 0.1 0.1 0.1 0.1 0.1 0.2 0.1 0.1
[6,] 0.3 0.1 0.1 0.1 0.1 0.1 0.2 0.1
[7,] 0.2 0.3 0.3 0.3 0.3 0.3 0.3 0.4

#2


1  

EDIT : function is updated, as it gave some results twice.

编辑:函数会被更新,因为它会给一些结果两次。

You can try this function, based on recursive calculation. It will give you all possible combinations, regardless of the order. I've done it this way, as you otherwise get a multiple of the rows with all possible permutations.

您可以尝试这个函数,基于递归计算。它会给你所有可能的组合,不管顺序如何。我是这样做的,否则你会得到所有可能排列的行数的倍数。

The calculation is based on integers. The minimum weight P is set as 1, and Pint becomes the number of weight units that can be divided. max.W will be the maximum amount of units that can be given to one variable.

计算是基于整数的。最小重量P设为1,品脱为可以除以的重量单位数。max。W是可以给一个变量的最大单位量。

The algorithm goes as follows :

算法如下:

  • if N=2, then make all possible combinations for the given minimum and maximum weight.

    如果N=2,那么在给定的最小和最大重量下进行所有可能的组合。

  • if N > 2, apply this algorithm for N = 1 to ceiling(max.weight / N), with the maximum weight specified as the current maximum weight +1 minus N, and the minimum weight as N.

    如果N > 2,将这个算法应用于N = 1到上限(最大值)。重量/ N),最大重量指定为当前最大重量+1减N,最小重量为N。

This gives you all possible combinations of integers. Multiplication with P gives the original weights.

这就给出了所有可能的整数组合。与P相乘得到原来的权重。

Or in function :

或功能:

myfunc <- function(N,P){
  if(100%%(P*100) !=0){
    stop("100% cannot be divided in portions of P")
  }
  Pint <- 100/(P*100)
  max.W <- Pint- N + 1

  combs <- function(n,max.w,min){
    mw <- max.w + 1

    if(n==2){

      w <- seq.int(min,floor((mw)/2))
      out <- cbind(w,mw-w)

    } else if (n > 2){

      x <- lapply(1:ceiling(max.w/n),function(i){

        newcombs <- combs(n-1,mw-i,i)
        cbind(newcombs,rep(i,nrow(newcombs)))

      })

      out <- do.call("rbind",x)
    }
    colnames(out) <-rownames(out) <- NULL
    out
  }  
  res <- combs(N,max.W)
  apply(res,1,sort)*P
}

This gives the combinations in columns of a matrix :

这就给出了矩阵列的组合:

> Y <- myfunc(3,0.1)
> Y
     [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
[1,]  0.1  0.1  0.1  0.1  0.2  0.2  0.2  0.3
[2,]  0.1  0.2  0.3  0.4  0.2  0.3  0.4  0.3
[3,]  0.8  0.7  0.6  0.5  0.6  0.5  0.4  0.4

Be warned! with the testcase you gave (7 variables, jumps of 0.01), you'll be calculating a very long time for the huge amounts of possibilities. With N=7 and P=0.04, you have already 3555 possible combinations. With N=0.2, that becomes 336,443 possibilities. And you have to take into account every possible permutation of these combinations if that is what you're after.

警告!使用您提供的测试用例(7个变量,跳数为0.01),您将为大量的可能性计算很长时间。对于N=7和P=0.04,已经有3555种可能的组合。N=0。2时,有336,443种可能。你必须考虑这些组合的每一个可能的排列如果这是你想要的。