2016-08-22 12 views
0

辞書に効率よく展開する必要があるオブジェクトのリストがあります。リストには2,000,000を超えるオブジェクトがあります。操作には1.5時間以上かかる。これをより効率的に行うことができるかどうかを知りたい。 リスト内のオブジェクトは、このクラスに基づいています。Python:オブジェクトのリストをDictionaryに展開する

class ResObj: 
def __init__(self, index, result): 
    self.loc = index ### This is the location, where the values should go in the final result dictionary 
    self.res = result ### This is a dictionary that has values for this location. 

    self.loc = 2 
    self.res = {'value1':5.4, 'value2':2.3, 'valuen':{'sub_value1':4.5, 'sub_value2':3.4, 'sub_value3':7.6}} 

現在のところ、この操作はこの操作を実行するために使用します。

def make_final_result(list_of_results): 
    no_sub_result_variables = ['value1', 'value2'] 
    sub_result_variables = ['valuen'] 
    sub_value_variables = ['sub_value1', 'sub_value3', 'sub_value3'] 

    final_result = {} 
    num_of_results = len(list_of_results) 
    for var in no_sub_result_variables: 
     final_result[var] = numpy.zeros(num_of_results) 
    for var in sub_result_variables: 
     final_result[var] = {sub_var:numpy.zeros(num_of_results) for sub_var in sub_value_variables} 

    for obj in list_of_results: 
     i = obj.loc 
     result = obj.res 
     for var in no_sub_result_variables: 
      final_result[var][i] = result[var] 
     for var in sub_result_variables: 
      for name in sub_value_variables: 
       try: 
        final_result[var][name][i] = result[var][name] 
       except KeyError as e: 
        ##TODO Add a debug check 
        pass 

私は()。辞書やマネージャーmultiprocessing.Managerを使用して試してみました()。配列は、()しかし、私は唯一のにもかかわらず、私は手動で設定する(2つのプロセスが仕事を得ることができ、このために並列処理を使用しますプロセス数= 24)。 より速い方法でパフォーマンスを向上させてください。 ありがとうございます。

+1

これはデータ構造や特に効率的なオブジェクトの初期化をうまく利用しているようには見えませんが、実際にどこから始めたのかは分かりません。入力と出力の例を教えてください。 –

+0

マシン上で実行するのに1.5時間以上かかる短い自己完結型の '.py'ファイルを投稿してください:http://sscce.org/ – pts

+0

あなたはネストされたループを持っているようです:' for var in no_sub_result_variables: 'と'for var in sub_result_variables:'です。本当にネストループをここに入れたいですか?もしそうなら、内部ループ変数の名前を 'var2'に変更してください。 – pts

答えて

0

あなたのループは非ネストされた作るためにいくつかのインデントを削除します。

for obj in list_of_results: 
    i = obj.loc 
    result = obj.res 
    for var in no_sub_result_variables: 
     final_result[var][i] = result[var] 
    for var in sub_result_variables: 
     for name in sub_value_variables: 
      try: 
       final_result[var][name][i] = result[var][name] 
      except KeyError as e: 
       ##TODO Add a debug check 
       pass 
+0

ありがとうございます。私はすでに質問を編集しました。 – ssm

2

ネストされたnumpyの配列を持つことは、あなたのデータを構造化するための最良の方法を思えません。 numpyのstructured arraysを使用すると、より直感的なデータ構造を作成できます。

import numpy as np 

# example values 
values = [ 
    { 
     "v1": 0, 
     "v2": 1, 
     "vs": { 
      "x": 2, 
      "y": 3, 
      "z": 4, 
     } 
    }, 
    { 
     "v1": 5, 
     "v2": 6, 
     "vs": { 
      "x": 7, 
      "y": 8, 
      "z": 9, 
     } 
    } 
] 

def value_to_record(value): 
    """Take a dictionary and convert it to an array-like format""" 
    return (
     value["v1"], 
     value["v2"], 
     (
      value["vs"]["x"], 
      value["vs"]["y"], 
      value["vs"]["z"] 
     ) 
    ) 

# define what a record looks like -- f8 is an 8-byte float 
dtype = [ 
    ("v1", "f8"), 
    ("v2", "f8"), 
    ("vs", [ 
     ("x", "f8"), 
     ("y", "f8"), 
     ("z", "f8") 
    ]) 
]   

# create actual array 
arr = np.fromiter(map(value_to_record, values), dtype=dtype, count=len(values)) 

# access individual record 
print(arr[0]) # prints (0.0, 1.0, (2.0, 3.0, 4.0)) 
# access specific value 
assert arr[0]['vs']['x'] == 2 
# access all values of a specific field 
print(arr['v2']) # prints [ 1. 6.] 
assert arr['v2'].sum() == 7 

データを生成するこの方法を使用すると、マシンで2秒間に200万の長さの配列が作成されました。

オブジェクトをResObjオブジェクトで使用するには、loc属性で並べ替えて、res属性をvalue_to_record関数に渡します。

1

プロセス間で作業をキー名で配布することができます。
ここでは、ワーカーのプールを作成し、varとオプションのサブ変数名を渡します。
巨大なデータセットは安価のforkを使用するワーカーと共有されています。
Unpacker.unpackは、ResObjから指定された変数をピックし、それらをnp.arrayとして返します。
make_final_resultのメインループはfinal_resultの配列を結合します。
PY2

from collections import defaultdict 
from multiprocessing import Process, Pool 
import numpy as np 

class ResObj(object): 
    def __init__(self, index=None, result=None): 
     self.loc = index ### This is the location, where the values should go in the final result dictionary 
     self.res = result ### This is a dictionary that has values for this location. 

     self.loc = 2 
     self.res = {'value1':5.4, 'value2':2.3, 'valuen':{'sub_value1':4.5, 'sub_value2':3.4, 'sub_value3':7.6}} 

class Unpacker(object): 
    @classmethod 
    def cls_init(cls, list_of_results): 
     cls.list_of_results = list_of_results 

    @classmethod 
    def unpack(cls, var, name): 

     list_of_results = cls.list_of_results 
     result = np.zeros(len(list_of_results)) 
     if name is None: 
      for i, it in enumerate(list_of_results): 
       result[i] = it.res[var] 
     else: 
      for i, it in enumerate(list_of_results): 
       result[i] = it.res[var][name] 
     return var, name, result 

#Pool.map doesn't accept instancemethods so the use of a wrapper 
def Unpacker_unpack((var, name),): 
    return Unpacker.unpack(var, name) 


def make_final_result(list_of_results): 
    no_sub_result_variables = ['value1', 'value2'] 
    sub_result_variables = ['valuen'] 
    sub_value_variables = ['sub_value1', 'sub_value3', 'sub_value3'] 

    pool = Pool(initializer=Unpacker.cls_init, initargs=(list_of_results,)) 
    final_result = defaultdict(dict) 

    def key_generator(): 
     for var in no_sub_result_variables: 
      yield var, None 
     for var in sub_result_variables: 
      for name in sub_value_variables: 
       yield var, name 

    for var, name, result in pool.imap(Unpacker_unpack, key_generator()): 
     if name is None: 
      final_result[var] = result 
     else: 
      final_result[var][name] = result 
    return final_result 

if __name__ == '__main__': 
    print make_final_result([ResObj() for x in xrange(10)]) 

は、Windows上にないことを確認してください。それにはforkがなく、マルチプロセッシングはデータセット全体を24のワーカープロセスにパイプする必要があります。
これが役に立ちます。

関連する問題