6

キー「時間」、「電力」、「使用」にdictionary3を含むpythonがあります。listsすべてのリストに同じ数の要素があり、すべてのリストがソートされています。私がやりたいことは、時間単位ごとに電力と使用量のサンプルが 1 つだけになるように、インデックスがリスト「時間」の同じ値に対応するリスト「電力」と「使用量」のすべての要素を合計することです。

たとえば、この辞書を変換します。

{'time': [1, 2, 2, 3, 4, 4, 5],
 'power': [2, 2, 3, 6, 3, 3, 2],
 'usage': [0, 1, 1, 2, 1, 4, 7]}

これに:

{'time': [1, 2, 3, 4, 5],
 'power': [2, 5, 6, 6, 2],
 'usage': [0, 2, 2, 5, 7]}

すでに動作するこのコードを書いていますが、あまり好きではありません:

d = {'time':[1,2,2,3,4,4,5], 'power':[0,1,1,2,1,4,7], 'usage':[2,2,3,6,3,3,2]}
prev = -1
new_d = {'time':[], 'power': [], 'usage':[]}
indexes =  range( len(d['time']) )

for i in indexes:
  if d['time'][i]!=prev:
    new_d['time'].append(d['time'][i])
    new_d['power'].append(d['power'][i])
    new_d['usage'].append(d['usage'][i])
  else:
    last_power = len( new_d['power'] ) - 1
    last_usage = len( new_d['usage'] ) - 1
    new_d['power'][last_power]+=d['power'][i]
    new_d['usage'][last_usage]+=d['usage'][i]
  prev=d['time'][i]

print d
print new_d

これをより簡単かつ包括的に行うpythonianの方法はありますか?

4

9 に答える 9

3

これは、任意の辞書を処理するものです....(あなたの辞書はどこにdありますか...)

from itertools import groupby, imap
from operator import itemgetter

def group_dict_by(mapping, field, agg=sum):
    grouper = mapping[field]
    new_grouper = []
    accum = {k: [] for k in mapping.viewkeys() - [field]}
    for key, grp in groupby(enumerate(grouper), itemgetter(1)):
        new_grouper.append(key)
        idx = [g[0] for g in grp]   
        for dk, dv in accum.iteritems():
            dv.append(agg(imap(mapping[dk].__getitem__, idx)))

    accum[field] = new_grouper
    return accum

print group_dict_by(d, 'time')
# {'usage': [0, 2, 2, 5, 7], 'power': [2, 5, 6, 6, 2], 'time': [1, 2, 3, 4, 5]}
于 2013-04-10T14:50:41.007 に答える
3

任意の数の追加フィールドを処理できる堅牢なソリューション - 「時間」フィールドでソート (メソッドとして):

def aggregate(old_d, sort_key='time'):
    new_d = dict((k, []) for k in old_d)
    prev = None
    curr = None
    for i in range(len(old_d[sort_key])):
        curr = old_d[sort_key][i]
        for key, lst in new_d.iteritems(): # .items() in Python 3+
            if prev == curr:
                if key != sort_key:           
                    lst[-1] += old_d[key][i]
            else:
                lst.append(old_d[key][i])
        prev = curr
    return new_d

辞書の使用:

d = {'time': [1, 2, 2, 3, 4, 4, 5],
     'power': [2, 2, 3, 6, 3, 3, 2],
     'usage': [0, 1, 1, 2, 1, 4, 7]}

print aggregate(d)
>>>
{'usage': [0, 2, 2, 5, 7], 'power': [2, 5, 6, 6, 2], 'time': [1, 2, 3, 4, 5]}
于 2013-04-10T13:03:38.583 に答える
1
>>> from itertools import groupby
>>> from operator import itemgetter
>>> d = {'usage': [0, 1, 1, 2, 1, 4, 7], 'power': [2, 2, 3, 6, 3, 3, 2], 'time': [1, 2, 2, 3, 4, 4, 5]}
>>> groups = groupby(zip(d['time'], d['power'], d['usage']), key=itemgetter(0))
>>> lists = zip(*[[k] + map(sum, zip(*g)[1:]) for k, g in groups])
>>> dict(zip(('time', 'power', 'usage'), lists))
{'usage': (0, 2, 2, 5, 7), 'power': (2, 5, 6, 6, 2), 'time': (1, 2, 3, 4, 5)}

For variable number of keys, I've added the keys variable to avoid having to rewrite them:

>>> from itertools import groupby
>>> from operator import itemgetter
>>> keys = ('time', 'power', 'usage')
>>> groups = groupby(zip(*[d[k] for k in keys]), key=itemgetter(0))
>>> lists = zip(*[[k] + map(sum, zip(*g)[1:]) for k, g in groups])
>>> dict(zip(keys, lists))
{'usage': (0, 2, 2, 5, 7), 'power': (2, 5, 6, 6, 2), 'time': (1, 2, 3, 4, 5)}
于 2013-04-10T13:50:24.380 に答える
1

最初に値を新しい dict にグループ化し、次に合計します。少し多くのスペースが必要ですが、簡単で高速です。

from collections import defaultdict
from itertools import groupby

power = defaultdict(list)
usage = defaultdict(list)

for i, time in enumerate(data['time']):
    power[time].append(data['power'][i])
    usage[time].append(data['usage'][i])

times = [key for key,group in groupby(data['time'])]

print {    'time': times,
           'power' : [sum(power[time]) for time in times],
           'usage' : [sum(usage[time]) for time in times]
       }
于 2013-04-10T13:15:43.923 に答える
0

これは「pythonianの方法」です:):

d = {'time': [1, 2, 2, 3, 4, 4, 5],
 'power': [2, 2, 3, 6, 3, 3, 2],
 'usage': [0, 1, 1, 2, 1, 4, 7]}

new_d = {'time' : [], 'power' : [], 'usage' : []}

for time in set(d['time']):
    new_d['time'].append(time)
    new_d['power'].append(sum(value for index, value in enumerate(d['power']) if d['time'][index] == time)) 
    new_d['usage'].append(sum(value for index, value in enumerate(d['usage']) if d['time'][index] == time))

print new_d
于 2013-04-10T13:09:23.297 に答える