我有一个用于随机颜色选择器的代码,但没有一个随机数字。我需要它从5到20之间选择一个随机数15次,但问题是所有15个数字的总和必须等于227
我有一个用于随机颜色生成器的代码,但是我不知道如何生成数字以及如何获取总数227
import turtle
import random
turtle.bgcolor("black")
t = turtle.Pen()
t.width(4)
colours = ["yellow", "orange", "red"]
for i in range(60):
t.pencolor(colours[random.randint(0,2)])
t.forward(100)
t.back(100)
t.left(6)
答案 0 :(得分:1)
让我们分析问题:
我们将生成14个数字并手动将15个数字相加以获得正确的总和。
但是我会改变@jfaccioni一次生成所有数字的方法,并更早地重新开始循环:如果我们生成5
5次,我们已经知道我们无法获得正确的和! (5 * 5 + 20 *(15-5)<227)
def rng_list():
while True:
rng_list = []
current_sum = 0
for i in range(14):
r = random.randint(5, 20)
rng_list.append(r)
current_sum+= r
if not 5*(14-i) <= 227-current_sum <= 20*(14-i): #`i` goes from 0 to 14, so 14-i is how many (from 15) numbers are still not calculated
break
if len(rng_list) == 14:
rng_list.append(227-current_sum)
return rng_list
print("Pass failed with list {}, sum {} - trying again.".format(rng_list, current_sum)) #added to debug/show how it works
我添加了打印件以监视其在书写时的工作方式,您可以将其更改为计数器,以便重新滚动列表。但是现在,您也可以看到失败尝试的持续时间不同,因为我们每次都会监视当前的总和!
>>> rng_list()
Pass failed with list [12, 7, 18, 20, 12, 12, 15, 7, 15, 16, 7], sum 141 - trying again.
Pass failed with list [17, 6, 20, 5, 16, 18, 5, 19, 19, 7, 8], sum 140 - trying again.
Pass failed with list [10, 15, 18, 10, 8, 8, 12, 12, 13], sum 106 - trying again.
Pass failed with list [9, 12, 8, 5, 17, 20, 20, 6, 8], sum 105 - trying again.
Pass failed with list [9, 16, 9, 16, 6, 17, 20, 15, 9, 11, 15], sum 143 - trying again.
Pass failed with list [5, 14, 13, 12, 12, 13, 13, 9, 8], sum 99 - trying again.
Pass failed with list [11, 9, 5, 11, 11, 13, 18, 7], sum 85 - trying again.
Pass failed with list [10, 12, 19, 9, 14, 16, 11, 19, 5, 5], sum 120 - trying again.
Pass failed with list [11, 10, 8, 10, 10, 17, 17, 9, 19, 14], sum 125 - trying again.
Pass failed with list [13, 11, 7, 15, 14, 7, 5, 10], sum 82 - trying again.
Pass failed with list [11, 6, 7, 20, 6, 17, 18, 12, 8], sum 105 - trying again.
Pass failed with list [16, 17, 9, 18, 7, 8, 17, 14, 13, 13, 14], sum 146 - trying again.
[19, 6, 18, 9, 19, 20, 15, 14, 16, 15, 11, 18, 11, 20, 16]
>>> rng_list()
Pass failed with list [17, 6, 8, 9, 14, 17, 13, 8, 10], sum 102 - trying again.
Pass failed with list [7, 16, 12, 8, 20, 19, 18, 15, 5, 5], sum 125 - trying again.
Pass failed with list [5, 7, 6, 15, 12, 17, 6, 10], sum 78 - trying again.
Pass failed with list [17, 18, 8, 17, 18, 6, 10, 16, 18, 18, 6, 5], sum 157 - trying again.
Pass failed with list [10, 13, 9, 11, 11, 5, 18, 17, 13, 12], sum 119 - trying again.
Pass failed with list [20, 8, 8, 7, 14, 16, 17, 15, 15, 19, 13, 15, 17], sum 184 - trying again.
Pass failed with list [19, 12, 10, 15, 12, 13, 20, 14, 12, 6, 9], sum 142 - trying again.
Pass failed with list [9, 5, 13, 10, 15, 10, 13, 14, 7], sum 96 - trying again.
Pass failed with list [15, 12, 5, 19, 6, 5, 5, 17], sum 84 - trying again.
Pass failed with list [8, 5, 7, 11, 15, 16, 12, 18, 13], sum 105 - trying again.
Pass failed with list [15, 14, 10, 9, 8, 6, 10, 15, 18], sum 105 - trying again.
Pass failed with list [14, 17, 10, 13, 16, 8, 5, 6, 14], sum 103 - trying again.
Pass failed with list [10, 12, 19, 9, 5, 18, 12, 8, 9], sum 102 - trying again.
Pass failed with list [15, 10, 11, 19, 12, 12, 18, 15, 13, 8, 19, 11], sum 163 - trying again.
Pass failed with list [10, 20, 17, 11, 20, 11, 14, 13, 18, 5, 5], sum 144 - trying again.
Pass failed with list [20, 8, 11, 16, 18, 16, 15, 12, 9, 14, 15, 18, 13], sum 185 - trying again.
Pass failed with list [16, 7, 20, 11, 12, 16, 11, 9, 5, 13], sum 120 - trying again.
Pass failed with list [10, 12, 19, 9, 14, 15, 17, 19, 7, 11, 17, 17, 7], sum 174 - trying again.
Pass failed with list [5, 5, 6, 12, 10, 16, 10], sum 64 - trying again.
Pass failed with list [16, 18, 20, 14, 20, 19, 16, 7, 5, 12, 9, 11, 15], sum 182 - trying again.
Pass failed with list [14, 7, 13, 15, 16, 12, 20, 5, 5, 13], sum 120 - trying again.
Pass failed with list [17, 16, 9, 20, 13, 9, 9, 17, 19, 19, 7, 13, 18], sum 186 - trying again.
Pass failed with list [16, 11, 18, 17, 14, 16, 9, 10, 14, 19, 17, 6, 17], sum 184 - trying again.
Pass failed with list [12, 9, 9, 16, 10, 12, 18, 17, 16, 12, 18, 15], sum 164 - trying again.
[15, 14, 11, 14, 13, 13, 18, 19, 19, 13, 14, 6, 19, 16, 23]
>>> rng_list()
[13, 8, 15, 5, 17, 19, 14, 15, 17, 19, 20, 14, 17, 15, 19]
(在输出中添加了空行以提高可读性。)
答案 1 :(得分:1)
好吧,对于这类问题,multinomial distribution是正确的答案-根据定义,总和等于期望的数量。在Python中,这几乎是一个衬里
q = np.random.multinomial(227, [1/15.]*15)
np.sum(q)
将打印
227
然后您可以应用拒绝/接受技术:
if np.any(q < 5):
# reject and start again
if np.any(q > 20):
# reject and start again
# accept, do something with the sampled array
或以函数形式
import numpy as np
def sample(nof_samples, min, max, sum):
p = np.full(nof_samples, 1.0/np.float64(nof_samples)) # probabilities
while True:
q = np.random.multinomial(sum, p)
if not np.any(q > max):
if not np.any(q < min):
return q
t = sample(15, 5, 20, 227)
print(t)
t = sample(15, 5, 20, 227)
print(t)
t = sample(15, 5, 20, 227)
print(t)
答案 2 :(得分:1)
摆脱Severin Pappadeux的回答,您可以通过从min
和max
中减去5,使这个特定问题的值分别为0和15,从而消除对下限抑制的需要。这样会将目标sum
减少了nof_samples * min
。一旦合奏通过缩减的上限检查,就无需检查下限违规,因为它现在为0,并且所有结果均为正。我们只需要通过将min
添加回所有值来转换这些结果,即可将其恢复到原始范围。
import numpy as np
import sys
def sample(nof_samples, min, max, sum):
p = np.full(nof_samples, 1.0/np.float64(nof_samples)) # probabilities
sum -= nof_samples * min
max -= min
if sum < 0 or sum > nof_samples * max: # check that args have a feasible solutioon
print('Inconceivable!')
sys.exit()
while True:
q = np.random.multinomial(sum, p)
if not np.any(q > max):
return q + min
for _ in range(3):
t = sample(15, 5, 20, 227)
print(t)
print(min(t), max(t), sum(t)) # confirm that all constraints have been met
请注意,此版本还可以使用负数作为总和和界限:
print(sample(5, -10, 20, -1))
产生例如
[ 0 1 -1 4 -5]
答案 3 :(得分:0)
如果您不在乎数字是否严格随机,则可以生成5到20之间的14个随机数字,请检查这些数字的总和是否足够接近所需的总数227 (这样,在5到20之间添加另一个数字将达到227)并添加相应的“缺失”数字。
以下功能可以做到这一点:
def rng_list():
while True:
rng_list = [random.randint(5, 20) for _ in range(14)]
if 207 <= sum(rng_list) <= 222:
break
rng_list.append(227 - sum(rng_list))
return rng_list
此函数并未真正优化,因为可能要花很多时间才能得出14个随机数的列表,这些和的总和位于正确的位置,但是对于您的用例而言,它应该足够快。
答案 4 :(得分:0)
您想要15个数字加起来等于227。227/15 = 15.133。因此,从[15,15,...,15,16,16,16]开始,总计为227(15 x 15 = 225)。
现在对数字对进行随机更改,以使a)总数保持不变,b)不会将数字压入5..20限制之外。
一种方法是随机选择2个数字,检查两个数字与极限的距离,然后使用该信息选择随机大小的变化。将大小更改添加到该对中的一个,然后从另一个中减去。然后选择另一对并重复。
ETA:不要随机选择该对中的两个成员。使用类似费舍尔·耶茨(Fisher-Yates)洗牌的方法,该对中的一个成员顺序地遍历列表,从而确保列表中的每个成员在遍历列表时至少被处理一次。