Python: объединение учетных данных - PullRequest
3 голосов
/ 09 мая 2011

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

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

0,2 А

0,1 А

0,3 А

0,3 B

0,2 C

0,5 С

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

0,6 A

0,3 В

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

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

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

Ответы [ 11 ]

6 голосов
/ 09 мая 2011

Вы хотите использовать 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
3 голосов
/ 10 мая 2011

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

result = {}
for line in percents:
    value, key = line
    result[key] = result.get(key, 0) + float(value)
2 голосов
/ 10 мая 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}
2 голосов
/ 09 мая 2011
total = {}
data = [('0.1', 'A'), ('0.2', 'A'), ('.3', 'B'), ('.4', 'B'), ('-10', 'C')]
for amount, key in data:
    total[key] = total.get(key, 0.0) + float(amount)

for key, amount in total.items():
    print key, amount
1 голос
/ 10 мая 2011

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

# 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')})

1 голос
/ 09 мая 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']
>>> 
1 голос
/ 09 мая 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!
0 голосов
/ 10 мая 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])]
0 голосов
/ 10 мая 2011
>>> from itertools import groupby, imap
>>> from operator import itemgetter
>>> data = [['0.2', 'A'], ['0.1', 'A'], ['0.3', 'A'], ['0.3', 'B'], ['0.2', 'C'], ['0.5', 'C']]
>>> # data = sorted(data, key=itemgetter(1))
... 
>>> for k, g in groupby(data, key=itemgetter(1)):
...     print sum(imap(float, imap(itemgetter(0), g))), k
... 
0.6 A
0.3 B
0.7 C
>>> 
0 голосов
/ 10 мая 2011
letters = {}
for line in open("data", "r"):
    lineStrip = line.strip().split()
    percent = float(lineStrip[0])
    letter = lineStrip[1]
    if letter in letters:
        letters[letter] = percent + letters[letter]
    else:
        letters[letter] = percent

for letter, percent in letters.items():
    print letter, percent

A 0.6
C 0.7
B 0.3
...