Python中随机生成特定长度整数分区的算法?
我一直在使用SAGE提供的Python中随机生成特定长度整数分区的算法?,python,combinatorics,sage,Python,Combinatorics,Sage,我一直在使用SAGE提供的random\u element()函数为特定长度(S)的给定整数(N)生成随机整数分区。我试图从所有分区的集合中为N和S的给定值生成无偏随机样本。SAGE的函数快速返回N的随机分区(即分区(N).random_element()) 但是,当添加S(即分区(N,长度=S).random_元素())时,速度会大大减慢。同样地,过滤掉长度为S的N的随机分区速度非常慢 但是,我希望这对某些人有所帮助,我发现当函数返回的分区N与长度S不匹配时,共轭分区的长度通常为S。也就是说:
random\u element()
函数为特定长度(S
)的给定整数(N
)生成随机整数分区。我试图从所有分区的集合中为N
和S
的给定值生成无偏随机样本。SAGE的函数快速返回N的随机分区(即分区(N).random_element()
)
但是,当添加S
(即分区(N,长度=S).random_元素()
)时,速度会大大减慢。同样地,过滤掉长度为S
的N
的随机分区速度非常慢
但是,我希望这对某些人有所帮助,我发现当函数返回的分区N
与长度S
不匹配时,共轭分区的长度通常为S。也就是说:
S = 10
N = 100
part = list(Partitions(N).random_element())
if len(part) != S:
SAD = list(Partition(part).conjugate())
if len(SAD) != S:
continue
这增加了发现长度为S
的分区的速度,并似乎产生了无偏样本(我已经针对N
和S
的不同值对整个分区集的结果进行了检查)
但是,我使用了N(例如
10000
)和S(例如300
)的值,这使得这种方法的速度不切实际。与SAGE的random_element()
函数相关的注释承认存在大量优化空间。那么,是否有一种方法可以更快地生成与给定值N
和S
匹配的整数分区的无偏(即随机均匀)样本,或者,不生成与S
不匹配的分区?此外,在许多情况下,使用共轭分区可以很好地生成无偏样本,但我不能说我确切地理解了原因 简单方法:随机分配整数:
def random_partition(n, s):
partition = [0] * s
for x in range(n):
partition[random.randrange(s)] += 1
return partition
当我试图计算强生日问题的概率时,我遇到了一个类似的问题 首先,当只给出少量的数字时,配分函数爆炸。您将返回大量信息。无论使用哪种方法,N=10000和S=300都会生成大量的数据。这将是缓慢的。您使用的任何纯python实现都可能同样慢或更慢。期待制作一个CModule 如果您想尝试python,我采用的方法是将itertools和生成器结合起来,以降低内存使用率。我似乎不再手边有我的代码,但这里有一个很好的补充: 编辑: 找到我的代码:
def partition(a, b=-1, limit=365):
if (b == -1):
b = a
if (a == 2 or a == 3):
if (b >= a and limit):
yield [a]
else:
return
elif (a > 3):
if (a <= b):
yield [a]
c = 0
if b > a-2:
c = a-2
else:
c = b
for i in xrange(c, 1, -1):
if (limit):
for j in partition(a-i, i, limit-1):
yield [i] + j
def分区(a,b=-1,limit=365):
如果(b==-1):
b=a
如果(a==2或a==3):
如果(b>=a和极限):
收益率[a]
其他:
返回
elif(a>3):
如果(a-2:
c=a-2
其他:
c=b
对于x范围内的i(c,1,-1):
如果(限制):
对于分区中的j(a-i,i,极限-1):
收益率[i]+j
最后,我有一个绝对无偏的方法,具有零拒绝率。当然,我已经测试过它,以确保结果是整个可行集的代表性样本。它非常快速且完全无偏。享受吧
from sage.all import *
import random
首先是一个函数,用于查找n与s部分的分区的最小最大加数
def min_max(n,s):
_min = int(floor(float(n)/float(s)))
if int(n%s) > 0:
_min +=1
return _min
接下来是一个使用缓存和备忘录查找分区数的函数
n的s部分中,x是最大的部分。这很快,但我认为有
一个更优雅的解决方案。例如,通常是:P(N,S,max=K)=P(N-K,S-1)
感谢ante()帮助我做到这一点:
感谢您的回复,但我不知道此函数如何基于均匀随机采样生成分区。@klocey,我错过了您从序列生成随机元素的事实,抱歉。我实现了此函数,并将其生成的随机样本与完整的分区集进行了比较,以进行N和S的几种组合。比较使用分区方差生成的核密度曲线生成。与我尝试过的所有其他采样策略一样,此函数生成有偏差的样本(低于预期方差的分区).显然,对于给定的总N和长度S,从所有分区的集合中生成无偏随机样本非常困难。SAGE函数是我得到的最接近的函数,但它远不是最优的。是的,组合爆炸很难实现。但是,我一次生成一个随机分区,只为c保留一个小的随机样本比较分析。我试图获得一个小的、无偏的、随机的、给定长度的N个分区样本。SAGE的函数在Cython中运行,我自己的脚本也是如此,所以高效的速度并不是一个问题,而是找到一种算法或一种方法来调整SAGE的函数,以避免生成不必要的分区(即长度不为S的分区)。我将查看您的实现和“强生日问题”。谢谢。找到了我的代码,它是一个生成器,它可以找到大小为2或更大的分区(最大为给定数字),您可以删除阻止分区小于2的逻辑。但我怀疑它是否会更快。
D = {}
def P(n,s,x):
if n > s*x or x <= 0: return 0
if n == s*x: return 1
if (n,s,x) not in D:
D[(n,s,x)] = sum(P(n-i*x, s-i, x-1) for i in xrange(s))
return D[(n,s,x)]
def random_partition(n,s):
S = s
partition = []
_min = min_max(n,S)
_max = n-S+1
total = number_of_partitions(n,S)
which = random.randrange(1,total+1) # random number
while n:
for k in range(_min,_max+1):
count = P(n,S,k)
if count >= which:
count = P(n,S,k-1)
break
partition.append(k)
n -= k
if n == 0: break
S -= 1
which -= count
_min = min_max(n,S)
_max = k
return partition