繁体   English   中英

从 python 中的固定限制的数字范围生成随机值

[英]Generate random value from a range of number for a fixed limit in python

代码:

 import random
 import numpy as np
 X=10
 Y=5
 while True:
    random_value=np.random.choice((range(1,X)),Y)
    if sum(random_value)==X:
       break
    else:
       continue

问题

此代码适用于 X 和 Y 的小值,但不适用于 X=56 和 Y=52 等大值。我的目标是从列表中的 X 生成随机值,其大小为 Y 以及随机值应该是 b X

我应该如何优化代码以获得大值的 output

这是一些工作代码。 在像X = 56Y = 52这样的情况下,大多数数字都是 1,因此这段代码计算出需要多少个 1,生成其他数字,然后从这些随机数中减去或添加这些随机数,直到它们总和为所需的金额。

import numpy as np
import random

def get_vals_from_X_Y(X, Y):
    # If X = 56 and Y = 55, can have a single 2 in generated values and then 54 ones.
    # If X = 56 and Y = 54, can have 2 twos and 52 ones.
    # Pattern is that you need (Y - (X - Y)) ones, which simplifies to (2Y - X).
    # This pattern ONLY APPLIES if Y >= X / 2. If Y < X / 2, then every Y value needs to be >= 2.

    if Y >= X / 2:
        num_1s_needed = 2*Y - X
    else:
        num_1s_needed = 0
    
    # vals will eventually contain Y values summing to X.
    vals = []
    vals = [1]*num_1s_needed

    # What the random numbers need to sum to. It's X minus all the ones.
    sum_needed = X - num_1s_needed
    
    if sum_needed == 0:
        return vals
    elif sum_needed == 1:
        idx = random.randrange(num_1s_needed-1)
        vals.insert(idx, 1)
        return vals
    else:
        # places_left determines how many random numbers to generate.
        places_left = Y - num_1s_needed
        random_vals = [random.randrange(1, sum_needed) for i in range(places_left)]
        
        # If sum of random_vals is too small, add randomly to a value as needed.
        while sum(random_vals) < sum_needed:
            idx_to_add_to = random.randrange(len(random_vals))
            if random_vals[idx_to_add_to] < X:
                random_vals[idx_to_add_to] += 1
        
        # Sort from big to small and find the first instance of 1.
        # Add all 1s to vals and remove from random_vals.
        # Adjust sum_needed to always be X - len(vals).

        random_vals.sort(reverse=True)
        try:
            idx_1 = random_vals.index(1)
            orig_length = len(random_vals)
            random_vals = random_vals[:idx_1]
            vals += [1]*(orig_length - len(random_vals))
            sum_needed -= (orig_length - len(random_vals))

        # If there is no 1 in random_vals, function will go to the except block.
        except:
            pass
        
        # Subtract as needed from a random value that is greater than 1.
        while sum(random_vals) > sum_needed:
            idx_to_subtract_from = random.randrange(len(random_vals))
            if random_vals[idx_to_subtract_from] > 1:
                random_vals[idx_to_subtract_from] -= 1
        
        # Generate a random index and insert each random_val into vals at that index.
        for i in range(len(random_vals)):
            idx = 0
            if len(vals) > 1:
                idx = random.randrange(len(vals))
            vals.insert(idx, random_vals[i])
        return vals

# Change X and Y to your liking.
vals = get_vals_from_X_Y(X, Y)

让我知道是否需要澄清。

您可以从合适的多项式分布中采样,但给定范围[1..limit-1]通常不会在结果中耗尽,即使可能。

import numpy as np
rng = np.random.default_rng()

N     = 52
limit = 56
a = rng.multinomial(limit - N, np.full(N, 1.0/N)) + 1

print(a)
print(f'sum:{a.sum()}, length:{a.shape[0]}')

Output(随机)

[1 2 1 1 1 1 1 1 1 2 2 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 1 1 1 1 1 1 1]
sum:56, length:52

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM