Algorithm 均匀生成最多重复k次的置换?
我们已经设置了Algorithm 均匀生成最多重复k次的置换?,algorithm,random,language-agnostic,permutation,uniform,Algorithm,Random,Language Agnostic,Permutation,Uniform,我们已经设置了{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
{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
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]到一个大数组中
在大型重复阵列上运行a的前m个步骤,以获得所需的排列。不需要洗牌整个数组,因为您只需要m个数字
这假设您有足够的内存来保存数字[1..n]k次
设置数组[1..n]
将数组复制k次:[1..n,1..n,1..n,…1..n]到一个大数组中
在大型重复阵列上运行a的前m个步骤,以获得所需的排列。不需要洗牌整个数组,因为您只需要m个数字
如果我没记错的话,np.choice有一个选项来给出概率,那么你可以这样做:
设置数组[1..n]
将数组复制k次:[1..n,1..n,1..n,…1..n]到一个大数组中。
就像@rossum提议的那样
生成此大型阵列的概率均匀(1/(k*n))
重复m次:
从结果数组中获取一个数字
设置抽取项目概率为0的概率,其余为
相同的值在它们之间均匀分布1/(k*n),我们刚刚设置为0
例如:
设S=[1,1,1,2,2,3,3,3,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。我认为最难的部分将是操纵概率。如果我没记错的话。选择有一个选项来给出概率,那么你可以这样做:
设置数组[1..n]
将数组复制k次:[1..n,1..n,1..n,…1..n]到一个大数组中。
就像@rossum提议的那样
生成此大型阵列的概率均匀(1/(k*n))
重复m次:
从结果数组中获取一个数字
设置抽取项目概率为0的概率,其余为
相同的值在它们之间均匀分布1/(k*n),我们刚刚设置为0
例如:
设S=[1,1,1,2,2,3,3,3,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。我认为最难的部分将是操纵概率。不必是Python。我在寻找更多的想法,而不是程序。不必是Python。我寻找的更多的是一个想法,而不是程序。它不会返回一致的随机排列。有了列表[1,2,1,2]和m=2,我会收到概率:(1,1)->1/6,(2,2)->1/6,(1,2)->2/6,(2,1)->2/6尝试检查F-Y洗牌代码是否正常工作。您需要移动大型阵列中的元素,以便只能拾取一次。它洗牌[1,2,3,4,5,6]正确吗?还可以查看RNG的输出;它是否显示出一种模式?例如,一些简单的RNG交替使用奇数和偶数。@rossum:(注释修订)不,OP是对的。你的算法不统一。假设你计算所有2n![1..2n]的置换,并查看每个置换中的前两个数字。你更愿意打赌这两个数字具有相同的奇偶性还是具有不同的奇偶性?答复:(b)。有2n(2n-1)对;其中n(n-1)都是偶数,n(n-1)都是奇数,而n²是偶数/奇数,n²是奇数/偶数。所以不同的奇偶比相同的奇偶更可能是n/(n-1)。如果n为2,这一点尤其明显,如上面OP的例子中所示。当然,这取决于“统一”的精确定义。统一的意思是,任何一对可能的配置都具有相同的概率。不会返回统一的随机排列。有了列表[1,2,1,2]和m=2,我会收到概率:(1,1)->1/6,(2,2)->1/6,(1,2)->2/6,(2,1)->2/6尝试检查F-Y洗牌代码是否正常工作。您需要移动大数组中的元素,以便它们只能