Преобразование кодировки ascii в int и обратно в python (быстро) - PullRequest
6 голосов
/ 27 сентября 2010

У меня есть формат файла (формат fastq), который кодирует строку целых чисел как строку, где каждое целое число представлено кодом ascii со смещением. К сожалению, обычно используются две кодировки: одна со смещением 33, а другая со смещением 64. У меня обычно есть несколько 100 миллионов строк длиной 80-150 для преобразования из одного смещения в другое. Простейший код, который я мог бы придумать для таких вещей:

def phred64ToStdqual(qualin):
    return(''.join([chr(ord(x)-31) for x in qualin]))

Это работает просто отлично, но не особенно быстро. На 1 миллион строк у меня уходит около 4 секунд. Если я перейду к использованию пары диктовок для перевода, я могу уменьшить это примерно до 2 секунд.

ctoi = {}
itoc = {}
for i in xrange(127):
    itoc[i]=chr(i)
    ctoi[chr(i)]=i

def phred64ToStdqual2(qualin):
    return(''.join([itoc[ctoi[x]-31] for x in qualin]))

Если я запускаю вслепую под Cython, я уменьшаю его до 1 секунды.
Похоже, что на уровне C, это просто приведение к int, вычитание, а затем приведение к char. Я не написал это, но я предполагаю, что это немного быстрее. Любые советы, в том числе о том, как лучше написать это на python или даже в версии на cython, были бы весьма полезны.

Спасибо

Sean

1 Ответ

4 голосов
/ 27 сентября 2010

Если вы посмотрите на код для urllib.quote, есть нечто похожее на то, что вы делаете.Это выглядит следующим образом:

_map = {}
def phred64ToStdqual2(qualin):
    if not _map:
        for i in range(31, 127):
            _map[chr(i)] = chr(i - 31)
    return ''.join(map(_map.__getitem__, qualin))

Обратите внимание, что вышеуказанная функция работает в случае, если сопоставления имеют разную длину (в urllib.quote вам нужно взять «%» -> «% 25».

Но на самом деле, поскольку каждый перевод имеет одинаковую длину, в Python есть функция, которая делает это очень быстро: maketrans и перевод . Вероятно, вы не получите намного быстреечем:

import string
_trans = None
def phred64ToStdqual4(qualin):
    global _trans
    if not _trans:
        _trans = string.maketrans(''.join(chr(i) for i in range(31, 127)), ''.join(chr(i) for i in range(127 - 31)))
    return qualin.translate(_trans)
...