把特征放在六个随机数上,使三个负数和三个正数等于1?



如何使三个随机负数和三个正随机数等于 1,约束在 -1 和 1 之间。例如

random_nums = np.array([-.2,-.3,-.5,.5,.8,.7])) = 1

我不想要 np.uniform 答案,我需要 arr[0],arr[1],arr[2],arr[3],arr[4],arr[5],arr[6] =1 中的 6 个随机数。然后想以不同的顺序洗牌(random_nums(。

显然,由此方案生成的数字永远不会是真正的"随机",因为要满足此约束,您必须约束其中一些。

但是,撇开警告不谈,这里有一种方法可以生成这样的数组:

  1. 生成一对 (a,b(,其中 a = rand(( 和 b=-rand((
  2. 如果 a+b <0,则反向保持 (a,b(,否则 a,b = -a, -b
  3. 重复另一对 (c,d(
  4. 如果 a+b+c+d <1,则保留 (c,d(,否则 c,d = -c, -d。
  5. 如果 a+b+c+d <0,则 a,b,c,d = -a, -b, -c, -d
  6. 现在应该有一个正 a+b+c+d。获取范围为 [-(a+b+c+d(, 0] 的随机数 e
  7. 你的最终数字是 f = 1 - (a+b+c+d+e(

Python实现的粗略(未经测试(示例:

def getSix():
a = numpy.random.rand()
b = -numpy.random.rand()
a,b = (a,b) if a+b > 0 else (-a,-b)
c = numpy.random.rand()
d = -numpy.random.rand()
c,d = (c,d) if a+b+c+d < 1 else (-c, -d)
a,b,c,d = (a,b,c,d) if a+b+c+d > 0 else (-a, -b, -c, -d)
e = -numpy.random.rand()*(a+b+c+d)
f = 1 - (a+b+c+d+e)
return numpy.array([a,b,c,d,e,f])

显然,这非常特定于您的 6 个元素的情况,但如有必要,您可以找到一种方法将其推广到更多元素。

这可能是违反直觉的,但实际上,你不能:

1) the last one of them must be non-random so that the sum equals 1.
2) the penultimate must be in an interval such that when summed with
the first four, the result is between 0 and 2. 
3) the antepenultimate must be in an interval such that when summed with
the first three, the result is between -1 and 3. and so on...

这些数字是受约束的,因此它们不能是随机的。

要实现解决方案,您可以做的是使用回溯算法。

您的问题没有解决方案。您的问题可以用以下等式表述:

x + y + z + p + q + r = 1,其中 x、y、z> 0 和 p、q、r <0。

如您所见,这是一个不确定的等式。这意味着它具有无限的解决方案,因此无法满足您的要求。

由于总和约束而非真正的随机性,并且由于浮点舍入,精确值的浮点总和也可能出现问题,但是只需一点蛮力,十进制模块并计算五个随机数的第六个值,以下示例即可。

下面的代码生成五个随机数,并计算第六个总和要求和循环,直到 6 个数字中的 3 个为负数:

from decimal import Decimal
import random
def get_nums():
while True:
# Use integers representing 100ths to prevent float rounding error.
nums = [random.randint(-100,100) for _ in range(5)]
nums.append(100-sum(nums)) # compute 6th number so sum is 100.
# Check that 6th num is in right range and three are negative.
if -100 <= nums[5] <= 100 and sum([1 if num < 0 else 0 for num in nums]) == 3:
break
return [Decimal(n) / 100 for n in nums]
for _ in range(10):
print(get_nums())

输出:

[Decimal('-0.36'), Decimal('0.89'), Decimal('0.39'), Decimal('1'), Decimal('-0.05'), Decimal('-0.87')]
[Decimal('-0.01'), Decimal('0.12'), Decimal('0.98'), Decimal('-0.48'), Decimal('-0.45'), Decimal('0.84')]
[Decimal('0.99'), Decimal('0.5'), Decimal('-0.29'), Decimal('0.49'), Decimal('-0.65'), Decimal('-0.04')]
[Decimal('0.51'), Decimal('-0.03'), Decimal('0.64'), Decimal('-0.96'), Decimal('0.99'), Decimal('-0.15')]
[Decimal('0.51'), Decimal('-0.27'), Decimal('-0.62'), Decimal('0.67'), Decimal('-0.22'), Decimal('0.93')]
[Decimal('-0.25'), Decimal('0.84'), Decimal('-0.23'), Decimal('-0.59'), Decimal('0.94'), Decimal('0.29')]
[Decimal('0.75'), Decimal('-0.39'), Decimal('0.86'), Decimal('-0.81'), Decimal('0.6'), Decimal('-0.01')]
[Decimal('-0.4'), Decimal('-0.46'), Decimal('0.89'), Decimal('0.94'), Decimal('0.27'), Decimal('-0.24')]
[Decimal('-0.87'), Decimal('0.6'), Decimal('0.95'), Decimal('-0.12'), Decimal('0.9'), Decimal('-0.46')]
[Decimal('0.5'), Decimal('-0.58'), Decimal('-0.04'), Decimal('-0.41'), Decimal('0.68'), Decimal('0.85')]

下面是一种使用求和规范化的简单方法:

import numpy as np

def gen_rand(n):
result = np.array((np.random.random(n // 2) + 1).tolist() + (np.random.random(n - n // 2) - 1).tolist())
result /= np.sum(result)
return result

rand_arr = gen_rand(6)
print(rand_arr, np.sum(rand_arr))
# [ 0.70946589  0.62584558  0.77423647 -0.51977241 -0.28432949 -0.30544603] 1.0

基本上,我们在范围 (1, 2( 中生成 N/2 个数字,在范围 (0, -1( 中生成 N/2 个数字,然后对这些数字进行总和归一化。 该算法不保证确切的结果,但随着 N 的增加,无效结果的概率变为零。

N = 100000
failures = 0
for i in range(N):
rand_arr = gen_rand(6)
if np.any(rand_arr > 1) or np.any(rand_arr < -1):
failures += 1
print(f'Drawings: {N}, Failures: {failures}, Rate: {failures / N:.2%}')
# Drawings: 100000, Failures: 1931, Rate: 1.93%

因此,如果您严格要求,您可以将其与其他一些逻辑相结合,以丢弃无效的世代,例如:

import numpy as np

def gen_rand_strict(n):
result = np.full(n, 2.0, dtype=float)
while np.any(result > 1) or np.any(result < -1):
result = np.array((np.random.random(n // 2) + 1).tolist() + (np.random.random(n - n // 2) - 1).tolist())
result /= np.sum(result)
return result
rand_arr = gen_rand_strict(6)
print(rand_arr, np.sum(rand_arr))
# [ 0.55928446  0.5434739   0.38103321 -0.24799626 -0.09556285 -0.14023246] 1.0

N = 100000
failures = 0
for i in range(N):
rand_arr = gen_rand_strict(6)
if np.any(rand_arr > 1) or np.any(rand_arr < -1):
failures += 1
print(f'Drawings: {N}, Failures: {failures}, Rate: {failures / N:.2%}')
# Drawings: 100000, Failures: 0, Rate: 0.00%

实际上,通过确保值在确切范围内的逻辑,您无需在范围内考虑太多,这也将很好地工作:

import numpy as np

def gen_rand_strict(n):
result = np.full(n, 2.0, dtype=float)
while np.any(result > 1) or np.any(result < -1):
result = np.array((np.random.random(n // 2) * n).tolist() + (np.random.random(n - n // 2) * -n).tolist())
result /= np.sum(result)
return result
rand_arr = gen_rand_strict(6)
print(rand_arr, np.sum(rand_arr))
# [ 0.32784034  0.75649476  0.8097567  -0.2923395  -0.41629451 -0.1854578 ] 1.0

N = 100000
failures = 0
for i in range(N):
rand_arr = gen_rand_strict(6)
if np.any(rand_arr > 1) or np.any(rand_arr < -1):
failures += 1
print(f'Drawings: {N}, Failures: {failures}, Rate: {failures / N:.2%}')
# Drawings: 100000, Failures: 0, Rate: 0.00%

最新更新