Conversione ASCII encoding a int e viceversa in python (rapidamente)
-
25-09-2019 - |
Domanda
Ho un formato di file (formato FASTQ) che codifica una stringa di numeri interi come una stringa in cui ogni numero intero è rappresentato da un codice ASCII con un offset. Purtroppo, ci sono due codifiche di uso comune, uno con un offset di 33 e l'altro con un offset di 64. Io in genere hanno diversi 100 milioni di stringhe di lunghezza 80-150 per convertire da una compensazione all'altro. Il codice più semplice che ho potuto venire con per fare questo tipo di cose è:
def phred64ToStdqual(qualin):
return(''.join([chr(ord(x)-31) for x in qualin]))
Questo funziona bene, ma non è particolarmente veloce. Per 1 milione di corde, ci vogliono circa 4 secondi sulla mia macchina. Se cambio di utilizzare un paio di dicts a fare la traduzione, posso ottenere questo fino a circa 2 secondi.
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]))
Se io alla cieca corro sotto Cython, ho capito fino a poco meno di 1 secondo.
Sembra che a livello di C, questo è semplicemente un cast a int, sottrarre, e poi gettato a char. Non ho scritto questo, ma sto cercando di indovinare che è un po 'più veloce. Eventuali suggerimenti tra cui come codice migliore di questo in Python o anche una versione Cython per fare questo sarebbe molto utile.
Grazie,
Sean
Soluzione
Se si guarda il codice per urllib.quote, c'è qualcosa che è simile a quello che stai facendo. Sembra che:
_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))
Si noti che la funzione di cui sopra funziona nel caso in cui le mappature non sono la stessa lunghezza (in urllib.quote, si deve prendere '%' -.> '% 25'
Ma in realtà, dal momento che ogni traduzione è la stessa lunghezza, Python ha una funzione che fa proprio questo molto rapidamente: maketrans e tradurre . Probabilmente non sarà possibile ottenere molto più veloce di:
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)