2016-04-10 39 views
-5

4623 satırlı bir metin dosyası ve 0 ve 1'ler (ör. 01010111) dizgileri biçiminde girişler var. Karakterleri karakterle karşılaştırıyorum. 100,1000 ve 10,000 karakter uzunluğunda birkaç veri kümem var. 10.000 için hesaplamak için 1000 ve 60 saat 25 saat sürer. Hızlandırmak için herhangi bir yolu var mı? Çok işlemcili kitaplığı kullanmayı denedim, ancak değerleri çoğaltır. Belki yanlış kullanıyorum. Kod:python yürütmeyi hızlandırma nasıl yapılır

f = open("/path/to/file/file.txt", 'r') 
l = [s.strip('\n') for s in f] 
f.close() 

for a in range(0, len(l)): 
    for b in range(0, len(l)): 
     if (a < b): 
      result = 0 
      if (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) 

Python'da yeniyim, bu yüzden bu kodun bazı optimizasyonlara ihtiyacı olduğunu düşünüyorum. Herhangi bir yardım iyi olacak. Şimdiden teşekkürler. Her iki dizeleri 1 olan sayma

+0

Kodunuzun düzgün bir şekilde girintili görünmemesi gibi görünüyor - düzeltebilir misiniz lütfen? – snakecharmerb

+0

Eğer bir

+0

Ayrıca bu kodun başarmaya çalıştığı şeyi açıkladıysanız yardımcı olabilir - örnek kodun hızlandırılması dışında başka optimizasyonlar da olabilir. – snakecharmerb

cevap

6

Temelleri

Yolunuz son derece yavaştır. İşte basit bir örnek:

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'in ve 0ın olarak sadece bit Dizelerinizi temsil eden bir konu kullanarak mukayese edelim: 2045 kat daha hızlı olduğunu

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 

. Öyleyse soru, python'u hızlandırmak değil, "hangi veri yapısını kullanmalıyım?" senin örneğin kodda olduğu gibi, bir ürünü kullanmadan

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 

veya: bitarray ve en kötü durum böyle değil 10,000 100 1'lerin hatları ve 0 en bir dosyayı, ancak kullanma

Büyük Ölçekli

:

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 

Not:

Eğer a < b olmadığını kontrol eğer
if a == b: 

önceki zira, True asla:

Sizin onu açmamış ve ölü kod içerdiğinden, sahip taşıma sonuçlar atlandı. Ben doğru anladım eğer

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) 

"Gerçek" Veri En kötü durumda ile

,: Sana girinti veya mantıksal hatalar var ve böyle bir şey anlamına geldiğini götürün

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 dilimlemeyi aldığımı ve atladığımı fark ettim. Çok olduğu çok yeni kopyalarını oluşturur gibi dilimleme yapacak olan etrafında bütün bu hafızayı taşımak için masraflı:

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 
Yani

önceden maksimum bit genişliği biliyorsanız, hatta verilerinden bunu hesaplamak Ben bütün "1'lerin saymak" do o zaman sıfırlarla kısa bitarrays ped için yararlı olacağını düşünüyorum ve:

İşte
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.txt, 1 've 0'ların 4623 karma uzunluğundan (100, 1000 veya 10000 rastgele seçim) oluşan dizelerden oluşmuştur.

+0

Yaptığınızdan (int (l [a] [i]) == int (l [b] [i]) == 1): 'kodunuzda, aslında her iki dizenin de içerdiği doğrudur '' 1 '' Ben onları char ile karşılaştır 'dediğiniz halde, 1'leri saymak istediğinizi sanıyorum. Bu bitarray için daha hızlı bir işlevi vardır, 'bitdiff'. Farklı uzunluktaki girişleri biraz daha farklı bir şekilde ele almayı gerektirecektir, fakat yine de mevcut cevapta olduğu gibi aynı balo parkında olacaktır. –

+0

Çok teşekkürler. Sorunumu anlamak gerçekten çok faydalı. – Masyaf

İlgili konular