提问人:Kornel 提问时间:6/2/2019 最后编辑:Kornel 更新时间:6/2/2019 访问量:647
均匀生成排列,最多重复 k 次?
Uniform generation of permutation with repetition at most k times?
问:
我们有一组数字。我们希望生成这些数字创建的 m 长度的排列,并在大多数时候重复每个数字。{1, 2, 3, ...,n}
k
如果我们假设 ,那么我们可以得到: ,但不像第二个例子中那样恰好是输出的三倍,这比 k 多。n=5, k=2, m=3
{3,3,1}
{3, 3, 3}
3
有没有办法快速均匀地生成这种排列?
我尝试了两种不同的解决方案。
第一:
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
第二种方法:
生成随机整数,仅当它没有出现在时间之前时才将其添加到序列中。下面介绍了这些单词的优化版本(用 Python 编写)。
Python 代码段:k
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
第二个是没有产生均匀的排列(有些比其他的概率更大)。
你有什么想法如何快速、均匀地生成这样的序列吗?
答:
这假设您有足够的内存来保存数字 [1..n] k 次。
设置阵列 [1..n]。
复制数组 k 次:[1..n, 1..n, 1..n, ...1..n] 添加到一个大数组中。
在大型重复数组上运行 Fisher-Yates 洗牌的前 m 步,以获得所需的排列。没有必要洗牌整个数组,因为你只需要 m 个数字。
评论
如果我没记错的话,np.choice 有一个选项来给出概率,那么你可以做这样的事情:
设置阵列 [1..n]。
复制数组 k 次:[1..n, 1..n, 1..n, ...1..n] 添加到一个大数组中。 就像@rossum提议的那样。
生成这个大数组均匀的概率 (1/(k*n))。
重复 m 次:
- 获取一个数字到结果数组
- 设置 Probabilities,对于绘制的项目概率为 0,将 rest 设置为 相同的值在它们之间均匀分布 1/(k*n),我们刚刚设置为 0
例:
设 S=[1,1,1,2,2,2,3,3,3,4,4,4] 是一个大数组,其中每个项目都有 k,k=3 和 m = 4。
生成 P = [1/12]*len(S)
结果 = 随机(S,P) 假设结果 = [1]
概率是这样的 P = [0,1/12+1/36,1/12+1/36,1/12+1/36,其余保持不变]
重复步骤 2 和 3 m 次
如果没有更多与绘制的值相同的值,请将其设置为 0 并进行静止概率以保持此比率和总和为 1 。我认为最困难的部分是操纵概率。
评论