2013-05-07 2 views
3

У меня есть (довольно большой) словарь, который имеет числовые значения, например, в форме data = {'a': 0.2, 'b': 0.3, ...}. Каков наилучший способ нормализации этих значений (EDIT: убедитесь, что значения суммируются до 1)?Нормализация значений словаря

И что меня особенно интересует: будет ли это для определенного размера набора данных использовать, например, numpy вместо понимания dict?

Я использую python 2.7.

+11

Что вы имеете в виду нормализуют? – Mark

+0

Сумма значений должна быть равна единице. – 2013-05-07 11:35:38

+0

Вы хотите заменить значения в оригинальном словаре или хотите новый? –

ответ

12

Попробуйте изменить на месте:

d={'a':0.2, 'b':0.3} 
factor=1.0/sum(d.itervalues()) 
for k in d: 
    d[k] = d[k]*factor 

результат:

>>> d 
{'a': 0.4, 'b': 0.6} 

В качестве альтернативы для изменения в новый словарь, использовать Dict понимание:

d={'a':0.2, 'b':0.3} 
factor=1.0/sum(d.itervalues()) 
normalised_d = {k: v*factor for k, v in d.iteritems() } 

Обратите внимание на использование d.iteritems(), который использует меньше памяти, чем d.items(), поэтому лучше для большого словаря.

EDIT: Поскольку существует довольно много из них, и получить это право, кажется, важно, я кратко все идеи в комментариях к этому ответу вместе с следующим (включая заимствование что-то из this post) :

import math 
import operator 

def really_safe_normalise_in_place(d): 
    factor=1.0/math.fsum(d.itervalues()) 
    for k in d: 
     d[k] = d[k]*factor 
    key_for_max = max(d.iteritems(), key=operator.itemgetter(1))[0] 
    diff = 1.0 - math.fsum(d.itervalues()) 
    #print "discrepancy = " + str(diff) 
    d[key_for_max] += diff 

d={v: v+1.0/v for v in xrange(1, 1000001)} 
really_safe_normalise_in_place(d) 
print math.fsum(d.itervalues()) 

Взял пару идет придумать словарь, который фактически создал ненулевую ошибку при нормализации, но надеюсь, что это иллюстрирует точку.

+1

лучше использовать 'd.itervalues' (так как вы повторяете значения дважды и сохраняете их в списке в памяти, если используете' d.values ​​() ') – jamylak

+0

Спасибо - это хороший момент. Я обновил, чтобы использовать itervalues. – Benedict

+1

Чтобы повысить точность, используйте * math.fsum() * вместо * sum() *. С большим словарем OP больше возможностей для потери точности во время суммирования, что приводит к небольшому отсутствию * фактора *. –

3
def normalize(d, target=1.0): 
    raw = sum(d.values()) 
    factor = target/raw 
    return {key:value*factor for key,value in d.iteritems()} 

Используйте это так:

>>> data = {'a': 0.2, 'b': 0.3, 'c': 1.5} 
>>> normalize(data) 
{'b': 0.15, 'c': 0.75, 'a': 0.1} 
+0

Вам нужны iteritems для python 2.x. – 2013-05-07 11:41:59

+0

Словарь довольно большой, поэтому было бы лучше его изменить на месте – jamylak

+0

@Jaapsneep: Я не видел ссылку на Python 2.7, когда я впервые прочитал вопрос. Благодарю. –

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