2016-09-22 8 views
1

私はアイテムのリストは以下のrowsに表示する頻度を数える機能があります、実際には関数内の並列性は?

def count(pair_list): 
    return float(sum([1 for row in rows if all(item in row.split() for item in pair_list)])) 

if __name__ == "__main__": 
    pairs = [['apple', 'banana'], ['cookie', 'popsicle'], ['candy', 'cookie'], ...] 
    # grocery transaction data 
    rows = ['apple cookie banana popsicle wafer', 'almond milk eggs butter bread', 'bread almonds apple', 'cookie candy popsicle pop', ...] 

    res = [count(pair) for pair in pairs] 

len(rows)10000あると18000pairsの要素なので、count()でリスト内包のコンピューティング・コストがあります主な機能のものは高価です。どちらか、これはすぐに実行されません

from multiprocessing.dummy import Pool as ThreadPool 
import multiprocessing as mp 

threadpool = ThreadPool(processes = mp.cpu_count()) 

res = threadpool.map(count, pairs) 

は、私はいくつかの並列処理を試してみました。実際には、15分後に、私は仕事が終了するように見えなかったので、仕事をやめました。 2つの質問:1)どのように私は実際には、 count()で行われる検索をスピードアップできますか? 2) threadpool.mapプロセスのステータスを確認するにはどうすればよいですか(繰り返し処理するペア数は確認できます)

+1

大きな「行」を共有しています。 chunkksize = 100を 'map'に渡してみてください。 – khachik

+1

とあなたの質問については、進歩 - 使用するimap。 – khachik

+0

本当の問題は 'count()'のリストの理解でなければならないと思います。これはボトルネックにはならないでしょう、ここでは 'pairs(p)'を得るために 'pairs 'のすべてのpを繰り返します。 – blacksite

答えて

1

1)計算の全体的な複雑さは巨大であり、それは異なるソースから来ている:

A)あなたは、計算のローレベルで行を分割するので、Pythonはすべての反復のための新しい行分割を作成する必要があります。これを避けるには、行を事前に計算することができます。この(「カウント」機能の小さな変化で)仕事をするような何か:

rows2 = [row.split() for row in rows] 

b)は、あなたが唯一の別のリストに単語が存在することを確認する必要があるにもかかわらず、リスト項目を一つずつ比較します。ここでは、より多くのそれを微調整(および「カウント」機能に代わりrows2のrows3を使用)することができます

rows3 = [set(row.split()) for row in rows] 

def count(pair_list): 
    return float(sum([1 for row in rows3 if all(item in row for item in pair_list)])) 

C)あなたは、行のすべての単語とのペアですべての単語を確認してください。計算では、元のバージョンの「カウント」関数の呼び出しごとに2 * len(行)* len(行)反復が必要ですが、それよりも少なくて済みます。オプションb)の場合は2 * len(行)にすることができますが、2つではなく、1組につき1セットの検索を行うことができます。 トリックはすべての行のすべての単語*単語の組み合わせを準備することですこのセットに対応するタプルが存在するかどうかを確認します。 だから、主な機能には、複雑な不変の検索構造を作成します。

rows4 = [set((a, b) for a in row for b in row) for row in rows2] 

そして今異なって見えるだろう「カウント」、それはリストの代わりにタプル取ります

def count2(pair): 
    return float(len([1 for row in rows4 if(pair in row)])) 

だからあなたは少し違う、それを呼び出します: res = [count2(タプル(ペア)ペアのペア)]

検索構造体の作成には時間と空間の行ごとにlen(row.split())^ 2が必要であることに注意してください。長く、最適ではありません。結局のところ、オプションb)はより良いことがあります。

2) "カウント"の呼び出し回数を予測できます - それはlen(ペア)です。 "count"関数の呼び出しをカウントし、例えば1000回の呼び出しごとにその中にデバッグプリントを作成します。

+0

これは役に立ちます。スクリプト全体が今すぐ飛ぶ! – blacksite