2016-04-10 13 views
-5

私は、4623行と0と1の文字列形式のエントリを持つテキストファイルを持っています(例えば01010111)。私はそれらを文字で比較しています。私は文字列の長さが100,1000と10,000のデータセットをいくつか持っています。 10,000を計算するためには1000時間には25時間かかり、60時間には60時間かかります。それをスピードアップする方法はありますか?私はマルチプロセッシングライブラリを使用しようとしましたが、値を複製するだけです。たぶん私はそれを間違って使用しています。コード:Pythonの実行をスピードアップする方法

私はこのコードにいくつかの最適化が必要だと思います。どんな助けも良いでしょう。前もって感謝します。

+0

コードが正しくインデントされていないように見えますが、修正できますか? – snakecharmerb

+0

'if a

+0

また、このコードが達成しようとしていることを説明した場合に役立ちます。サンプルコードをスピードアップするだけでは、他の最適化が可能かもしれません。 – snakecharmerb

答えて

6

基本事項

両方の文字列が1の場合のカウント方法は非常に遅いです。ここでは簡単な例を示します。

In [24]: a = '1010' * 2500 

In [25]: b = '1100' * 2500 

In [27]: def test1(): 
    counter = 0    
    for i in range(len(a)): 
     if int(a[i]) == int(b[i]) == 1: 
      counter += 1 
    return counter 

In [28]: %timeit test1() 
100 loops, best of 3: 4.07 ms per loop 

は、1と0のと同じくらいのビットのあなたの文字列を表して何かを使用することの比較:2045倍高速である

In [29]: aba = bitarray(a) 

In [30]: bba = bitarray(b) 

In [31]: def test2(): 
    ....:  return (aba & bba).count() 
    ....: 

In [32]: %timeit test2() 

100000 loops, best of 3: 1.99 µs per loop 

。だから問題は、Pythonをスピードアップする方法ではなく、 "私はどのようなデータ構造を使うべきか"ということです。

In [22]: from bitarray import bitarray 

In [23]: testdata = open('teststrs.txt') 

In [24]: l = [bitarray(line.rstrip()) for line in testdata] 

In [25]: len(l) 
Out[25]: 10000 

In [26]: len(l[0]) 
Out[26]: 100 

In [27]: combs = combinations(l, 2) 

In [28]: %time res = [(a & b[:len(a)]).count() for a, b in combs] 
CPU times: user 1min 14s, sys: 396 ms, total: 1min 15s 
Wall time: 1min 15s 

か、あなたの例のコードのように、製品を使用して:bitarrayとあなたの最悪のケースではありません100の1の10,000行と0のファイル、ただしを使用して

大規模

In [30]: from itertools import product 

In [31]: prod = product(l, repeat=2) 

In [32]: %time res = [(a & b[:len(a)]).count() for a, b in prod] 
CPU times: user 2min 51s, sys: 628 ms, total: 2min 52s 
Wall time: 2min 51s 

注:

あなたがそれを開いていないと、それはデッドコードが含まれているので、私は、あなたが持って取り扱い、結果をスキップ:直前にあなたがそのa < bを確認した場合ので、

if a == b: 

は、Trueになることはありません。私はそれを正しく理解している場合、あなたの最悪のケースでは、データ

「実」

if a < b: 
     result = 0 
    elif a == b: 
     result = 1 
    else: 
     counter = 0 
     for i in range(len(l[a])): 
      if (int(l[a][i]) == int(l[b][i]) == 1): 
       counter += 1 
     result = counter/10000 
    print((a + 1), (b + 1), result) 

In [1]: src = map(lambda i: '{:010000b}\n'.format(i), iter(lambda: random.getrandbits(10000), None)) 

In [2]: import random 

In [3]: from itertools import islice 

In [4]: with open('teststrs.txt', 'w') as datafile: 
    datafile.writelines(islice(src, 0, 4623)) 

... 

In [35]: testdata = open('teststrs.txt') 

In [36]: l = [bitarray(line.rstrip()) for line in testdata] 

In [37]: prod = product(l, repeat=2) 

In [38]: %time res = [(a & b).count() for a, b in prod] 
CPU times: user 52.1 s, sys: 424 ms, total: 52.5 s 
Wall time: 52.5 s 

In [39]: len(l) 
Out[39]: 4623 

In [40]: len(l[0]) 
Out[40]: 10000 

を私はあなたがインデントや論理エラーを持っていること、それを取ると、のようなものを意味し私は浮気してスライスをスキップしたことに注目してくださいb。あなたの最大ビット幅が事前にわかっているのであれば

In [43]: %time res = [(a & b[:len(a)]).count() for a, b in prod] 
CPU times: user 29min 40s, sys: 676 ms, total: 29min 41s 
Wall time: 29min 40s 

を、あるいはあなたのデータからそれを計算します。新しいコピーを作成して、スライスが行うであろう、周りのすべてのそのメモリを移動するために非常に非常にコストがかかります

In [18]: def test():      
    with open('teststrs.txt') as testdata: 
     lines = [line.strip() for line in testdata] 
    max_len = max(map(len, lines)) 
    l = [bitarray(line.ljust(max_len, '0')) for line in lines] 
    prod = product(l, repeat=2) 
    return [(a & b).count() for a, b in prod] 
    ....: 

In [19]: %timeit test() 
1 loops, best of 3: 43.9 s per loop 

ここteststrsを:、私はそれがゼロで短いbitarraysパッドに有益であろうし、その後全体が「1のカウント」んだと思います。txtは、1と0の4623の混合長(ランダム選択100,1000または10000)の文字列で構成されていました。

+0

あなたのコードで 'if(int [l] [i])== int(l [b] [i])== 1):'を実行するので、実際にはどちらの文字列も ''1 ''、私はあなたが本当に1を数えたいと思っていると思いますが、あなたはあなたが "charとcharを比較する"と言っています。そのため、ビット配列はさらに高速な関数 'bitdiff'を持っています。これは、異なる長さの入力を少し違って扱う必要がありますが、それでも現在の答えと同じボールパークにいます。 –

+0

ありがとうございました。私の問題を理解するのに本当に役立ちます。 – Masyaf

関連する問題