如何在一定范围内分配值(0 - 1.0)

时间:2016-07-20 08:37:33

标签: python sum distribution

在Python中,我有一个总和为1.0的值字典。

weights = {u'obj_1': 0.018564743024138134, u'obj_2': 0.012814665648003992, 
           u'obj_3': 0.38978992409415425, u'obj_4': 0.0594938403597285, 
           u'obj_5': 0.41613932145700294, u'obj_6': 0.10319750541697208}

我希望能够为其中一个设置新值,差异将均匀分配给其余部分。所有值的总和应始终为1.0。

我写这篇文章是为了做到这一点。

set_inf = "obj_4"
set_weight = 0.9

rest = set_weight-weights[set_inf]
distribute_count = len(weights)-1
distribute_weight = rest/distribute_count

for inf, val in weights.items():
    if inf == set_inf:
        weights[inf] = set_weight
    else:
        new_val = val-distribute_weight
        weights[inf] = new_val

    print "%s : %s" % (inf, weights[inf])

哪个输出:

obj_3 : 0.221688692166
obj_2 : -0.15528656628
obj_1 : -0.149536488904
obj_6 : -0.0649037265111
obj_5 : 0.248038089529
obj_4 : 0.9
Total sum: 1.0

obj_4设置为我想要的值,总和等于1.0。问题是我想确保每个值永远不会低于0,并且永远不会超过1.0。

这就是混乱的来源,我不确定处理它的最佳方法。如果我限制值,它仍然需要补偿其他值,否则总和不会是1.0。我怎样才能实现这样的目标呢?

set_weight可以是介于0到1.0之间的任何值。

3 个答案:

答案 0 :(得分:3)

这很大程度上取决于您要实现的算法类型。如果将实现中变为负值的值设置为零并将剩余的值分配给剩余的值可能对您有用,请尝试这样的操作

def updateDict(oldDict, key, val):
    assert(val <= 1.0)
    assert(sum(oldDict.values()) == 1.0)
    while sum(oldDict.values()) + val > 1.0:
        nVals = len(oldDict)
        diff = 1. - (sum(oldDict.values()) + val)
        diffPerVal = diff / nVals
        for k in oldDict:
            if oldDict[k] + diffPerVal >= 0.:
                oldDict[k] += diffPerVal
            else:
                oldDict[k] = 0.
    oldDict[key] = val

现在

d = {1: 0.5, 2: 0.5}
updateDict(d, 3, 0.2)

产生d = {1: 0.4, 2: 0.4, 3: 0.2},而

d = {1: 0.2, 2: 0.8}
updateDict(d, 3, 0.9)

收益d = {1: 0.0, 2: 0.10000000000000009, 3: 0.9}

答案 1 :(得分:0)

它总结为1(我责备浮动精度),但我想你想这样做吗?

weights = {u'obj_1': 0.018564743024138134, u'obj_2': 0.012814665648003992,
           u'obj_3': 0.38978992409415425, u'obj_4': 0.0594938403597285,
           u'obj_5': 0.41613932145700294, u'obj_6': 0.10319750541697208}

set_inf = "obj_4"
set_weight = 0.9

rest = set_weight-weights[set_inf]
distribute_count = len(weights)-1
distribute_weight = rest/distribute_count

sum = 0.0
for inf, val in weights.items():
    if inf == set_inf:
        weights[inf] = set_weight
    else:
        weights[inf] = val*(1-set_weight)  # this changed

    print "%s : %s" % (inf, weights[inf])
    sum += weights[inf]
print "%s" % sum

这会产生

obj_3 : 0.0389789924094
obj_2 : 0.0012814665648
obj_1 : 0.00185647430241
obj_6 : 0.0103197505417
obj_5 : 0.0416139321457
obj_4 : 0.9
0.994050615964

因为你已经在词典中有分数,你只需要将其余数字乘以0.1(1 - 0.9)? 取决于你想要达到的目标。

答案 2 :(得分:0)

这似乎与我期待的一样。

weights = [0.2, 0.4, 0.3, 0.1]

def update_value(index, new_value):
    dif = (1.0-new_value) / (1.0-weights[index])

    for i in range(len(weights)):
        if i == index:
            weights[i] = new_value
        else:
            weights[i] *= dif

这种方式适用于新值小于或大于原始值的情况,并且所有其他值都相应地传播。

update_value(1, 0.6)
# Returns [0.13333333333333336, 0.6, 0.19999999999999998, 0.06666666666666668]

update_value(1, 0.1)
# Returns: [0.30000000000000004, 0.1, 0.44999999999999996, 0.15000000000000002]

如果有更好的方式,请随时告诉我!