我们设置了{1, 2, 3, ...,n}
个数字。我们希望生成由这些数字创建的m个长度的置换,每个数字最多重复k
次。
如果我们假设n=5, k=2, m=3
,那么我们可以收到:{3,3,1}
,但不能收到{3, 3, 3}
,因为第二个示例中的3
恰好是输出的三倍,这是大于k。
有没有一种快速统一生成这种排列的方法?
我尝试了两种不同的解决方案。
第一:
1)生成具有重复的随机排列,有n^m
个不同的排列。
2)检查这是否是正确的排列(如果它包含的次数不超过相同数字的k
3)如果是,则返回,否则转到1)
Python代码段:
import numba
import numpy as np
@numba.jit(nopython=True)
def gen_sequence1(n, k, m):
result = np.random.randint(0, n, (1, m))[0]
while not is_correct(result, k):
result = np.random.randint(0, n, (1, m))[0]
return result
@numba.jit(nopython=True)
def most_frequent(iter):
return np.bincount(iter).max()
@numba.jit(nopython=True)
def is_correct(pruf, k):
return most_frequent(pruf) <= k
第二种方法:
生成随机整数,仅在k
次之前没有出现时才将其添加到序列中。这些单词的优化版本如下所示(用Python编写)。
Python片段:
def gen_seq(n, d, m):
choices = list(range(n))
degrees = [0] * n
result = []
k = n - 1
for i in range(m):
rand = np.random.randint(0, k)
result.append(choices[rand])
degrees[choices[rand]] += 1
if degrees[choices[rand]] == d:
choices[rand], choices[k] = choices[k], choices[rand]
k -= 1
return result
问题在于第一种方法在n=30, m=28, d=1
时非常慢,它需要10^9
次才能生成序列,这很明显。
第二个不是生成统一排列(某些排列的概率比其他排列大)。
您是否知道如何快速而均匀地生成这样的序列?
答案 0 :(得分:0)
这假定您有足够的内存来保存数字[1..n] k次。
设置数组[1..n]。
将数组k次复制:[1..n,1..n,1..n,... 1..n]到大数组中。
在大型重复数组上运行Fisher-Yates shuffle的前m个步骤,以获取所需的排列。因为只需要m个数字,所以不需要重新整理整个数组。
答案 1 :(得分:0)
如果我没记错的话,np.choice有一个给出概率的选项,那么您可以这样做:
设置数组[1..n]。
将数组复制k次:[1..n,1..n,1..n,... 1..n]成一个大数组。 就像@rossum建议的一样。
生成这种大阵列均匀(1 /(k * n))的概率。
重复m次:
示例:
让S = [1,1,1,2,2,2,3,3,3,4,4,4]是一个大数组,里面每个元素都有k个,k = 3和m = 4。
生成P = [1/12] * len(S)
结果= random(S,P)假设结果= [1]
概率将像这样P = [0,1 / 12 + 1 / 36,1 / 12 + 1 / 36,1 / 12 + 1/36,其余保持不变]
< / li>重复步骤2和3 m次
如果没有更多与绘制的值相同的值,则将其设置为0并设置静息概率以将该比率和总和保持为1。我认为最困难的部分是操纵概率。