Pythonにて、辞書(dict({key,value})を使って、list型の全要素をValue値に変換する際の、
高速化が可能かどうかをご教授いただきたいです。
python
1dict1 = {"a":"100","b":"200","c":"300"} #例です。 (大量に辞書リストくらいあることを想定 2target_list =["a","b","c","d"] #例です。 (大量にデータがある事を想定 3 4new_list = [] #list初期化 5new_list = [ list(map(dict(dict1).get, document)) for document in target_list] 6print(new_list) 7#[['100'], ['200'], ['300'], [None]] 8
上記コードのように、一応内包表記はしているのですが、速度改善のための方法を教えていただきたいです。
追記
デバッグ可能状態で実行したところ、26秒程度かかっておりましたが、
デバッグなしの状態では、全処理に3.515秒となりました。
→アルゴリズム等の問題ではありませんでした。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答2件
0
気になって色々と試したけど、ピュアPythonのlist(map(dict1.get, target_list))
が一番早いみたい。
ProcessPoolExecutorも試したけどオーバーヘッド(多分プロセス間のオブジェクト転送によるもの)で比較対照にはならず、元のPythonコードで最適化しているのでnumba
やcython
でも特に速くならず。
Cとか使ってPythonの外の世界で仕事をしないとこれ以上の高速化はできなさそうです。
コード
python
1from collections import defaultdict 2from functools import partial 3from random import random 4from timeit import timeit 5from uuid import uuid4 6 7 8import numba 9import cython 10 11 12def testdata(n_table, n_list): 13 return ( 14 {str(uuid4()):random() for _ in range(n_table)}, 15 [str(uuid4()) for _ in range(n_list)], 16 ) 17 18 19def pattern1(dict1, target_list): 20 return [*map(dict1.get, target_list)] 21 22 23def pattern2(dict1, target_list): 24 dict1 = defaultdict(lambda: None, dict1) 25 return [dict1[k] for k in target_list] 26 27 28def pattern3(dict1, target_list): 29 return [dict1.get(k) for k in target_list] 30 31 32def pattern4(dict1, target_list): 33 return list(map(dict1.get, target_list)) 34 35 36def pattern5(dict1, target_list): 37 def gen(T, L): 38 for i in L: 39 try: 40 yield T[i] 41 except KeyError: 42 yield None 43 return list(gen(dict1, target_list)) 44 45 46def pattern6(dict1, target_list): 47 def gen(T, L): 48 T_get = T.get 49 for i in L: 50 yield T_get(i) 51 return list(gen(dict1, target_list)) 52 53 54pattern7 = numba.jit(pattern4) 55 56 57def pattern8(dict1, target_list): 58 @numba.jit 59 def gen(T, L): 60 T_get = T.get 61 for i in L: 62 yield T_get(i) 63 return list(gen(dict1, target_list)) 64 65 66pattern9 = partial(cython.inline, "list(map(dict1.get, target_list))") 67pattern9(dict1={}, target_list=[]) 68 69 70if __name__ == "__main__": 71 T, L = testdata(100000, 1000000) 72 73 for i in range(9): 74 func = "pattern%d" % (i + 1) 75 elapsed = timeit(func + "(dict1=T, target_list=L)", 76 number=10, globals=globals()) / 10 77 print("%s: %.3f sec" % (func, elapsed)) 78
実行結果
pattern1: 0.212 sec pattern2: 0.576 sec pattern3: 0.277 sec pattern4: 0.199 sec pattern5: 0.502 sec pattern6: 0.302 sec pattern7: 0.214 sec pattern8: 2.336 sec pattern9: 0.220 sec
環境
C:\Users\sakurai>python -VV Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)]
投稿2018/02/01 10:53
総合スコア6142
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/02/01 11:08
2018/02/01 23:23
0
ベストアンサー
欲しいリストを誤解しているかもしれませんがnew_list = [ dict1.get(document) for document in target_list]
なのでは?
Python
1def func(N): 2 # とりあえずキーは文字列とする 3 dict1 = {('%06d'%i):i for i in range(N)} 4 print(dict1) 5 # {'000000': 0, '000001': 1} 6 7 target_list = [('%06d'%(i%N)) for i in range(3*N)] 8 print(target_list) 9 # ['000000', '000001', '000000', '000001', '000000', '000001'] 10 11 new_list = [ list(map(dict(dict1).get, document)) for document in target_list] 12 print(new_list) # これが求めたいリスト? 13 # [[None, None, None, None, None, None], [None, None, None, None, None, None], [None, None, None, None, None, None], [None, None, None, None, None, None], [None, None, None, None, None, None], [None, None, None, None, None, None]] 14 15 new_list = [ dict1.get(document) for document in target_list] 16 print(new_list) # こちらでは? 17 # [0, 1, 0, 1, 0, 1] 18 19func(2)
辞書100万、元リスト300万要素での実行結果
i7-3770, 16GB, Win10, Anaconda(x64), python=3.5.x
Python
1def printTime( prev): 2 cur = time.time() 3 print ("elapsed[%.3f][sec]"%(cur - prev)) 4 return cur 5 6def func(N): 7 prev = time.time() 8 dict1 = {('key%06d'%i):('val%06d'%i) for i in range(N)} 9 prev = printTime(prev) 10 target_list = [('key%06d'%(i%N)) for i in range(3*N)] 11 prev = printTime(prev) 12 new_list = [ [dict1.get(document)] for document in target_list] 13 prev = printTime(prev) 14func(1000000) 15""" 16elapsed[0.794][sec] 17elapsed[1.138][sec] 18elapsed[2.558][sec] 19"""
投稿2018/02/01 02:41
編集2018/02/01 05:20総合スコア38230
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2018/02/01 02:59
2018/02/01 04:03
2018/02/01 04:22
2018/02/01 04:26
2018/02/01 04:28
2018/02/01 04:38
2018/02/01 04:48 編集
2018/02/01 04:50
2018/02/01 04:53
2018/02/01 05:01
2018/02/01 05:21
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。