2016-05-25 4 views
1

私は数百万のトランザクションを持つテーブルを持っています。テーブルは、トランザクションのタイムスタンプ、金額、およびいくつかの他のプロパティ(例えば、アドレス)を含む。それぞれの取引について、同じ住所、例えば1ヶ月などの期間内に発生した取引の数と金額の合計を計算したいと考えています。ここでトランザクションログから速度変数を計算する

は、例えば、入力された:

+----+---------------------+----------------+--------+ 
| id | ts     | address  | amount | 
+----+---------------------+----------------+--------+ 
| 0 | 2016-10-11 00:34:21 | 123 First St. | 56.20 | 
+----+---------------------+----------------+--------+ 
| 1 | 2016-10-13 02:53:58 | 456 Second St. | 96.19 | 
+----+---------------------+----------------+--------+ 
| 2 | 2016-10-23 02:28:17 | 123 First St. | 64.65 | 
+----+---------------------+----------------+--------+ 
| 3 | 2016-10-31 07:14:35 | 456 Second St. | 36.38 | 
+----+---------------------+----------------+--------+ 
| 4 | 2016-11-04 09:25:39 | 123 First St. | 93.65 | 
+----+---------------------+----------------+--------+ 
| 5 | 2016-11-20 22:30:15 | 123 First St. | 88.39 | 
+----+---------------------+----------------+--------+ 
| 6 | 2016-11-28 09:39:14 | 123 First St. | 74.40 | 
+----+---------------------+----------------+--------+ 
| 7 | 2016-12-03 17:09:12 | 123 First St. | 83.13 | 
+----+---------------------+----------------+--------+ 

これはすべき出力:

+----+-------+--------+ 
| id | count | amount | 
+----+-------+--------+ 
| 0 | 0  | 0.00 | 
+----+-------+--------+ 
| 1 | 0  | 0.00 | 
+----+-------+--------+ 
| 2 | 1  | 56.20 | 
+----+-------+--------+ 
| 3 | 1  | 96.19 | 
+----+-------+--------+ 
| 4 | 2  | 120.85 | 
+----+-------+--------+ 
| 5 | 1  | 64.65 | 
+----+-------+--------+ 
| 6 | 1  | 88.39 | 
+----+-------+--------+ 
| 7 | 2  | 162.79 | 
+----+-------+--------+ 

これを行うために、私は、タイムスタンプでテーブルをソートして、私は基本的にキューや辞書を使用していますしかし、それは本当に遅く実行されているようだ、私はそれを行うより良い方法があるのだろうかと思っていた。ここで

が私のコードです:

import csv 
import Queue 
import time 

props = [ 'address', ... ] 
spans = { '1m': 2629800, ... } 

h = [ 'id' ] 
for value in [ 'count', 'amount' ]: 
    for span in spans: 
     for prop in props: 
      h.append(span + '_' + prop + '_' + value) 

tq = { } 
kq = { } 
vq = { } 
for span in spans: 
    tq[span] = Queue.Queue() 
    kq[span] = { } 
    vq[span] = { } 
    for prop in props: 
     kq[span][prop] = Queue.Queue() 
     vq[span][prop] = { } 

with open('transactions.csv', 'r') as csvin, open('velocities.csv', 'w') as csvout: 
    reader = csv.DictReader(csvin) 
    writer = csv.DictWriter(csvout, h) 
    writer.writeheader() 
    for i in reader: 
     o = { 'id': i['id'] } 
     ts = time.mktime(time.strptime(i['ts'], '%Y-%m-%d %H:%M:%S')) 
     for span in spans: 
      while not tq[span].empty() and ts > tq[span].queue[0] + spans[span]: 
       tq[span].get() 
       for prop in props: 
        key = kq[span][prop].get() 
        vq[span][prop][key].get() 
        if vq[span][prop][key].empty(): 
         del vq[span][prop][key] 
      tq[span].put(ts) 
      for prop in props: 
       kq[span][prop].put(i[prop]) 
       if not i[prop] in vq[span][prop]: 
        vq[span][prop][i[prop]] = Queue.Queue() 
       o[span + '_' + prop + '_count'] = vq[span][prop][i[prop]].qsize() 
       o[span + '_' + prop + '_amount'] = sum(vq[span][prop][i[prop]].queue) 
       vq[span][prop][i[prop]].put(float(i['auth'])) 
     writer.writerow(o) 
     csvout.flush() 

私はまた、RB-木とvq[span][prop]を交換しようとしたが、パフォーマンスはさらに悪化していました。

答えて

0

どちらのコードが、それはあなたが言うことをやっている場合には必要以上に(複雑、複雑ではない)大幅複雑ですので、私は基本的にあなたが何をしようとして誤解、またはあなたがあなたはやっている。あなたが言うように、あなたが「数百万のトランザクション」の上に、まだが動作している

import csv 
from collections import namedtuple, defaultdict, Counter 
from datetime import datetime 

Span = namedtuple('Span', ('start', 'end')) 

month_span = Span(start=datetime(2016, 1, 1), end=datetime(2016, 1, 31)) 
counts = defaultdict(Counter) 
amounts = defaultdict(Counter) 
with open('transactions.csv') as f: 
    reader = csv.DictReader(f) 
    for row in reader: 
     timestamp = datetime.strptime(row['ts'], '%Y-%m-%d %H:%M:%S') 
     if month_span.start < timestamp < month_span.end: # or <= 
      # You do some checking for properties. If you *will* always 
      # have these columns, you *should* just use ``row['count']`` 
      # and ``row['amount']`` 
      counts[month_span][row['address']] += int(row.get('count', 0)) 
      amount[month_span][row['address']] += float(row.get('amount', 0.00)) 
print(counts) 
print(amounts) 

注意。あなたが同じことをしているので、それをどのように回しても、時間がかかるでしょう数百万回。あなたの現在のコードがどこに費やされているのかを見たい場合は、profile itです。私はline profilerが使いやすく、うまく機能していることがわかります。

あなたは何百万回も何をしているのだろうから、これをさらにスピードアップすることはできません。 Cython、C、またはC++。それはいくつかのことをスピードアップしますが、コードを書くことは間違いなくもっと難しくなります。

+0

私は十分にクリアされていないかもしれません。私がCSV(トランザクション)内の行を処理する場合、カウントと金額は、そのトランザクションの前月以内に発生したすべてのトランザクション(たとえば、そのプロパティを共有しているすべてのトランザクション)例えば、同じアドレスを持つ)。 – wizplum

+0

例として、これは、現在のトランザクションの日付が「2016-03-01 10:33:11」で、アドレスが「123 Main St」の場合、2629800まで発生したすべてのトランザクションを反映することを意味しますその前に同じアドレスを持っていました。 – wizplum

+0

二次元でグループ化しているのなら、かなり簡単です。単に 'defaultdict(Counter)'を使用してください。私の例を更新しました。 –

関連する問題