在某些约束下生成随机数

时间:2017-09-24 17:04:21

标签: python random

我碰巧有一个列表y = [y1,y2,... yn]。我需要生成随机数ai,使得0 <= ai&lt; = c(对于某些常数c)和所有ai * yi = 0的总和。任何人都可以帮我解决如何在python中编码这个问题吗?即使伪代码/逻辑工作,我在这里也有一个概念问题。虽然第一个约束很容易满足,但我无法获得第二个约束的任何内容。

编辑:把所有yi = +1或-1,如果这有帮助,但对此的一般解决方案将是有趣的。

5 个答案:

答案 0 :(得分:2)

假设y(n)不等于零。如果你生成数字

a(1),..., a(n-1)

您可以将最后一个确定为

a(n) = - ( y(1)*a(1) + ... + y(n-1)*a(n-1) ) / y(n)

如果a(n)不小于c,请重复此过程。看:可能是你在有限的时间内找不到解决方案:) 但我想是的,如果n不是那么大。

如果您的问题是技术问题而非理论问题,您可以尝试一下,看看它是否有效。

答案 1 :(得分:2)

您可以使用贪婪(种类)校正算法来完成此操作。基本上,首先从均匀分布中生成随机a。这会给你一些错误(总和不会为零)。通过将术语的c[i]减半,使用与错误相同的符号给出最大贡献,可以迭代地减少该错误,直到您可以将该项减少一半,使得总和为零。当然,结果a不会均匀分布,但它们会很接近。

我已经减半的原因是因为你的用例不允许有a[i]=0的许多值。你不需要使用减半,你可以使用另一个系数。在下面的实现中,您可以更改reduce_coefficient来更改此设置。值reduce_coefficient = 1.将设置a[i] = 0.,直到它可以删除总和(适当的贪婪算法),而当reduce_coefficient接近0时,您将得到一个需要很长时间的算法运行时间并将a * y中最大的项剪辑为一定界限,以满足总和。

这适用于一般y[i],包括y[i] = +/- 1

的情况

这是一个实现:

import numpy as np

y = np.random.randn(1000)
c = 2.
reduce_coefficient = 0.5
a = np.random.uniform(0, c, 1000)

sum = np.sum(a*y)
while sum != 0:
    a_y = a * y
    i = np.argmax(np.sign(sum) * a_y)
    if abs(sum) < abs(a_y[i] * reduce_coefficient):
        a_y_i_desired = a_y[i] - sum
        a[i] = a_y_i_desired / y[i]
        a_y[i] = a[i] * y[i]
        sum = 0
    else:
        sum -= a_y[i] * reduce_coefficient
        a[i] *= (1. - reduce_coefficient)

这会对a的分布产生一些奇怪的影响,其中略小于reduce_coefficient * c的值比其他值更有可能,接近c的值不太可能,分配是统一的。如果这是一个问题,您可以在每次迭代时随机设置reduce_coefficient。这种方法对分布的唯一影响是使a的值非常接近c

import numpy as np

y = np.random.randn(1000)
c = 2.
a = np.random.uniform(0, c, 1000)

sum = np.sum(a*y)
while sum != 0:
    reduce_coefficient = np.random.uniform(0, 1.)
    a_y = a * y
    i = np.argmax(np.sign(sum) * a_y)
    if abs(sum) < abs(a_y[i] * reduce_coefficient):
        a_y_i_desired = a_y[i] - sum
        a[i] = a_y_i_desired / y[i]
        a_y[i] = a[i] * y[i]
        sum = 0
    else:
        sum -= a_y[i] * reduce_coefficient
        a[i] *= (1. - reduce_coefficient)

如果您还关心接近c的值对概率分布的影响,您可以在每次迭代时设置i = np.random.randint(0, a.shape[0]),而不是使用argmax。权衡是需要修改更多的值。在实践中,所有这些都修改了很少的值,如果您在更正前后绘制a的直方图,则可以看到这些值。

答案 2 :(得分:1)

这仍然导致非常不对称的解决方案。

我首先设置了一个特定的问题。

>>> from random import uniform
>>> C = 9
>>> y = list(range(23,45))

我创建了一个比我需要的更多的随机数。只是我的草率编码。

>>> ai_s = [uniform(0,C) for _ in range(len(y))]

计算前n-1对的总和,然后计算一个'ai',它将使最终对的贡献导致全部和为零。

>>> partial_sum = sum([ai_s[i]*y[i] for i in range(-1+len(y))])
>>> remaining_ai = -partial_sum / y[-1]
>>> ai_s[-1] = remaining_ai
>>> full_sum = sum([ai_s[i]*y[i] for i in range(len(y))])

验证该企业的明显成功。

>>> full_sum
0.0
>>> remaining_ai
-55.61967982871243

现在缩放所有ai,使得最大的ai不大于'C'。

>>> scale = remaining_ai / C
>>> ai_s = [ai/scale for ai in ai_s]
>>> full_sum = sum([ai_s[i]*y[i] for i in range(len(y))])
>>> full_sum
-1.1368683772161603e-13

显示令人震惊的结果。

>>> ai_s
[-0.6762926525200684, -1.0583640594370294, -0.5122417560322818, -0.6809333760704214, -0.20217581044287009, -0.2156635979549709, -0.13351148980420294, -0.5498721696679322, -0.8367502192020138, -0.6485761671051807, -0.3756426962557057, -0.6732767276510332, -1.3123482119760639, -0.6525099994998692, -1.1226532211454199, -0.6194721784294968, -0.2262874341537195, -0.34684998461675415, -0.21587028201158823, -0.26403652293422325, -0.7801743698236504, 9.0]

可以调整这些值,使得最终值在某种意义上更接近其他值。但是,我觉得这种方法可能会在可能性空间中产生一个不具吸引力的部分。

答案 3 :(得分:0)

如果需要0到c之间的随机整数值,请使用random.randint(0, c)。对于0之间的随机浮点值,使用random.uniform(0, c)

答案 4 :(得分:0)

我喜欢分解这个问题。注意,y必须有一些正值和一些负值(否则sum(ai * yi)不能等于零)。

  1. 为y的负值生成随机正系数ai,并仅在y的负值上构造ai * yi的总和(假设该和为-R)。

  2. 假设存在“m”个正值,根据ai = uniform(R /(m * max(y)),为正yi值选择ai系数的前m-1个随机数

  3. 使用约束来确定am =(R-sum(ai yi | yi> 0))/ ym。请注意,通过构造,所有ai都是正数,并且ai yi的总和= 0.

  4. 另请注意,将所有ai乘以相同的量k也将满足约束。因此,找到最大的ai(我们称之为amax),如果amax大于c,则将ai的所有值乘以c /(amax + epsilon),其中epsilon是大于零的任何数。

  5. 我错过了什么吗?