问题在于:我尝试在两个元素之间选择n次(假设为[0,1] - > 0或1),我的最终列表将有n / 2 [0] + n / 2 [1]。我倾向于有这样的结果:[0 1 0 0 0 1 0 1 1 1 1 1 1 0 0,直到n]:问题是我不想连续4或5次相同的数字所以经常。我知道我可以使用准随机化程序,但我不知道该怎么做(我正在使用Python)。
答案 0 :(得分:5)
为了保证存在相同数量的零和1,您可以生成包含n / 2个零和n / 2个的列表,并使用random.shuffle
对其进行随机播放。
对于小n,如果您对结果超过您的验收标准(例如,没有太多连续相等的数字)感到不满意,请再次进行洗牌。请注意,执行此操作会降低结果的随机性,而不是增加它。
对于较大的n,使用此方法查找通过条件的结果将花费很长时间(因为大多数结果将失败)。相反,您可以使用以下规则一次生成一个元素:
答案 1 :(得分:2)
连续6个1并不是特别不可能 - 你确定你没有得到你想要的东西吗?
有一个简单的Python接口,用于均匀分布的随机数,那就是你要找的东西吗?
答案 2 :(得分:2)
您可以使用random.shuffle
随机化列表。
import random
n = 100
seq = [0]*(n/2) + [1]*(n-n/2)
random.shuffle(seq)
现在你可以浏览列表,每当你看到一个太长的运行时,交换一个元素来分解序列。我还没有该部分的任何代码。
答案 3 :(得分:1)
可能不是最聪明的方式,但它适用于“无顺序运行”,而不会产生相同数量的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)
下面的这个更正了过滤洗牌的想法,并正确地使用AFAICT,但需要注意的是最后一个数字可能会形成一个运行。通过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)
答案 4 :(得分:1)
这是我的看法。前两个函数是实际的实现,最后一个函数是用于测试它。
键是第一个查看列表中最后N个元素的函数,其中N+1
是您想要一个数字出现在一行中的次数的限制。它计算出现的数量,然后以(1 - N / n)概率返回1,其中n
是已存在的数量。请注意,在N
连续的情况下,此概率为0,在N
个连续零的情况下,概率为1。
与真正的随机选择一样,无法保证1和0的比率为1,但在数千次运行中平均,它确实产生的数量为零。
对于较长的列表,这比重复调用shuffle
并检查它是否满足您的要求要好。
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)