2014-12-04 5 views
7

필자는 Python을 처음 접했을 때 fastq 파일에서 임의로 시퀀스의 하위 집합을 선택한다고 가정합니다 (아마도 매우 못생긴) 스크립트를 작성했습니다. fastq-file은 정보를 4 행씩 블록 단위로 저장합니다. 각 블록의 첫 번째 행은 문자 "@"로 시작합니다. 입력 파일로 사용하는 fastq 파일은 약 14,000,000 줄을 포함하는 36GB입니다.파이썬 스크립트를 더 빠르게 만들 수 있습니까?

너무 많은 메모리를 사용하는 기존 스크립트를 다시 작성하려고 시도했으며 메모리 사용량을 많이 줄였습니다. 그러나 스크립트는 영원히 돌아가며 왜 나타나는지를 보지 못합니다.

parser = argparse.ArgumentParser() 
parser.add_argument("infile", type = str, help = "The name of the fastq input file.", default = sys.stdin) 
parser.add_argument("outputfile", type = str, help = "Name of the output file.") 
parser.add_argument("-n", help="Number of sequences to sample", default=1) 
args = parser.parse_args() 


def sample(): 
    linesamples = [] 
    infile = open(args.infile, 'r') 
    outputfile = open(args.outputfile, 'w') 
    # count the number of fastq "chunks" in the input file: 
    seqs = subprocess.check_output(["grep", "-c", "@", str(args.infile)]) 
    # randomly select n fastq "chunks": 
    seqsamples = random.sample(xrange(0,int(seqs)), int(args.n)) 
    # make a list of the lines that are to be fetched from the fastq file: 
    for i in seqsamples: 
     linesamples.append(int(4*i+0)) 
     linesamples.append(int(4*i+1)) 
     linesamples.append(int(4*i+2)) 
     linesamples.append(int(4*i+3)) 
    # fetch lines from input file and write them to output file. 
    for i, line in enumerate(infile): 
     if i in linesamples: 
      outputfile.write(line) 

위한 grep 단계는 전혀 실제적으로 더 시간이 필요 없지만, 500 분, 스크립트는 여전히 출력 파일에 쓰기 시작되지 않았습니다. 그래서 grep과 마지막 for-loop 사이의 단계 중 하나라고 생각합니다. 하지만 정확히 어떤 단계인지 이해하지 못하고 속도를 높이기 위해 할 수있는 일이 있습니다.

+7

어떤 단계가 멈추는 지 확인하려면 [profiling] (https://docs.python.org/2/library/profile.html) 프로그램을 고려해야합니다.또한 작은 파일에서 코드를 실행 해 보았고 실행이 완료되었는지 확인 했습니까? 나중에 최적화 할 때 고려해야 할 또 하나의 단계는 스레딩과 다중 처리를 사용하여 작업을 분류하는 것입니다. –

+0

루프 내에서 항상'int'를 호출하지 마십시오. 또한,'with' 문을 사용하십시오. – Veedrac

답변

2

linesamples의 크기에 따라 infile을 통해 각 반복마다 목록을 검색하므로 if i in linesamples에 시간이 오래 걸릴 수 있습니다. 조회 시간을 단축하기 위해 이것을 set으로 변환 할 수 있습니다. 또한 enumerate은 그리 효율적이지 않습니다. 각 반복에서 증가하는 line_num 구조로 대체했습니다.

def sample(): 
    linesamples = set() 
    infile = open(args.infile, 'r') 
    outputfile = open(args.outputfile, 'w') 
    # count the number of fastq "chunks" in the input file: 
    seqs = subprocess.check_output(["grep", "-c", "@", str(args.infile)]) 
    # randomly select n fastq "chunks": 
    seqsamples = random.sample(xrange(0,int(seqs)), int(args.n)) 
    for i in seqsamples: 
     linesamples.add(int(4*i+0)) 
     linesamples.add(int(4*i+1)) 
     linesamples.add(int(4*i+2)) 
     linesamples.add(int(4*i+3)) 
    # make a list of the lines that are to be fetched from the fastq file: 
    # fetch lines from input file and write them to output file. 
    line_num = 0 
    for line in infile: 
     if line_num in linesamples: 
      outputfile.write(line) 
     line_num += 1 
    outputfile.close() 
+0

이 답변은 if linesamples에서 병목 현상을 정확히 식별한다고 생각합니다. 명시 적으로 파일 핸들을 닫는 것이 좋습니다. :) – cel

+0

@cel, agree - 코드를 업데이트했습니다. – vikramls

+3

'enumerate'는 효율적이지 않습니까? 그것을 증명할 수있는 벤치 마크가 있습니까? – Matthias

0

코드를 병렬 처리하십시오. 내말은 이것이야. 14,000,000 줄의 입력이 있습니다.

  1. 는 우리의 코드에서 작동, filteredInput001.txt 같은 파일의 10.000-100.000 라인에 filteredInput 분할 filteredInput002.txt 당신의 GREP을 작업하고 먼저 선을 필터링하고 filteredInput.txt
  2. 에 기록 이 분할 파일. 출력을 다른 파일 (예 : output001.txt, output002.txt)에 작성하십시오.
  3. 마지막 단계로 결과를 병합하십시오.

코드가 전혀 작동하지 않으므로. 이러한 필터링 된 입력에 코드를 실행할 수도 있습니다. 귀하의 코드는 filteredInput 파일의 존재를 확인하고 그가 어떤 단계에 있었는지 이해하고 그 단계에서 재개합니다.

쉘 또는 파이썬 스레드를 사용하여 (1 단계 후)이 방법으로 여러 파이썬 프로세스를 사용할 수도 있습니다.

+1

알고리즘을 최적화하기 전에 병렬화를 제안하는 것은 좋지 않습니다. 올바른 알고리즘으로 IO는 CPU가 아닌 병목이됩니다. – cel

+0

@cel 그의 코드는 지금도 작동하지 않지만 문제를 나누고 병렬 처리하는 것은 좋은 생각이 아닙니다. –

1

당신은 GREP이의 발생을 계산하는 경우에 대신 단지 그렙를 사용하므로 매우 빠르게 수행을 완료했다 @ 그렙 출력 그렙에 대한 -b 옵션을 사용하여이 보는 각 @ 문자 (의 바이트 오프셋을). 그런 다음 random.sample을 사용하여 원하는 블록을 선택하십시오. 원하는 바이트 오프셋을 선택했으면 infile.seek을 사용하여 각 바이트 오프셋으로 이동하여 거기에서 4 줄을 인쇄하십시오.

0

Reservoir Sampling 알고리즘을 사용할 수 있습니다. 이 알고리즘을 사용하면 데이터를 한 번만 읽을 수 있으므로 (미리 파일의 수를 계산할 필요가 없음) 스크립트를 통해 데이터를 파이프 할 수 있습니다. Wikipedia 페이지에 python 코드 예제가 있습니다.

Heng Li의 seqtk에서 fastq 샘플링을위한 C 구현도 있습니다.