문제

I have several hundred tuples on the following format (id1, id2, id3, [xydata]) For example:

('a', 'b', 'c', [(1, 2),(2, 3),(3, 4)])
('a', 'b', 'c', [(1, 1),(2, 4),(3, 6)])
('a', 'b', 'd', [(1, 3),(2, 6),(3, 7)])
('a', 'b', 'd', [(1, 7),(2, 8),(3, 9)])

Now I want to merge the tuples so that those that start with the same three values are combined in the following way. I am guaranteed that the same X values are in all xydata:

('a', 'b', 'c', [(1, mean(2, 1)),(2, mean(3, 4)),(3, mean(4, 6))])
('a', 'b', 'd', [(1, mean(3, 7)),(2, mean(6, 8)),(3, mean(7, 9))])

The current solution takes several steps to reorder and break out the data, storing the tuples in a multilayer dictionary before combining them and rebuilding the original datastructure. Is there a neat and Pythonic way to do this instead?

도움이 되었습니까?

해결책 2

You can merge by using defaultdict:

>>> l = [('a', 'b', 'c', [(1, 2),(2, 3),(3, 4)]),
...      ('a', 'b', 'c', [(1, 1),(2, 4),(3, 6)]),
...      ('a', 'b', 'd', [(1, 3),(2, 6),(3, 7)]),
...      ('a', 'b', 'd', [(1, 7),(2, 8),(3, 9)])]

>>> d = defaultdict(lambda:defaultdict(list))
>>> for k1,k2,k3, lst in l:
...  for t in lst:
...   d[(k1,k2,k3)][t[0]].append(t[1])

result:

>>> d
defaultdict(<function <lambda> at 0x8e33e9c>, 
{('a', 'b', 'c'): defaultdict(<type 'list'>, {1: [2, 1], 2: [3, 4], 3: [4, 6]}),
 ('a', 'b', 'd'): defaultdict(<type 'list'>, {1: [3, 7], 2: [6, 8], 3: [7, 9]})})

if you need it in list:

>>> [(k, v.items()) for k,v in d.items()]
[(('a', 'b', 'c'), [(1, [2, 1]), (2, [3, 4]), (3, [4, 6])]),
 (('a', 'b', 'd'), [(1, [3, 7]), (2, [6, 8]), (3, [7, 9])])]

with mean calculation:

>>> [(k, [(n, sum(t)/float(len(t))) for n,t in v.items()]) for k,v in d.items()]
[(('a', 'b', 'c'), [(1, 1.5), (2, 3.5), (3, 5.0)]),
 (('a', 'b', 'd'), [(1, 5.0), (2, 7.0), (3, 8.0)])]

다른 팁

Using itertools.groupby, izip and some list comprehensions:

from itertools import groupby, izip
from pprint import pprint

lis = [('a', 'b', 'c', [(1, 2), (2, 3), (3, 4)]), ('a', 'b', 'c', [(1, 1), (2, 4), (3, 6)]), ('a', 'b', 'd', [(1, 3), (2, 6), (3, 7)]), ('a', 'b', 'd', [(1, 7), (2, 8), (3, 9)])]

def solve(seq, X):
    for k, g in groupby(seq, key=lambda x:x[:3]):
        data = ((y[1] for y in x[3]) for x in g)
        yield  tuple(list(k) + [[(a, sum(b, 0.0)/len(b)) 
                                                for a, b in izip(X, izip(*data))]])

X = [a for a, _ in lis[0][3]]
pprint(list(solve(lis, X)))  

Output:

[('a', 'b', 'c', [(1, 1.5), (2, 3.5), (3, 5.0)]),
 ('a', 'b', 'd', [(1, 5.0), (2, 7.0), (3, 8.0)])]
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top