2016-07-20 3 views
0

В Python У меня есть словарь значений с суммой 1.0.Как распределить значения в определенном диапазоне (0 - 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.

+0

математически эта проблема у вас имеет бесконечное количество решений.Предполагая, что вы устанавливаете 'obj_3', сумма всех остальных объектов должна быть равна 1 - obj_3. Есть бесконечные способы сделать это, даже если вы наложите на них неотрицательные условия. Длинная история, вам нужно придумать больше условий или оставить вещи на произвол. –

+0

Я думаю, что хотел бы распределить разницу в зависимости от процента. Имеет ли это смысл? –

ответ

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] 

Если есть лучший способ, пожалуйста, не стесняйтесь, дайте мне знать!

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}.

+0

Да, я думал о чем-то подобном. Кроме того, что я не добавляю новые значения, я просто меняю любой из существующих. Попытка подтвердить это право, спасибо! –

+1

Это то, что было на моем первом месте, но вы должны быть осторожны. Дикты не понимают порядок, поэтому может быть, что вы пытаетесь обновить значение, которое обычно будет меньше нуля. Кто вы отдаете потом? попробуйте запустить пример OPs несколько раз, чтобы увидеть. –

+0

О, если вы хотите только обновить существующий ключ/значение, используйте ту же функцию, вызывая 'del oldDict [key]' после утверждений. – dirkster

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)? Зависит от того, чего вы хотите достичь.

+0

'set_weight' не является процентом. Я не могу просто умножить его на инвертированное значение. Попробуйте это с разными значениями, например '0.1', и вы увидите, что итоговая сумма не указана. Спасибо хоть. –

Смежные вопросы