我需要根据一些权重分配一个值。例如,如果我的权重是1和2,那么我希望列加权为2的值是列加权1的两倍。
我有一些Python代码来演示我正在尝试做什么,以及问题:
def distribute(total, distribution):
distributed_total = []
for weight in distribution:
weight = float(weight)
p = weight/sum(distribution)
weighted_value = round(p*total)
distributed_total.append(weighted_value)
return distributed_total
for x in xrange(100):
d = distribute(x, (1,2,3))
if x != sum(d):
print x, sum(d), d
上面的代码显示了许多情况,其中分配值导致分布的总和不同于原始值。例如,分配权重为(1,2,3)的3会产生(1,1,2),总计为4.
修复此分配算法的最简单方法是什么?
更新:
我希望分布式值是整数值。只要它们总和到正确的值,并且它们与正确的分布“尽可能接近”,整个分布的确切方式无关紧要。
(通过正确的分布,我的意思是非整数分布,我还没有完全定义“尽可能接近”的意思。)可能有几个有效的输出,只要它们总和原始值。)
答案 0 :(得分:3)
按预期分配第一个分享。现在您有一个更简单的问题,参与者少一个,可用于分发的金额减少。重复,直到没有更多的参与者。
>>> def distribute2(available, weights):
... distributed_amounts = []
... total_weights = sum(weights)
... for weight in weights:
... weight = float(weight)
... p = weight / total_weights
... distributed_amount = round(p * available)
... distributed_amounts.append(distributed_amount)
... total_weights -= weight
... available -= distributed_amount
... return distributed_amounts
...
>>> for x in xrange(100):
... d = distribute2(x, (1,2,3))
... if x != sum(d):
... print x, sum(d), d
...
>>>
答案 1 :(得分:2)
你必须以某种方式分发舍入错误:
Actual:
| | | |
Pixel grid:
| | | |
最简单的方法是将每个真值舍入到最近的像素,对于开始和结束位置。因此,当您将块A 0.5向上舍入为1时,您还将块B的起始位置从0.5更改为1.这将B的大小减小0.5(实质上,从其中“窃取”大小)。当然,这会导致你从C中偷B大小,最终导致:
| | | |
但你还有什么期望将3分为3个整体部分?
答案 2 :(得分:1)
如果您希望分配权重为(1,2,3)的3等于(0.5,1,1.5),那么舍入就是您的问题:
weighted_value = round(p*total)
你想:
weighted_value = p*total
编辑:返回整数分布的解决方案
def distribute(total, distribution):
leftover = 0.0
distributed_total = []
distribution_sum = sum(distribution)
for weight in distribution:
weight = float(weight)
leftover, weighted_value = modf(weight*total/distribution_sum + leftover)
distributed_total.append(weighted_value)
distributed_total[-1] = round(distributed_total[-1]+leftover) #mitigate round off errors
return distributed_total
答案 3 :(得分:1)
最简单的方法是计算标准化比例,这是权重总和超过您的目标总和的因子,然后将权重中的每个项目除以该比例。
def distribute(total, weights):
scale = float(sum(weights))/total
return [x/scale for x in weights]