2017-05-05 3 views
0

Ich habe genomische Daten von 16 Kernen. Die erste Spalte stellt den Nukleus dar, die nächsten zwei Spalten repräsentieren das Gerüst (Abschnitt des Genoms) bzw. die Position auf dem Gerüst, und die letzten zwei Spalten repräsentieren das Nukleotid bzw. die Abdeckung. Es kann gleiche Gerüste und Positionen in verschiedenen Kernen geben.Wie extrahiere ich schnell Daten aus dieser massiven CSV-Datei?

Mit Eingabe für Start- und Endpositionen (Gerüst und Position von jedem), soll ich eine CSV-Datei ausgeben, die die Daten (Nucleotid und Coverage) jedes Kerns innerhalb des Bereichs von Anfang bis Ende zeigt. Ich dachte daran, indem ich 16 Spalten (eine für jeden Kern) hatte und dann die Daten von oben nach unten zeigte. Die Region ganz links wäre ein Referenzgenom in diesem Bereich, auf das ich durch Erstellen eines Wörterbuchs für jedes ihrer Gerüste zugreifen konnte.

In meinem Code habe ich eine defaultdict von Listen, so der Schlüssel ist eine Zeichenfolge, die das Gerüst und die Position kombiniert, während die Daten ein Array von Listen ist, so dass für jeden Kern die Daten angehängt werden können der gleiche Ort, und am Ende hat jeder Ort Daten von jedem Kern.

Natürlich ist das sehr langsam. Wie sollte ich es stattdessen tun?

Code:

#let's plan this 
#input is start and finish - when you hit first, add it and keep going until you hit next or larger 
#dictionary of arrays 
#loop through everything, output data for each nucleus 

import csv 
from collections import defaultdict 

inrange = 0 
start = 'scaffold_41,51335' 
end = 'scaffold_41|51457' 
locations = defaultdict(list) 
count = 0 

genome = defaultdict(lambda : defaultdict(dict)) 
scaffold = '' 
for line in open('Allpaths_SL1_corrected.fasta','r'): 
    if line[0]=='>': 
     scaffold = line[1:].rstrip() 
    else: 
     genome[scaffold] = line.rstrip() 
print('Genome dictionary done.') 

with open('automated.csv','rt') as read: 
    for line in csv.reader(read,delimiter=','): 
     if line[1] + ',' + line[2] == start: 
      inrange = 1 
     if inrange == 1: 
      locations[line[1] + ',' + line[2]].append([line[3],line[4]]) 
     if line[1] + ',' + line[2] == end: 
      inrange = 0 
     count += 1 
     if count%1000000 == 0: 
      print('Checkpoint '+str(count)+'!') 

with open('region.csv','w') as fp: 
    wr = csv.writer(fp,delimiter=',',lineterminator='\n') 
    for key in locations: 
     nuclei = [] 
     for i in range(0,16): 
      try: 
       nuclei.append(locations[key][i]) 
      except IndexError: 
       nuclei.append(['','']) 
     wr.writerow([genome[key[0:key.index(',')][int(key[key.index(',')+1:])-1],key,nuclei]) 
print('Done!') 

Dateien: https://drive.google.com/file/d/0Bz7WGValdVR-bTdOcmdfRXpUYUE/view?usp=sharing https://drive.google.com/file/d/0Bz7WGValdVR-aFdVVUtTbnI2WHM/view?usp=sharing

+2

Hier ist ein Tipp: abstrahieren Sie Ihre Frage * weg von den Besonderheiten Ihres Problems *. Erstellen Sie ein Spielzeug-Dataset mit denselben Eigenschaften wie Ihr reales Dataset, das Benutzer schnell ausführen können. Je mehr Jargon Sie für Ihr Fachgebiet verwenden, desto weniger wahrscheinlich werden Sie Menschen dazu bringen, sich in Ihre Frage zu vertiefen. –

+2

Wahrscheinlich müssen Sie [pandas.read_csv] (http://pandas.pydata.org/pandas-docs/stable/generated/pandas.read_csv.html) oder [pandas.read_table] (http: //pandas.pydata .org/pandas-docs/stable/erzeugt/pandas.read_table.html). Nachdem Sie den Datensatz gelesen haben, gibt es viele Methoden, ihn in Pandas umzuwandeln. – Leonid

+0

Wenn Sie die gleiche Datei mehrmals filtern müssen, würde ich vorschlagen, eine zusätzliche Datei mit Anfängen und Enden für jedes Gerüst (Hash-Tabelle) zu erstellen und nur in Untertabellen zu suchen und sie in einen Speicher einzulesen. Das Erstellen einer Tabelle ist ein ziemlich langer Prozess, aber danach kann die Suche sehr schnell durchgeführt werden. – rth

Antwort

0

(Nur auf dem CSV-Abschnitt in der Mitte des Codes Fokussierung)

Das Beispiel CSV-Datei Sie ist über 2 GB geliefert und 77.822.354 Zeilen. Von diesen Linien scheinen Sie nur auf 26.804.253 Linien oder etwa 1/3 konzentriert zu sein.

Als allgemeine Vorschlag, können Sie etwas beschleunigen durch:

  1. Vermeiden Sie die Verarbeitung der Daten, die Sie nicht interessiert sind (2/3 der Datei);
  2. Beschleunigen Sie die Identifizierung der Daten, die Sie interessieren;
  3. Vermeiden Sie die Dinge, die sich Millionen von Malen wiederholen, die dazu neigen, langsamer zu sein (jede Zeile wird als CSV verarbeitet, eine Zeichenfolge wird neu zusammengesetzt usw.);
  4. Vermeiden Sie alle Daten zu lesen, wenn Sie es in Blöcke oder Linien brechen (Speicher wird eng wird)
  5. Verwenden schneller Tools wie numpy, pandas und pypy

Sie Daten, Block ausgerichtet ist, so dass Sie Verwenden Sie ein Objekt vom Typ FlipFlop, um zu erkennen, ob Sie sich in einem Block befinden oder nicht.

Die erste Spalte der CSV-numerisch ist, so anstatt die Linie auseinander Aufspalten und zwei Spalten Zusammenbauen, können Sie den schnellen Python in Operator den Beginn und das Ende der Blöcke zu finden:

start = ',scaffold_41,51335,' 
end = ',scaffold_41,51457,' 

class FlipFlop: 
    def __init__(self, start_pattern, end_pattern): 
     self.patterns = start_pattern, end_pattern 
     self.state = False 
    def __call__(self, st): 
     rtr=True if self.state else False 
     if self.patterns[self.state] in st: 
      self.state = not self.state 
     return self.state or rtr 

lines_in_block=0  
with open('automated.csv') as f: 
    ff=FlipFlop(start, end) 
    for lc, line in enumerate(f): 
     if ff(line): 
      lines_in_block+=1 

print lines_in_block, lc 

Prints:

Das läuft in etwa 9 Sekunden in PyPy und 46 Sekunden in Python 2.7.

Sie können dann den Teil nehmen, der die Quell-CSV-Datei liest und diese in einen Generator umwandelt, so dass Sie nur mit einem Datenblock gleichzeitig arbeiten müssen.

(sicher nicht richtig, da ich keine Zeit damit verbracht, Ihre Dateien insgesamt zu verstehen ..):

def csv_bloc(fn, start_pat, end_pat): 
    from itertools import ifilter 
    with open(fn) as csv_f: 
    ff=FlipFlop(start_pat, end_pat) 
    for block in ifilter(ff, csv_f): 
     yield block 

Oder, wenn Sie alle Blöcke in einem dict kombinieren müssen:

def csv_line(fn, start, end): 
    with open(fn) as csv_in: 
     ff=FlipFlop(start, end) 
     for line in csv_in: 
      if ff(line): 
       yield line.rstrip().split(",")    

di={}    
for row in csv_line('/tmp/automated.csv', start, end): 
    di.setdefault((row[2],row[3]), []).append([row[3],row[4]]) 

Das dauert in etwa 1 Minute auf meinem (alten) Mac in PyPy und etwa 3 Minuten in cPython 2.7.

Beste

Verwandte Themen