使用Python进行准随机化
问题是:我尝试在两个元素之间随机选择n次,比如[0,1]>0或1,我的最终列表将有n/2[0]+n/2[1]。我倾向于得到这样的结果:[01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01。我知道我可以使用准随机过程,但我不知道如何使用Python。为了保证将有相同数量的零和一,您可以生成一个包含n/2个零和n/2个一的列表,并使用random.shuffle将其洗牌 对于小n,如果您对结果通过验收标准(例如,没有太多连续相等的数字)不满意,请再次洗牌。请注意,这样做会减少结果的随机性,而不是增加结果的随机性 对于较大的n,使用此方法查找通过条件的结果将花费太长时间,因为大多数结果将失败。相反,您可以使用以下规则一次生成一个元素: 如果一行中已经生成了4个数字,则下一个数字必须为零,反之亦然。 否则,如果需要多生成x个1和y个0,则下一个数字为1的概率为x/x+y。使用Python进行准随机化,python,random,Python,Random,问题是:我尝试在两个元素之间随机选择n次,比如[0,1]>0或1,我的最终列表将有n/2[0]+n/2[1]。我倾向于得到这样的结果:[01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01
为了保证有相同数量的0和1,您可以生成一个包含n/2个0和n/2个1的列表,并使用random.shuffle将其洗牌 对于小n,如果您对结果通过验收标准(例如,没有太多连续相等的数字)不满意,请再次洗牌。请注意,这样做会减少结果的随机性,而不是增加结果的随机性 对于较大的n,使用此方法查找通过条件的结果将花费太长时间,因为大多数结果将失败。相反,您可以使用以下规则一次生成一个元素: 如果一行中已经生成了4个数字,则下一个数字必须为零,反之亦然。 否则,如果需要多生成x个1和y个0,则下一个数字为1的概率为x/x+y。
连续6个1不是特别不可能的-你确定你没有得到你想要的吗
对于均匀分布的随机数,有一个简单的Python接口,这就是您想要的吗?一行有6个1不是特别不可能的-您确定没有得到您想要的吗
对于均匀分布的随机数,有一个简单的Python接口,这就是您要寻找的吗?可能不是最聪明的方法,但它不适用于连续运行,同时不生成相同数量的0和1。有关符合所有要求的版本,请参见下文
from random import choice
CHOICES = (1, 0)
def quasirandom(n, longest=3):
serial = 0
latest = 0
result = []
rappend = result.append
for i in xrange(n):
val = choice(CHOICES)
if latest == val:
serial += 1
else:
serial = 0
if serial >= longest:
val = CHOICES[val]
rappend(val)
latest = val
return result
print quasirandom(10)
print quasirandom(100)
import random
def next_value(selected):
# Mathematically, this isn't necessary but it accounts for
# potential problems with floating point numbers.
if selected.count(0) == 0:
return 0
elif selected.count(1) == 0:
return 1
N = len(selected)
selector = float(selected.count(1)) / N
if random.uniform(0, 1) > selector:
return 1
else:
return 0
def get_sequence(N, max_run):
lim = min(N, max_run - 1)
seq = [random.choice((1, 0)) for _ in xrange(lim)]
for _ in xrange(N - lim):
seq.append(next_value(seq[-max_run+1:]))
return seq
def test(N, max_run, test_count):
ones = 0.0
zeros = 0.0
for _ in xrange(test_count):
seq = get_sequence(N, max_run)
# Keep track of how many ones and zeros we're generating
zeros += seq.count(0)
ones += seq.count(1)
# Make sure that the max_run isn't violated.
counts = [0, 0]
for i in seq:
counts[i] += 1
counts[not i] = 0
if max_run in counts:
print seq
return
# Print the ratio of zeros to ones. This should be around 1.
print zeros/ones
test(200, 5, 10000)
下面这一条修正了过滤洗牌的想法,并在AICT下正常工作,同时警告最后的数字可能会形成一个运行。Pass debug=True以检查是否满足要求
from random import random
from itertools import groupby # For testing the result
try: xrange
except: xrange = range
def generate_quasirandom(values, n, longest=3, debug=False):
# Sanity check
if len(values) < 2 or longest < 1:
raise ValueError
# Create a list with n * [val]
source = []
sourcelen = len(values) * n
for val in values:
source += [val] * n
# For breaking runs
serial = 0
latest = None
for i in xrange(sourcelen):
# Pick something from source[:i]
j = int(random() * (sourcelen - i)) + i
if source[j] == latest:
serial += 1
if serial >= longest:
serial = 0
guard = 0
# We got a serial run, break it
while source[j] == latest:
j = int(random() * (sourcelen - i)) + i
guard += 1
# We just hit an infinit loop: there is no way to avoid a serial run
if guard > 10:
print("Unable to avoid serial run, disabling asserts.")
debug = False
break
else:
serial = 0
latest = source[j]
# Move the picked value to source[i:]
source[i], source[j] = source[j], source[i]
# More sanity checks
check_quasirandom(source, values, n, longest, debug)
return source
def check_quasirandom(shuffled, values, n, longest, debug):
counts = []
# We skip the last entries because breaking runs in them get too hairy
for val, count in groupby(shuffled):
counts.append(len(list(count)))
highest = max(counts)
print('Longest run: %d\nMax run lenght:%d' % (highest, longest))
# Invariants
assert len(shuffled) == len(values) * n
for val in values:
assert shuffled.count(val) == n
if debug:
# Only checked if we were able to avoid a sequential run >= longest
assert highest <= longest
for x in xrange(10, 1000):
generate_quasirandom((0, 1, 2, 3), 1000, x//10, debug=True)
可能不是最聪明的方法,但它不适用于连续运行,同时不会生成相同数量的0和1。有关符合所有要求的版本,请参见下文
from random import choice
CHOICES = (1, 0)
def quasirandom(n, longest=3):
serial = 0
latest = 0
result = []
rappend = result.append
for i in xrange(n):
val = choice(CHOICES)
if latest == val:
serial += 1
else:
serial = 0
if serial >= longest:
val = CHOICES[val]
rappend(val)
latest = val
return result
print quasirandom(10)
print quasirandom(100)
import random
def next_value(selected):
# Mathematically, this isn't necessary but it accounts for
# potential problems with floating point numbers.
if selected.count(0) == 0:
return 0
elif selected.count(1) == 0:
return 1
N = len(selected)
selector = float(selected.count(1)) / N
if random.uniform(0, 1) > selector:
return 1
else:
return 0
def get_sequence(N, max_run):
lim = min(N, max_run - 1)
seq = [random.choice((1, 0)) for _ in xrange(lim)]
for _ in xrange(N - lim):
seq.append(next_value(seq[-max_run+1:]))
return seq
def test(N, max_run, test_count):
ones = 0.0
zeros = 0.0
for _ in xrange(test_count):
seq = get_sequence(N, max_run)
# Keep track of how many ones and zeros we're generating
zeros += seq.count(0)
ones += seq.count(1)
# Make sure that the max_run isn't violated.
counts = [0, 0]
for i in seq:
counts[i] += 1
counts[not i] = 0
if max_run in counts:
print seq
return
# Print the ratio of zeros to ones. This should be around 1.
print zeros/ones
test(200, 5, 10000)
下面这一条修正了过滤洗牌的想法,并在AICT下正常工作,同时警告最后的数字可能会形成一个运行。Pass debug=True以检查是否满足要求
from random import random
from itertools import groupby # For testing the result
try: xrange
except: xrange = range
def generate_quasirandom(values, n, longest=3, debug=False):
# Sanity check
if len(values) < 2 or longest < 1:
raise ValueError
# Create a list with n * [val]
source = []
sourcelen = len(values) * n
for val in values:
source += [val] * n
# For breaking runs
serial = 0
latest = None
for i in xrange(sourcelen):
# Pick something from source[:i]
j = int(random() * (sourcelen - i)) + i
if source[j] == latest:
serial += 1
if serial >= longest:
serial = 0
guard = 0
# We got a serial run, break it
while source[j] == latest:
j = int(random() * (sourcelen - i)) + i
guard += 1
# We just hit an infinit loop: there is no way to avoid a serial run
if guard > 10:
print("Unable to avoid serial run, disabling asserts.")
debug = False
break
else:
serial = 0
latest = source[j]
# Move the picked value to source[i:]
source[i], source[j] = source[j], source[i]
# More sanity checks
check_quasirandom(source, values, n, longest, debug)
return source
def check_quasirandom(shuffled, values, n, longest, debug):
counts = []
# We skip the last entries because breaking runs in them get too hairy
for val, count in groupby(shuffled):
counts.append(len(list(count)))
highest = max(counts)
print('Longest run: %d\nMax run lenght:%d' % (highest, longest))
# Invariants
assert len(shuffled) == len(values) * n
for val in values:
assert shuffled.count(val) == n
if debug:
# Only checked if we were able to avoid a sequential run >= longest
assert highest <= longest
for x in xrange(10, 1000):
generate_quasirandom((0, 1, 2, 3), 1000, x//10, debug=True)
可以使用将列表随机化
import random
n = 100
seq = [0]*(n/2) + [1]*(n-n/2)
random.shuffle(seq)
现在,您可以在列表中运行,每当您看到一个运行过长时,交换一个元素以分解序列。我还没有这部分的任何代码。您可以使用它来随机排列列表
import random
n = 100
seq = [0]*(n/2) + [1]*(n-n/2)
random.shuffle(seq)
现在,您可以在列表中运行,每当您看到一个运行过长时,交换一个元素以分解序列。我还没有那部分的代码。这是我的看法。前两个函数是实际实现,最后一个函数用于测试它 键是第一个函数,它查看列表的最后N个元素,其中N+1是一个数字在一行中出现次数的限制。它计算出现的数量,然后以1-N/N的概率返回1,其中N是已经出现的数量。注意,在N个连续1的情况下,该概率为0,在N个连续0的情况下,该概率为1 与真正的随机选择一样,不能保证1和0的比率为1,但经过数千次运行的平均值,它确实会产生与0一样多的1。 对于较长的列表,这比反复调用shuffle并检查它是否满足您的需求要好
from random import choice
CHOICES = (1, 0)
def quasirandom(n, longest=3):
serial = 0
latest = 0
result = []
rappend = result.append
for i in xrange(n):
val = choice(CHOICES)
if latest == val:
serial += 1
else:
serial = 0
if serial >= longest:
val = CHOICES[val]
rappend(val)
latest = val
return result
print quasirandom(10)
print quasirandom(100)
import random
def next_value(selected):
# Mathematically, this isn't necessary but it accounts for
# potential problems with floating point numbers.
if selected.count(0) == 0:
return 0
elif selected.count(1) == 0:
return 1
N = len(selected)
selector = float(selected.count(1)) / N
if random.uniform(0, 1) > selector:
return 1
else:
return 0
def get_sequence(N, max_run):
lim = min(N, max_run - 1)
seq = [random.choice((1, 0)) for _ in xrange(lim)]
for _ in xrange(N - lim):
seq.append(next_value(seq[-max_run+1:]))
return seq
def test(N, max_run, test_count):
ones = 0.0
zeros = 0.0
for _ in xrange(test_count):
seq = get_sequence(N, max_run)
# Keep track of how many ones and zeros we're generating
zeros += seq.count(0)
ones += seq.count(1)
# Make sure that the max_run isn't violated.
counts = [0, 0]
for i in seq:
counts[i] += 1
counts[not i] = 0
if max_run in counts:
print seq
return
# Print the ratio of zeros to ones. This should be around 1.
print zeros/ones
test(200, 5, 10000)
这是我的看法。前两个函数是实际实现,最后一个函数用于测试它 键是第一个函数,它查看列表的最后N个元素,其中N+1是一个数字在一行中出现次数的限制。它计算出现的数量,然后以1-N/N的概率返回1,其中N是已经出现的数量。注意,对于N个连续的概率,该概率为0 在N个连续零的情况下为1 与真正的随机选择一样,不能保证1和0的比率为1,但经过数千次运行的平均值,它确实会产生与0一样多的1。 对于较长的列表,这比反复调用shuffle并检查它是否满足您的需求要好
from random import choice
CHOICES = (1, 0)
def quasirandom(n, longest=3):
serial = 0
latest = 0
result = []
rappend = result.append
for i in xrange(n):
val = choice(CHOICES)
if latest == val:
serial += 1
else:
serial = 0
if serial >= longest:
val = CHOICES[val]
rappend(val)
latest = val
return result
print quasirandom(10)
print quasirandom(100)
import random
def next_value(selected):
# Mathematically, this isn't necessary but it accounts for
# potential problems with floating point numbers.
if selected.count(0) == 0:
return 0
elif selected.count(1) == 0:
return 1
N = len(selected)
selector = float(selected.count(1)) / N
if random.uniform(0, 1) > selector:
return 1
else:
return 0
def get_sequence(N, max_run):
lim = min(N, max_run - 1)
seq = [random.choice((1, 0)) for _ in xrange(lim)]
for _ in xrange(N - lim):
seq.append(next_value(seq[-max_run+1:]))
return seq
def test(N, max_run, test_count):
ones = 0.0
zeros = 0.0
for _ in xrange(test_count):
seq = get_sequence(N, max_run)
# Keep track of how many ones and zeros we're generating
zeros += seq.count(0)
ones += seq.count(1)
# Make sure that the max_run isn't violated.
counts = [0, 0]
for i in seq:
counts[i] += 1
counts[not i] = 0
if max_run in counts:
print seq
return
# Print the ratio of zeros to ones. This should be around 1.
print zeros/ones
test(200, 5, 10000)
这在我的书中是完全随机的:[0,0,0,0,0,1,1,1,1,1]当你们指的是一些对我来说足够混乱的分布时,你们需要停止说随机。我不想如此频繁地连续4或5倍于同一个数字为什么不?这就是随机的工作原理。有1/32的几率可以看到5个1连成一行。在我的书中,这是完全随机的:[0,0,0,0,1,1,1,1,1]当你们指的是一些对我来说足够混乱的分布时,你们需要停止说随机。我不想让相同的数字连续出现4或5倍,为什么不呢?这就是随机的工作原理。有1/32的几率在一行中看到5个1。当然,如果生成所有n/20的速度太快,那么该算法就会崩溃,然后其余的1将违反“一行中有太多1”约束。@Adam Rosenfield:啊。。。说得好,很好!这是可以解决的,但这可能会比它的价值更麻烦,这取决于需求的重要性。当然,这只是第三种算法的问题。前两项工作正常,但不完全符合要求。虽然被接受的答案也是如此,所以我猜要求比问题中所述的更灵活。我尝试在洗牌过程中进行过滤,但得出的结论是一个简单的洗牌也是一样的。。。幸好我的答案不被接受:当然,如果生成所有n/2 0的速度太快,那么该算法就会崩溃,而其余的1将违反“一行中有太多1”的约束。@Adam Rosenfield:啊。。。说得好,很好!这是可以解决的,但这可能会比它的价值更麻烦,这取决于需求的重要性。当然,这只是第三种算法的问题。前两项工作正常,但不完全符合要求。虽然被接受的答案也是如此,所以我猜要求比问题中所述的更灵活。我尝试在洗牌过程中进行过滤,但得出的结论是一个简单的洗牌也是一样的。。。好消息是我的答案被拒绝了:谢谢,我将使用这个并修改代码,以便对于一个100元素的列表,其中25个元素的n=2,25个元素的n=3…嗯,val=CHOICES[val]技巧将不起作用。此外,此版本不保证0和1的数量相等。如果这是一个要求,请选择Mark Ransom的答案,我将展示如何使其限制连续运行的次数。不要选择我的答案,我刚刚意识到回头看问题,Mark Byers早在我之前就提出了相同的建议。好的,我想我找到了一条出路,但它涉及暴力和迭代处理列表以打破运行。我不确定是否值得写下来,必须有一个更聪明的方法…这几乎是Mark Byers的一个实现答案:生成序列检查,确保没有连续运行,但要以shuffley的方式进行:谢谢,我将使用它并修改代码,对于100个元素的列表,有25个元素的n=2,25如果n=3…嗯,那么val=CHOICES[val]技巧就行不通了。此外,此版本不保证0和1的数量相等。如果这是一个要求,请选择Mark Ransom的答案,我将展示如何使其限制连续运行的次数。不要选择我的答案,我刚刚意识到回头看问题,Mark Byers早在我之前就提出了相同的建议。好的,我想我找到了一条出路,但它涉及暴力和迭代处理列表以打破运行。我不确定是否值得写下来,必须有一个更聪明的方法…这几乎是Mark Byers的一个实现答案:生成序列检查,确保没有连续运行,但要以随机方式进行:你如何决定交换哪个其他元素,以仅考虑这个想法?@ChristopheD,我没有这部分的代码的一个原因是我还没有弄清楚所有的细节:这比我最初想象的要难一点:D+1-我通常不会对重复项进行上推投票,但你的答案添加了一些我没有源代码的东西,我认为值得投一票你如何决定换成只考虑这个想法的其他因素?@ChristopheD,我没有这部分的代码的一个原因是我还没有弄清楚所有的细节:这比我最初想象的要难一点:D+1-我通常不会对重复项进行上推投票,但你的答案添加了一些我没有源代码的东西,我认为值得投一票我想如果你能对值和它们的数字进行概括,OP会很感激,但这非常优雅。我想OP会感激你能对值和它们的数字进行概括,但这非常优雅。@小丑:是吗 你读过了吗?若否,原因为何?如果是的话,你的具体问题是什么?@小丑:你读了吗?若否,原因为何?如果是,你的具体问题是什么?