假设您有一组理想比率,其总和 = 1。例如,
set = [0.2, 0.1, 0.4, 0.3]
但是假设有一条规则规定,如果它不等于 0,则它们都不应该低于一个值:
min = 0.25
直观地说,我们可以说一个很好的拟合是:
set = [0.25, 0, 0.425, 0.325]
但我真的不知道我在那里做了什么。
这种问题有名字吗?什么是通用解决方案?
假设您有一组理想比率,其总和 = 1。例如,
set = [0.2, 0.1, 0.4, 0.3]
但是假设有一条规则规定,如果它不等于 0,则它们都不应该低于一个值:
min = 0.25
直观地说,我们可以说一个很好的拟合是:
set = [0.25, 0, 0.425, 0.325]
但我真的不知道我在那里做了什么。
这种问题有名字吗?什么是通用解决方案?
让这个最小值为m
,一般的解决方案可能是:
while there is a none zero value smaller then `m`:
x <- lowest value
for each y != x:
y += y*x/ (1-x)
x <- 0
很容易看出,上述循环在每次迭代中都保留了 sum==1,因为:
除 x = 1-x 之外的所有元素的
总和因此,所有增加的总和为
x/(1-x) * [sum of all elements excluding x] = x / (1-x) * (1-x) = x
因此,在每次迭代中,总和减少和增加相同的值,因此总和保持为 1。
我认为这大约是您建议的算法(在 Python 中):
def fx(arr, m):
arr.sort()
if arr[0] >= m:
return arr
return _fx(arr, m, 0)
def _fx(arr, m, i):
extra = arr[i]
arr[i] = 0
for j in range(i + 1, len(arr)):
if arr[j] >= m:
break
extra -= m - arr[j]
arr[j] = m
if extra < 0:
arr[j] += extra
return _fx(arr, m, i + 1)
numToBump = len(arr) - j
for k in range(j, len(arr)):
arr[k] += extra / numToBump
return arr
解释:
首先,我们对数组进行排序。如果第一个元素高于最小值,我们就完成了。否则,_fx
使用我们的参数调用辅助方法 (),加上归零的索引 ( 0
)。
在辅助方法中,我们将i
第 th 个元素清零并将其原始值存储为我们必须分配的“额外”数量。首先,我们尝试将小于最小值的所有元素提升到最小值,方法是从extra
. 如果我们在完成之前用完了多余的东西,我们会尝试将下一个元素归零。
如果我们让所有的东西都高于最小值,那么我们将剩余的额外部分分配给我们尚未触及的元素。
注意:我以不同的顺序返回元素,但最后取消排序很容易。
这些都使用0.25
.
[0.1, 0.2, 0.3, 0.4] -> [0, 0.25, 0.325, 0.425]
[0.1, 0.1, 0.4, 0.4] -> [0, 0, 0.5, 0.5]
至少如果我理解正确,你想取最小的,如果它小于最小值,把它减少到零。然后将足够的(如果有的话)给下一个最小的以满足最小值。(如果不够,将下一个最小值归零,将其值添加到您正在分发的内容中,然后重复)。
当你有最小的到最小的,还有一些剩余的东西要分配给其他人时,你想先把其他人加起来得到一个总和。然后遍历其他数字,并将每个数字除以总和以获得比率。然后,每个人的金额是比率乘以您需要分配的金额。
例如,使用您的原始号码:
set = [0.2, 0.1, 0.4, 0.3]
我们将第二项归零,并将 0.05 分配给第一项,然后分配 0.05。
然后我们将另外两个相加得到 0.7。我们将其他每个除以得到它们的比率:0.4/0.7 和 0.3/0.7。然后我们将每个比率乘以 0.05,得到分配给每个比率的数量:4/7*.05 = .0285714... 和 3/7*.05 = .0214857...
所以我们每一个都加了那么多。当我们到达最后一个时,我们只需将剩下的所有相加,因此如果有任何舍入错误,我们的总和将保持原样。