2014-02-07 70 views
1

我有一個特殊格式的二進制文件,對here有興趣。格式不是重要的東西。我可以將這些數據讀取並轉換爲我想要的形式,但問題是這些二進制文件往往會在其中包含大量信息。如果我只是按照讀取的方式返回字節,這很快(不到1秒),但我無法對這些字節做任何有用的事情,它們需要首先轉換爲基因型,那是似乎是代碼放慢速度。二進制數據緩慢轉換

一系列字節到基因型的換算如下

 h = ['%02x' % ord(b) for b in currBytes] 
     b = ''.join([bin(int(i, 16))[2:].zfill(8)[::-1] for i in h])[:nBits] 
     genotypes = [b[i:i+2] for i in range(0, len(b), 2)] 
     map = {'00': 0, '01': 1, '11': 2, '10': None} 
     return [map[i] for i in genotypes] 

我所希望的是,有一個更快的方法來做到這一點?有任何想法嗎?以下是運行python -m cProfile test.py的結果,其中test.py正在調用我寫入的讀取器對象來讀取這些文件。

vlan1711:src davykavanagh$ python -m cProfile test.py 
183, 593483, 108607389, 366, 368, 46 
that took 93.6410450935 
     86649088 function calls in 96.396 seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 1.248 1.248 2.753 2.753 plinkReader.py:13(__init__) 
     1 0.000 0.000 0.000 0.000 plinkReader.py:47(plinkReader) 
     1 0.000 0.000 0.000 0.000 plinkReader.py:48(__init__) 
     1 0.000 0.000 0.000 0.000 plinkReader.py:5(<module>) 
     1 0.000 0.000 0.000 0.000 plinkReader.py:55(__iter__) 
    593484 77.634 0.000 91.477 0.000 plinkReader.py:58(next) 
     1 0.000 0.000 0.000 0.000 plinkReader.py:71(SNP) 
    593483 1.123 0.000 1.504 0.000 plinkReader.py:75(__init__) 
     1 0.000 0.000 0.000 0.000 plinkReader.py:8(plinkFiles) 
     1 0.000 0.000 0.000 0.000 plinkReader.py:85(Person) 
     183 0.000 0.000 0.001 0.000 plinkReader.py:89(__init__) 
     1 2.166 2.166 96.396 96.396 test.py:5(<module>) 
27300218 5.909 0.000 5.909 0.000 {bin} 
    593483 0.080 0.000 0.080 0.000 {len} 
     1 0.000 0.000 0.000 0.000 {math.ceil} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
     2 0.000 0.000 0.000 0.000 {method 'format' of 'str' objects} 
    593483 0.531 0.000 0.531 0.000 {method 'join' of 'str' objects} 
    593485 0.588 0.000 0.588 0.000 {method 'read' of 'file' objects} 
    593666 0.257 0.000 0.257 0.000 {method 'rsplit' of 'str' objects} 
    593666 0.125 0.000 0.125 0.000 {method 'rstrip' of 'str' objects} 
27300218 4.098 0.000 4.098 0.000 {method 'zfill' of 'str' objects} 
     3 0.000 0.000 0.000 0.000 {open} 
27300218 1.820 0.000 1.820 0.000 {ord} 
    593483 0.817 0.000 0.817 0.000 {range} 
     2 0.000 0.000 0.000 0.000 {time.time} 

回答

1

通過創建不需要的列表和大字符串,可以減慢速度。您只是檢查一些字節並將兩位組轉換爲數字。這可以實現得更簡單,例如。 G。這段代碼:

def convert(currBytes, nBits): 
    for byte in currBytes: 
    for p in range(4): 
     bits = (ord(byte) >> (p*2)) & 3 
     yield None if bits == 1 else 1 if bits == 2 else 2 if bits == 3 else 0 
     nBits -= 2 
     if nBits <= 0: 
     raise StopIteration() 

如果你真的需要一個list到底,只是用

list(convert(currBytes, nBits)) 

但我想可能有情況下,您只是想遍歷結果:

for blurp in convert(currBytes, nBits): 
    # handle your blurp (0, 1, 2, or None) 
+0

很酷。是的,nBits是醜陋的。它來自事實上我們事先知道有多少對比特是預期的(所以是,nBits總是2的倍數),如果這個數字不是8的倍數,那麼最後一個字節用額外的零填充。 –

+1

我正在進一步精簡版本,它根本不涉及字符串轉換。畢竟你只是使用位。這可以做得更好。不掛斷。 – Alfe

+1

好的,看看我的新答案。它比舊的更好。我想這會根據輸入的大小顯着加快你的速度。在最壞的情況下,我得到了像加速因子100。 – Alfe