Python: объединение данных подсчета

Хорошо - я уверен, что здесь уже был дан ответ, но я не могу его найти ....

Моя проблема: у меня есть список списков с таким составом

0.2 A

0.1 A

0.3 A

0.3 B

0.2 C

0.5 C

Моя цель - вывести следующее:

0.6 A

0.3 B

0.7 C

Другими словами, мне нужно объединить данные из нескольких строк вместе.

Вот код, который я использую:

unique_percents = []

for line in percents:
    new_percent = float(line[0])
    for inner_line in percents:
        if line[1] == inner_line[1]:
           new_percent += float(inner_line[0])
        else:
            temp = []
            temp.append(new_percent)
            temp.append(line[1])
            unique_percents.append(temp)
            break

Я думаю, это должно сработать, но это не прибавление процентов и все еще есть дубликаты. Может, я не понимаю, как работает "перерыв"?

Я также приму предложения по поводу лучшей структуры цикла или алгоритма для использования. Спасибо, Дэвид.


person David M    schedule 09.05.2011    source источник
comment
Есть ли словарь на Python? Вот что я бы использовал, если бы это был C #.   -  person Michael Todd    schedule 09.05.2011
comment
Это финальный сезон или что-то в этом роде?   -  person Blindy    schedule 09.05.2011
comment
Я бы использовал здесь словарь.   -  person Hamish Grubijan    schedule 09.05.2011
comment
Найдите словари Python. Они именно то, что вам здесь нужно.   -  person Chinmay Kanchi    schedule 09.05.2011
comment
Спасибо всем. Я знаю о словарях, но просто не представлял, как я буду их использовать в этом случае. МНОГИЕ хорошие ответы помогают. О, и Блинди, я сам учусь. Отсюда очень глупые вопросы.   -  person David M    schedule 10.05.2011


Ответы (9)


Вы хотите использовать dict, но collections.defaultdict может быть здесь очень кстати, так что вам не нужно беспокоиться о том, существует ли ключ в dict или нет - по умолчанию он равен 0.0:

import collections

lines = [[0.2, 'A'], [0.1, 'A'], [0.3, 'A'], [0.3, 'B'], [0.2, 'C'], [0.5, 'C']]
amounts = collections.defaultdict(float)
for amount, letter in lines:
    amounts[letter] += amount

for letter, amount in sorted(amounts.iteritems()):
    print amount, letter
person Ben Hoyt    schedule 09.05.2011
comment
Прохладный! За это я и люблю Python, он не перестает вас удивлять :) (P.S. не знал о collections.defaultdict) - person Zaur Nasibov; 10.05.2011

Попробуйте это:

result = {}
for line in percents:
    value, key = line
    result[key] = result.get(key, 0) + float(value)
person zindel    schedule 09.05.2011

Поскольку все буквенные оценки сгруппированы вместе, вы можете использовать itertools.groupby (а если нет, просто отсортируйте список заранее, чтобы сделать их такими):

data = [
    [0.2, 'A'],
    [0.1, 'A'],
    [0.3, 'A'],
    [0.3, 'B'],
    [0.2, 'C'],
    [0.5, 'C'],
]

from itertools import groupby

summary = dict((k, sum(i[0] for i in items)) 
                for k,items in groupby(data, key=lambda x:x[1]))

print summary

Дает:

{'A': 0.60000000000000009, 'C': 0.69999999999999996, 'B': 0.29999999999999999}
person PaulMcG    schedule 09.05.2011
comment
Это здорово, как насчет того, чтобы отсортировать это? - person Hamish Grubijan; 10.05.2011
comment
Использование оператора: key = operator.itemgetter (1) - person riza; 10.05.2011

Если у вас есть список таких списков: [ [0.2, A], [0.1, A], ...] (на самом деле он выглядит как список кортежей :)

res_dict = {}

for pair in lst:
    letter = pair[1]
    val = pair[0]
    try:
        res_dict[letter] += val
    except KeyError:
        res_dict[letter] = val

res_lst = [(val, letter) for letter, val in res_dict] # note, a list of tuples!
person Zaur Nasibov    schedule 09.05.2011

Использование collections.defaultdict для подсчета значений (при условии текстовых данных в d):

>>> s=collections.defaultdict(float)
>>> for ln in d:
...     v,k=ln.split()
...     s[k] += float(v)
>>> s
defaultdict(<type 'float'>, {'A': 0.60000000000000009, 'C': 0.69999999999999996, 'B': 0.29999999999999999})
>>> ["%s %s" % (v,k) for k,v in s.iteritems()]
['0.6 A', '0.7 C', '0.3 B']
>>> 
person gimel    schedule 09.05.2011
comment
как насчет сортировки по a b c? - person Hamish Grubijan; 10.05.2011
comment
Используйте OrderedDict - docs.python.org/library/ - person gimel; 10.05.2011

Если вы используете Python 3.1 или новее, вы можете использовать collections.Counter . Также я предлагаю использовать decimal.Decimal вместо чисел с плавающей запятой:

# Counter requires python 3.1 and newer
from collections import Counter
from decimal import Decimal

lines = ["0.2 A", "0.1 A", "0.3 A", "0.3 B", "0.2 C", "0.5 C"]
results = Counter()
for line in lines:
    percent, label = line.split()
    results[label] += Decimal(percent)
print(results)

Результат:

Счетчик ({'C': десятичный ('0,7'), 'A': десятичный ('0,6'), 'B': десятичный ('0,3')})

person Gregg    schedule 09.05.2011

Это многословно, но работает:

# Python 2.7
lines = """0.2 A
0.1 A
0.3 A
0.3 B
0.2 C
0.5 C"""

lines = lines.split('\n')
#print(lines)
pctg2total = {}
thing2index = {}
index = 0
for line in lines:
    pctg, thing = line.split()
    pctg = float(pctg)
    if thing not in thing2index:
        thing2index[thing] = index
        index = index + 1
        pctg2total[thing] = pctg
    else:
        pctg2total[thing] = pctg2total[thing] + pctg
output = ((pctg2total[thing], thing) for thing in pctg2total)
# Let's sort by the first occurrence.
output = list(sorted(output, key = lambda thing: thing2index[thing[1]]))
print(output)

>>> 
[(0.60000000000000009, 'A'), (0.29999999999999999, 'B'), (0.69999999999999996, 'C')]
person Hamish Grubijan    schedule 09.05.2011

Допустим, у нас есть это

data =[(b, float(a)) for a,b in 
    (line.split() for line in
        """
        0.2 A
        0.1 A
        0.3 A
        0.3 B
        0.2 C
        0.5 C""".splitlines()
        if line)]
print data 
# [('A', 0.2), ('A', 0.1), ('A', 0.3), ('B', 0.3), ('C', 0.2), ('C', 0.5)]

Теперь вы можете просто пройти через это и суммировать

counter = {}
for letter, val in data:
    if letter in counter:
        counter[letter]+=val
    else:
        counter[letter]=val

print counter.items() 

Или сгруппируйте значения вместе и используйте сумму:

from itertools import groupby
# you want the name and the sum of the values
print [(name, sum(value for k,value in grp)) 
    # from each group
    for name, grp in 
    # where the group name of a item `p` is given by `p[0]`
    groupby(sorted(data), key=lambda p:p[0])]
person Jochen Ritzel    schedule 09.05.2011

person    schedule
comment
+1 Мне нравится вызов get () со значением по умолчанию. Приятно иметь возможность держать это в одной строке. - person ralphtheninja; 10.05.2011