3

私は非常に大きなtxt入力ファイルを処理する必要があり、通常は.readlines()を使用して最初にファイル全体を読み取り、それをリストに変換します。

私はそれが本当にメモリコストであり、かなり遅くなる可能性があることを知っていますが、以下のように特定の行を操作するためにLIST特性を利用する必要もあります。

#!/usr/bin/python

import os,sys
import glob
import commands
import gzip

path= '/home/xxx/scratch/'
fastqfiles1=glob.glob(path+'*_1.recal.fastq.gz')

for fastqfile1 in fastqfiles1:
    filename = os.path.basename(fastqfile1)
    job_id = filename.split('_')[0]
    fastqfile2 = os.path.join(path+job_id+'_2.recal.fastq.gz') 

    newfastq1 = os.path.join(path+job_id+'_1.fastq.gz') 
    newfastq2 = os.path.join(path+job_id+'_2.fastq.gz') 

    l1= gzip.open(fastqfile1,'r').readlines()
    l2= gzip.open(fastqfile2,'r').readlines()
    f1=[]
    f2=[]
    for i in range(0,len(l1)):
        if i % 4 == 3:
           b1=[ord(x) for x in l1[i]]
           ave1=sum(b1)/float(len(l1[i]))
           b2=[ord(x) for x in str(l2[i])]
           ave2=sum(b2)/float(len(l2[i]))
           if (ave1 >= 20 and ave2>= 20):
              f1.append(l1[i-3])
              f1.append(l1[i-2])
              f1.append(l1[i-1])
              f1.append(l1[i])
              f2.append(l2[i-3])
              f2.append(l2[i-2])
              f2.append(l2[i-1])
              f2.append(l2[i])
    output1=gzip.open(newfastq1,'w')
    output1.writelines(f1)
    output1.close()
    output2=gzip.open(newfastq2,'w')
    output2.writelines(f2)
    output2.close()

一般的には全文の4行ごとに読み込もうとしていますが、4行目が希望の条件を満たしている場合は、この4行をテキストに追加します。それで、これを達成するためにreadlines()を避けることができますか?どうも

編集:こんにちは、実際に私自身がより良い方法を見つけました:

import commands
 l1=commands.getoutput('zcat ' + fastqfile1).splitlines(True)
 l2=commands.getoutput('zcat ' + fastqfile2).splitlines(True)

'zcat'は超高速だと思います....readlineに約15分かかりましたが、zcatだけに1分しかかかりませんでした...

4

6 に答える 6

6

コードをリファクタリングしてファイルを直線的に読み取ることができる場合はfor line in file、ファイルを一度にすべてメモリに読み込むことなく、ファイルの各行を反復処理するように言うことができます。ただし、ファイルアクセスはより複雑に見えるため、ジェネレータを使用してを置き換えることができますreadlines()。これを行う1つの方法は、itertools.izipまたはを使用することitertools.izip_longestです。

def four_at_a_time(iterable):
    """Returns an iterator that returns a 4-tuple of objects at a time from the
       given iterable"""
    args = [iter(iterable) * 4]
    return itertools.izip(*args)
...
l1 = four_at_a_time(gzip.open(fastqfile1, 'r'))
l2 = four_at_a_time(gzip.open(fastqfile2, 'r'))
for i, x in enumerate(itertools.izip(l1, l2))
    # x is now a 2-tuple of 4-tuples of lines (one 4-tuple of lines from the first file,
    # and one 4-tuple of lines from the second file).  Process accordingly.
于 2011-08-24T16:08:22.407 に答える
2

簡単な方法は、

(擬似コード、説明のみを目的として、エラーが含まれる場合があります)

    a=gzip.open()
    b=gzip.open()

    last_four_a_lines=[]
    last_four_b_lines=[]

    idx=0

    new_a=[]
    new_b=[]

    while True:
      la=a.readline()
      lb=b.readline()
      if (not la) or (not lb):
        break

      if idx % 4==3:
        a_calc=sum([ something ])/len(la)
        b_calc=sum([ something ])/len(lb)
        if a_calc and b_calc:
          for line in last_four_a_lines:
          new_a.append(line)
          for line in last_four_b_lines:
          new_b.append(line)

      last_four_a_lines.append(la)
      del(last_four_a_lines[0])
      last_four_b_lines.append(lb)
      del(last_four_b_lines[0])
      idx+=1
a.close()
b.close()
于 2011-08-24T16:26:47.710 に答える
1

ファイル内の行を反復処理するために使用できenumerateます。これにより、反復ごとにカウントと行が返されます。

with open(file_name) as f:
    for i, line in enumerate(f):
        if i % 4 == 3:
            print i, line
于 2011-08-24T16:05:36.933 に答える
1

foo前の3行を含むすべての行を印刷する方法は次のとおりです。

f = open(...)
prevlines = []
for line in f:
  prevlines.append(line)
  del prevlines[:-4]
  if 'foo' in line:
    print prevlines

一度に2つのファイルを(同じ行数で)読み取る場合は、次のようにします。

f1 = open(...)
f2 = open(...)
prevlines1 = []
for line1 in f1:
  prevlines1.append(line1)
  del prevlines1[:-4]
  line2 = f2.readline()
  prevlines2.append(line2)
  del prevlines2[:-4]
  if 'foo' in line1 and 'bar' in line2:
    print prevlines1, prevlines2
于 2011-08-24T16:16:31.260 に答える
0

l1とl2の取得を改善するだけでは不十分だと思います。コードをグローバルに改善する必要があります。

私が提案する:

#!/usr/bin/python

import os
import sys
import gzip

path= '/home/xxx/scratch/'

def gen(gfa,gfb):
    try:
        a = (gfa.readline(),gfa.readline(),gfa.readline(),gfa.readline())
        b = (gfb.readline(),gfb.readline(),gfb.readline(),gfb.readline())
        if sum(imap(ord,a[3]))/float(len(a[3])) >= 20 \
           and sum(imap(ord,b[3]))/float(len(b[3])) >= 20:
            yield (a,b)
    except:
        break

for fastqfile1 in glob.glob(path + '*_1.recal.fastq.gz') :
    pji = path + os.path.basename(fastqfile1).split('_')[0] # pji = path + job_id

    gf1= gzip.open(fastqfile1,'r')
    gf2= gzip.open(os.path.join(pji + '_2.recal.fastq.gz'),'r')

    output1=gzip.open(os.path.join(pji + '_1.fastq.gz'),'w')
    output2=gzip.open(os.path.join(pji + '_2.fastq.gz'),'w')

    for lines1,lines2 in gen(gf1,gf2):
        output1.writelines(lines1)
        output2.writelines(lines2)

    output1.close()
    output2.close()

実行時間が30%短縮されるはずです。純粋な推測。

PS:

コード

if sum(imap(ord,a[3]))/float(len(a[3])) >= 20 \
   and sum(imap(ord,b[3]))/float(len(b[3])) >= 20:

ではなく、より迅速に実行されます

ave1 = sum(imap(ord,a[3]))/float(len(a[3])) 
ave2 = sum(imap(ord,b[3]))/float(len(b[3]))
if ave1 >= 20 and ave2 >=20: 

ave1が20より大きくない場合、オブジェクトave2は評価されないためです。

于 2011-08-24T22:16:26.430 に答える
0

実際には2つのファイルを同時に処理しているため、注意が必要です。

fileinputモジュールを使用して、一度に1行ずつファイルを効率的に解析できます。これを使用してファイルのリストを解析することもできます。また、ブロック内のfileinput.nextfile()メソッドを使用して、複数のファイルを並行して交互に実行し、各ファイルから一度に1行を消費することができます。

fileinput.lineno()メソッドは、現在のファイルの現在の行番号も提供します。ループ本体で一時リストを使用して、4行のブロックを追跡できます。

完全にテストされていないアドホックコードは、おそらくコードの機能の誤解に基づいて、次のようになります。

f1 = []
f2 = []
for line in fileinput(filename1, filename2):
    if fileinput.filename() = filename1:
        f1.append(line)
    else:
        f2.append(line)
        if fileinput.lineno() % 4 == 3:
            doMyProcesing()
            f1 = []; f2 = []
    fileinput.nextfile()
于 2011-08-24T16:06:33.523 に答える