我有来自16个细胞核的基因组数据。第一列代表细胞核,接下来的两列分别代表支架(基因组的部分)和支架上的位置,最后两列分别代表核苷酸和覆盖。在不同的细胞核中可以有相同的支架和位置。
使用输入作为开始和结束位置(每个的支架和位置),我应该输出一个csv文件,该文件显示从开始到结束范围内每个核的数据(核苷酸和覆盖范围)。我想通过16列(每个核一个),然后从上到下显示数据来做到这一点。最左边的区域将是该范围内的参考基因组,我通过为每个支架创建字典来访问该区域。
在我的代码中,我有一个列表的默认值,因此键是一个组合了脚手架和位置的字符串,而数据是一个列表数组,因此对于每个核,数据可以附加到相同的位置,最后每个位置都有来自每个核心的数据。
当然,这很慢。我该怎么做呢?
代码:
#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!')
文件: https://drive.google.com/file/d/0Bz7WGValdVR-bTdOcmdfRXpUYUE/view?usp=sharing https://drive.google.com/file/d/0Bz7WGValdVR-aFdVVUtTbnI2WHM/view?usp=sharing
答案 0 :(得分:0)
(仅关注代码中间的CSV部分)
您提供的示例csv文件超过2GB和77,822,354行。在这些行中,您似乎只关注26,804,253行或约1/3。
作为一般性建议,您可以加快速度:
numpy
,pandas
和pypy
您的数据是面向块的,因此您可以使用FlipFlop
类型对象来感知您是否在某个块中。
你的csv的第一列是数字,所以你可以使用速度更快的Python in
运算符来查找块的开头和结尾,而不是将行分开并重新组合两列:
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
打印:
26804256 77822354
在PyPy中运行大约9秒,在Python 2.7中运行46秒。
然后,您可以获取读取源csv文件的部分并将其转换为生成器,这样您一次只需要处理一个数据块。
(当然不正确,因为我花了很长时间试图整体理解你的文件..):
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
或者,如果您需要将所有块组合成一个dict:
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]])
在PyPy中我的(旧)Mac上大约需要1分钟,在cPython 2.7中大约需要3分钟。
最佳