生成具有固定总和的随机整数 numpy 向量

问题描述 投票:0回答:3

根据代码,我想随机化指定特定范围的整数,但在最后三个数组中我总共需要有

100
。最后三个数组的总和不能超过
100
。我不知道如何解决这个问题。

self.position = np.array([rd.randint(0,2), rd.randint(0,2), rd.randint(0,100), rd.randint(0,50), rd.randint(0,1)])
python numpy
3个回答
2
投票

虽然解决方案Rmano建议是有效的,但它缺乏完全的随机性,因为一旦你绘制第一个随机整数,其他整数就会是伪随机的,或者由于依赖而根本不是随机的。

在我看来,更随机的解决方案是:

import numpy as np

def generate_fix_sum_random_vec(limit, num_elem, tries=10):
    v = np.random.randint(0, limit, num_elem)
    s = sum(v)
    if (np.sum(np.round(v/s*limit)) == limit):
        return np.round(v / s * limit)
    elif (np.sum(np.floor(v/s*limit)) == limit):
        return np.floor(v / s * limit)
    elif (np.sum(np.ceil(v/s*limit)) == limit):
        return np.ceil(v / s * limit)
    else:
        return generate_fix_sum_random_vec(limit, num_elem, tries-1)



for i in range(25):
    test_vec = generate_fix_sum_random_vec(100, 3)
    test_vec = test_vec.astype(int)
    print("vec: ", test_vec, "sum of vector: ", np.sum(test_vec))

这个解决方案更加鲁棒,并且可以对向量之和的任何限制有效,并且通过改变

num_elem
,它可以轻松地适用于任何长度的向量。此外,它不假设任何事情,只是尝试直到找到匹配项。

循环的输出:

vec:  [53 32 15] sum of vector:  100
vec:  [40 38 22] sum of vector:  100
vec:  [56 38  6] sum of vector:  100
vec:  [ 5 17 78] sum of vector:  100
vec:  [12 29 59] sum of vector:  100
vec:  [ 1 34 65] sum of vector:  100
vec:  [ 3 56 41] sum of vector:  100
vec:  [35 65  0] sum of vector:  100
vec:  [54  9 37] sum of vector:  100
vec:  [45  8 47] sum of vector:  100
vec:  [30 56 14] sum of vector:  100
vec:  [34 63  3] sum of vector:  100
vec:  [17 40 43] sum of vector:  100
vec:  [56 36  8] sum of vector:  100
vec:  [52 45  3] sum of vector:  100
vec:  [35 34 31] sum of vector:  100
vec:  [25 41 34] sum of vector:  100
vec:  [ 1 78 21] sum of vector:  100
vec:  [ 1 49 50] sum of vector:  100
vec:  [51 31 18] sum of vector:  100
vec:  [50 10 40] sum of vector:  100
vec:  [36 63  1] sum of vector:  100
vec:  [30 30 40] sum of vector:  100
vec:  [27 30 43] sum of vector:  100
vec:  [21 27 52] sum of vector:  100

需要检查结果向量和是否确实达到所需值,因为这不能保证


1
投票

回答OP下面的评论:

我不确定你会得到多少随机性,但是:

def three_to_100_b():
    a3 = random.randint(0,1)
    a2 = random.randint(0,50)
    a1 = 100-a3-a2
    return a1, a2, a3

会给你三个 pseudo - 随机数,第一个在 0-100 范围内,第二个在 0-50 范围内,最后一个是 0 或 1,总和为 100。

但请注意,

a1
a2
之间的随机性非常小——根据定义,它们位于一条直线+0或-1上......

注意,新答案——旧答案在随机性方面存在缺陷。

让三个数字之和为 100 的一种方法是生成三个随机数,然后缩放它们,使它们的总和为 100。这过于冗长,但其想法是:

#! /usr/bin/env python3

import random

def three_to_100():
    r1 = random.randint(0,100)
    r2 = random.randint(0,100)
    r3 = random.randint(0,100)
    a1 = r1*100/(r1+r2+r3)
    a2 = r2*100/(r1+r2+r3)
    a3 = 100 - a1 - a2
    return a1, a2,a3

#main
print("x\t y\t z")
for i in range(1000):
    # print(three_to_100())
    a=three_to_100()
    print("{}\t  {}\t {}".format(*a))

我绘制了前 1000 个数字的 (x,y) 对(第三个数字由点的颜色表示),我有:

旧答案

您可以生成一个 0 到 100 之间的数字,然后生成另一个 0 到(100 - 第一个数字)之间的数字,依此类推。最后一个不会是随机的:

#! /usr/bin/env python3

import random

def three_to_100():
    r1 = random.randint(0,100)
    r2 = random.randint(0,100-r1)
    r3 = 100 - r1 - r2
    return r1, r2,r3

#main
for i in range(10):
    print(three_to_100())

输出将是:

[romano:~/tmp] % ./randsum.py 
(26, 7, 67)
(85, 13, 2)
(43, 41, 16)
(75, 22, 3)
(66, 19, 15)
(30, 16, 54)
(43, 30, 27)
(36, 2, 62)
(31, 2, 67)
(91, 0, 9)

这是前两个数字的图 - 它们看起来相当随机,但也许它们在 x-y 轴上看起来有点拥挤。


0
投票

下面是 numpy 的答案。它无需重试逻辑即可工作

def randint_sum_total(num_elem, min, max, total_limit):
    """It will create random numbers between min and max range but the sum will match the expected_total

    Args:
        size (int): number of items
        min (int): minimum value
        max (int): max value
        limit (int): sum of all values should match this

    Returns:
        array: list contains random numbers
    """
    random_numbers = (np.random.uniform(min, max, num_elem)).astype(int)
    scaled_numbers = random_numbers / random_numbers.sum() * total_limit
    # Round the scaled numbers to integers
    rounded_numbers = np.round(scaled_numbers).astype(int)
    rounded_numbers[rounded_numbers<min] = min # if the scaled num less than min_range , add min_range
    rounded_numbers[rounded_numbers>max] = max # if the scaled num greater than max_range , add max_range
    remaining = total_limit - rounded_numbers.sum()
    indices = np.where((rounded_numbers + remaining > min) & (rounded_numbers + remaining < max))
    if len(indices[0]) > 0:  # Check if there are values in the range (min_range , max_range)
        # Add remaining to the first value meeting the condition
        rounded_numbers[indices[0][0]] += remaining

    return rounded_numbers
© www.soinside.com 2019 - 2024. All rights reserved.