2016-07-20 18 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つに新しい値を設定したいと思っています。その差は残りの部分に均等に分配されます。すべての値の合計は常に1.0にする必要があります。

私はこれを行うためにこれを書いています。

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に等しい:出力

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]) 

。問題は、各値が決して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

実装したいアルゴリズムの種類に大きく依存します。あなたのために働くだろうゼロにあなたの実装でマイナスとなり、残りの上に残りを配布する値を設定した場合、

ながら、今

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

d = {1: 0.4, 2: 0.4, 3: 0.2}生み出すこの

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.2, 2: 0.8} 
updateDict(d, 3, 0.9) 

収量d = {1: 0.0, 2: 0.10000000000000009, 3: 0.9}

+0

はい私はこれのようなものを考えていました。私は新しい値を追加するのではなく、既存の値を変更するだけです。この権利を確認しようとしています、ありがとう! –

+1

これは私の心にも最初に来たものですが、注意する必要があります。 Dictsは順序を理解していないので、最後にゼロ以下になる値を更新しようとすることができます。あなたは誰が残りをあげていますか?表示するOPの例を何度も試してみてください。 –

+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'のような異なる値で試してみると、結果の合計が消えてしまいます。しかし、ありがとう。 –

関連する問題