使用权重分配整数?怎么算?

时间:2012-01-31 23:06:51

标签: python algorithm

我需要根据一些权重分配一个值。例如,如果我的权重是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.

修复此分配算法的最简单方法是什么?

更新:

我希望分布式值是整数值。只要它们总和到正确的值,并且它们与正确的分布“尽可能接近”,整个分布的确切方式无关紧要。

(通过正确的分布,我的意思是非整数分布,我还没有完全定义“尽可能接近”的意思。)可能有几个有效的输出,只要它们总和原始值。)

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]