是否有一个很好的算法可以将随机生成的数字拆分成三个桶,每个桶都有关于它们可能包含多少总量的约束。
例如,假设我随机生成的数字为1,000,我需要将其拆分为数据桶a,b和c。
These ranges are only an example. See my edit for possible ranges.
Bucket a may only be between 10% - 70% of the number (100 - 700)
Bucket b may only be between 10% - 50% of the number (100 - 500)
Bucket c may only be between 5% - 25% of the number (50 - 250)
a + b + c must equal the randomly generated number
你希望分配的金额是完全随机的,所以除了等于所有三个桶的概率大约是它们的百分比平均值之外,桶的最大命中率与桶c相同。
编辑:以下内容很可能永远是真的:a + b + c的低端< 100%,a + b + c的高端> 100%。这些百分比仅表示a,b和c的可接受值。在a为10%而b和c为最大值(分别为50%和25%)的情况下,必须重新分配数字,因为总数不等于100%。这是我试图通过找到一种方法在一次通过中分配这些数字来避免的确切情况。
我想找到一种方法在一次通过中随机选择这些数字。
答案 0 :(得分:2)
问题相当于在N维对象中选择一个随机点(在你的例子中为N = 3),该对象由方程式定义(在你的例子中):
0.1 <= x <= 0.7
0.1 <= y <= 0.5
0.05 <= z <= 0.25
x + y + z = 1 (*)
显然,由于最后一个等式(*),其中一个坐标是多余的,即x和y的拾取值决定了z。
消除(*)和其中一个方程给我们留下了一个(N-1)维方框,例如
0.1 <= x <= 0.7
0.1 <= y <= 0.5
被不平等所削减
0.05 <= (1 - x - y) <= 0.25 (**)
派生自(*)和z的等式。这基本上是一个穿过盒子的斜条纹。
为了使结果一致,我只是重复采样(N-1)维方框,并接受满足(**)的第一个采样点。单通道解决方案可能最终会产生偏差分布。
答案 1 :(得分:0)
更新:是的,你是对的,结果不是均匀分布的。
假设你的百分比值是自然数(如果这个假设是错误的,你就不必再读了:)在这种情况下我没有解决方案)。
让我们将事件e
定义为3个值的元组(每个桶的百分比):e =(p a ,p b ,p <子> C 子>)。接下来,创建所有可能的事件e n 。你在这里拥有的是一个由离散数量的事件组成的元组空间。所有可能的事件应该有相同的可能性发生。
假设我们有一个函数f(n)=&gt; Ë<子>名词子>。然后,我们所要做的就是取一个随机数n并一次性返回e n 。
现在,问题仍然是创建这样一个函数f
:)
在伪代码中,一种非常慢的方法(仅用于说明):
function f(n) {
int c = 0
for i in [10..70] {
for j in [10..50] {
for k in [5..25] {
if(i + j + k == 100) {
if(n == c) {
return (i, j, k) // found event!
} else {
c = c + 1
}
}
}
}
}
}
你所知道的是单程解决方案,但问题只会被移除。函数f非常慢。但你可以做得更好:如果你正确设置范围并计算偏移而不是迭代你的范围,我认为你可以更快地计算一切。
这是否足够清楚?
首先,您可能需要调整范围。因为您无法保持条件a
,因此无法使用a+b+c = number
条中的10%。
关于您的问题:(1)为您的范围内的货币a
选择一个随机数,然后(2)以最小和最大百分比更新货柜b
的范围(您应该只缩小范围)。然后(3)为桶b
选择一个随机数。最后c
应该计算出你的条件成立(4)。
示例:
n = 1000
(1) a = 40%
(2) range b [35,50], because 40+35+25 = 100%
(3) b = 45%
(4) c = 100-40-45 = 15%
或者:
n = 1000
(1) a = 70%
(2) range b [10,25], because 70+25+5 = 100%
(3) b = 20%
(4) c = 100-70-20 = 10%
检查所有事件是否均匀分布。如果这应该是一个问题,您可能希望在步骤2中随机化范围更新。