我碰巧有一个列表y = [y1,y2,... yn]。我需要生成随机数ai,使得0 <= ai&lt; = c(对于某些常数c)和所有ai * yi = 0的总和。任何人都可以帮我解决如何在python中编码这个问题吗?即使伪代码/逻辑工作,我在这里也有一个概念问题。虽然第一个约束很容易满足,但我无法获得第二个约束的任何内容。
编辑:把所有yi = +1或-1,如果这有帮助,但对此的一般解决方案将是有趣的。
答案 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)不能等于零)。
为y的负值生成随机正系数ai,并仅在y的负值上构造ai * yi的总和(假设该和为-R)。
假设存在“m”个正值,根据ai = uniform(R /(m * max(y)),为正yi值选择ai系数的前m-1个随机数
使用约束来确定am =(R-sum(ai yi | yi> 0))/ ym。请注意,通过构造,所有ai都是正数,并且ai yi的总和= 0.
另请注意,将所有ai乘以相同的量k也将满足约束。因此,找到最大的ai(我们称之为amax),如果amax大于c,则将ai的所有值乘以c /(amax + epsilon),其中epsilon是大于零的任何数。
我错过了什么吗?