![](/img/trans.png)
[英]How to generate a certain number of random whole numbers that add up to a certain number and are at least a certain number or more?
[英]How to generate random numbers with each random number having a difference of at least x with all other elements?
我知道這違反了隨機數的定義,但我仍然需要這個項目。 例如,我想生成一個在range(0, 200)
有5個隨機元素的數組。
現在,我希望每個元素之間的差異至少為15。 所以隨機數組看起來應該是這樣的:
[15, 45, 99, 132, 199]
我可以使用numpy生成隨機數:
np.random.uniform(low=0, high=200, size=5)
但是,我無法保持至少15的一致差異。
如果問題顯示出更多努力來解決問題(例如來自Stack Overflow Tour :“不要問...問題,你沒有試圖找到答案(顯示你的工作!)”,這將是很好的。) ,但有時候一個問題會引發癢,你只需要刮開......
這是你可以做到的一種方式,寫成函數random_spaced
:
import numpy as np
def random_spaced(low, high, delta, n, size=None):
"""
Choose n random values between low and high, with minimum spacing delta.
If size is None, one sample is returned.
Set size=m (an integer) to return m samples.
The values in each sample returned by random_spaced are in increasing
order.
"""
empty_space = high - low - (n-1)*delta
if empty_space < 0:
raise ValueError("not possible")
if size is None:
u = np.random.rand(n)
else:
u = np.random.rand(size, n)
x = empty_space * np.sort(u, axis=-1)
return low + x + delta * np.arange(n)
例如,
In [27]: random_spaced(0, 200, 15, 5)
Out[27]: array([ 30.3524969 , 97.4773284 , 140.38221631, 161.9276264 , 189.3404236 ])
In [28]: random_spaced(0, 200, 15, 5)
Out[28]: array([ 81.01616136, 103.11710522, 118.98018499, 141.68196775, 169.02965952])
size
參數允許您一次生成多個樣本:
In [29]: random_spaced(0, 200, 15, 5, size=3)
Out[29]:
array([[ 52.62401348, 80.04494534, 96.21983265, 138.68552066, 178.14784825],
[ 7.57714106, 33.05818556, 62.59831316, 81.86507168, 180.30946733],
[ 24.16367913, 40.37480075, 86.71321297, 148.24263974, 195.89405713]])
此代碼使用100000個樣本為每個組件生成直方圖,並繪制每個組件的相應理論邊緣PDF:
import matplotlib.pyplot as plt
from scipy.stats import beta
low = 0
high = 200
delta = 15
n = 5
s = random_spaced(low, high, delta, n, size=100000)
for k in range(s.shape[1]):
plt.hist(s[:, k], bins=100, density=True, alpha=0.25)
plt.title("Normalized marginal histograms and marginal PDFs")
plt.grid(alpha=0.2)
# Plot the PDFs of the marginal distributions of each component.
# These are beta distributions.
for k in range(n):
left = low + k*delta
right = high - (n - k - 1)*delta
xx = np.linspace(left, right, 400)
yy = beta.pdf(xx, k + 1, n - k, loc=left, scale=right - left)
plt.plot(xx, yy, 'k--', linewidth=1, alpha=0.25)
if n > 1:
# Mark the mode with a dot.
mode0 = k/(n-1)
mode = (right-left)*mode0 + left
plt.plot(mode, beta.pdf(mode, k + 1, n - k, loc=left, scale=right - left),
'k.', alpha=0.25)
plt.show()
這是它生成的情節:
從圖中可以看出,邊際分布是β分布 。 邊際分布的模式對應於區間[low, high]
上的n
均勻間隔點的位置。
通過擺弄在random_spaced
生成u
方式,可以生成具有不同邊緣的分布(這個答案的舊版本有一個例子),但random_spaced
當前生成的分布似乎是一個自然的選擇。 如上所述,邊緣的模式出現在“有意義”的位置。 此外,在n
為1的平凡情況下,分布簡化為[ low
, high
]上的均勻分布。
反復試驗怎么樣? 例如,拋出一些隨機數,排序,計算差異......如果重復得太小?
import random as r
def spreadRandom(theRange, howMany, minSpacing):
while True:
candidate = sorted([r.randint(*theRange) for _ in range(howMany)])
minDiff = min([ candidate[i+1]-candidate[i] for i, _ in enumerate(candidate[:-1])])
if minDiff >= minSpacing:
return candidate
spreadRandom([0,200], 5, 15)
您無法保證得到答案,但您根本不會偏離您的數字,因為您可能會強制執行基於相鄰數字的范圍。
嘗試改組數字0-200:
import random
numbers = list(range(200))
random.shuffle(numbers)
distant_numbers = [numbers[0]]
for number in numbers:
if any(abs(number - x) < 15 for x in distant_numbers):
continue
distant_numbers.append(number)
if len(distant_numbers) >= 5: break
編輯:
這是一個使用z3
進行大規模過度z3
的解決方案:
def spaced_randoms(n, d, R, first=None):
solver = z3.SolverFor("QF_FD")
numbers = [z3.Int("x{}".format(x)) for x in range(n)]
for number in numbers:
solver.add(number >= 0)
solver.add(number <= R)
for ii in range(n):
for jj in range(ii+1,n):
solver.add(z3.Or(numbers[ii] - numbers[jj] > d, numbers[ii] - numbers[jj] < -d))
if first is not None:
solver.add(numbers[0] == first)
result = solver.check()
if str(result) != "sat":
raise Exception("Unsatisfiable")
model = solver.model()
return [model.get_interp(number) for number in numbers]
像這樣稱它為隨機結果:
import random
spaced_randoms(n, d, R, random.randint(0,R))
我認為此代碼可能有助於滿足您的特定需求:
import random
import numpy as np
five_list = np.asarray([])
end = False
number = random.randint(0,200)
five_list = np.append(five_list,number)
while True:
new_number = random.randint(0,200)
if all(np.absolute(np.subtract(five_list, new_number)) >= 15):
five_list = np.append(five_list,new_number)
if np.size(five_list) == 5:
break
print(np.sort(five_list))
嘗試“蠻力”:
l= [ i for i in range(201) ]
rslt= []
for i in range(5):
n=random.choice(l)
rslt.append(n)
l=[ k for k in l if abs(k-n)>=15 ]
#if not l:
# break
或巧妙地:
sgmnts= [(0,200)]
diff= 15
rslt= []
for i in range(5):
start,stop= sgmnts.pop( random.choice(range(len(sgmnts))) )
n= random.choice(range(start,stop+1))
rslt.append(n)
if n-diff > start:
sgmnts.append( (start,n-diff) )
if n+diff < stop:
sgmnts.append( (n+diff,stop) )
if not sgmnts:
break
“sgmnts”存儲合適的范圍。 我們也通過索引隨機選擇一個范圍。
這將在200之間生成5個隨機值,步長為5
import random
array = []
randomRange = 200
arrayRange = 5
valueStep = 15
for loop in range(arrayRange):
randomMaxValue = randomRange - valueStep * (arrayRange - loop) # First loop will the first randomMaxValue be 125 next will be 140, 155, 170, 185, 200
if not array: # Checks if the array is empty
array.append(random.randint(0, randomMaxValue)) # Appends a value between 0 and 125 (First will be 125 because 200 - 15 * 5)
else:
array.append(random.randint(array[-1] + 15, randomMaxValue)) # Appends the 4 next values
print(array)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.