我有一个脚本需要花费很多时间,并且在2天后无法完成... 我将1个文件解析为2个字典,如下所示:
gfftree = {'chr1':[(gene_id, gstart, gend),...], 'chr2':[(gene_id, gstart, gend),...],...}
TElocation = {'chr1':[(TE_id, TEstart, TEend),...], 'chr2':[(TE_id, TEstart, TEend),...],...}
- 目的是找到其TEstart或TEend或两者位于gene_id'之间的TE_id。每个chr(键)中的gstart和gend。
这是我的代码:
TE_in_TSS = []
for TErange in TElocation[chromosome]:
TE_id, TEstart, TEend = TErange
for item in gfftree[chromosome]:
gene, gstart, gend = item
if len(list(set(range(int(gstart),int(gend)+1)) & set(range(int(TEstart),int(TEend)+1)))) > 0:
TE_in_TSS.append((gene, TE_id, TEstart, TEend))
else:
pass
到目前为止,我确定这个循环对于小数据很好,但是当涉及到800,000 TE_id和4,000 gene_id等更大的循环时,需要时间......而且我不知道它是否可以光洁度...
答案 0 :(得分:3)
OP方法是O(n*m)
,其中n
是基因数,m
是TE数。这种方法不是像OP中那样针对每个TE测试每个基因,而是利用基因和TE的有序性质以及指定的匹配规则,仅查看每个基因和TE一次,除了描述的基因预测在3.
下面。这种方法是O(n + m)
,前提是平均基因前瞻相对于n
较小。访问每个基因和TE的顺序描述如下:
def get_TE_in_TSS(genes, TEs):
TE_in_TSS = []
gene_pos, TE_pos = 0, 0
gene_count, TE_count = len(genes), len(TEs)
while gene_pos < gene_count:
while (TE_pos < TE_count) and (TEs[TE_pos][1] <= genes[gene_pos][2]):
match_gene_pos = gene_pos
while (match_gene_pos < gene_count) and (TEs[TE_pos][2] >= genes[match_gene_pos][1]):
TE_in_TSS.append((genes[match_gene_pos][0], TEs[TE_pos][0],
TEs[TE_pos][1], TEs[TE_pos][2]))
match_gene_pos += 1 # look ahead to see if this TE matches the next gene
TE_pos += 1
gene_pos += 1
return TE_in_TSS
OP报告性能:
1 second (compared to 2 days + for OP code) for 801,948 TEs, 6,007 genes
测试数据:
genes = (('HTR3A', 7, 9), ('ADAMTSL4', 10,100), ('THSD4',2000, 2800), ('PAPLN', 2850, 3000))
TEs = (('a', 10, 11), ('b', 13, 17), ('c', 50, 2500), ('d', 2550, 2700),
('e', 2800, 2900), ('f', 9999, 9999))
TE_in_TSS = get_TE_in_TSS(genes, TEs)
print(TE_in_TSS)
输出:
[('ADAMTSL4', 'a', 10, 11), ('ADAMTSL4', 'b', 13, 17), ('ADAMTSL4', 'c', 50, 2500),
('THSD4', 'c', 50, 2500), ('THSD4', 'd', 2550, 2700), ('THSD4', 'e', 2800, 2900),
('PAPLN', 'e', 2800, 2900)]
请注意,此帖子的前9条评论指的是更为有效的O(n * m)
方法,该方法因澄清规范而过时。
答案 1 :(得分:1)
这是一个使用多线程的解决方案,比较用于嵌套循环方法的代码。
我创建了两个csv,一个有8k行,一个800行(int,float1,float2)随机生成的数字,导入如下:
import time
import itertools
start = time.time()
def f((TE_id, TEstart, TEend)):
a=[]
for gene, gstart, gend in gfftree['chr1']:
if (gstart <= TEstart <=gend) or (gstart<=TEend <=gend):
a.append((gene,TE_id,TEstart,TEend))
return a
'''
#slow
TEinTSS = []
for TE_id, TEstart, TEend in TElocation['chr1']:
for gene, gstart, gend in gfftree['chr1']:
if (gstart <= TEstart <=gend) or (gstart<=TEend <=gend):
TEinTSS.append((gene,TE_id,TEstart,TEend))
print len(TEinTSS)
print time.time()-start
#faster
TEinTSS = []
for things in TElocation['chr1']:
TEinTSS.extend(f(things))
print len(TEinTSS)
print time.time()-start
'''
#fastest (especially with multi-core, multithreading)
from multiprocessing import Pool
if __name__ == '__main__':
p=Pool()
TEinTSS = list(itertools.chain.from_iterable(p.imap_unordered(f, b)))
print len(TEinTSS)
print time.time() - start
答案 2 :(得分:1)
如果该过程的目的纯粹是为了找到落在特定起始范围内的基因ID而且您并不太担心如何实现这一目标,而只是寻找最快的解决方案,那么你可能想要考虑完全放弃循环的概念并查看预先存在的解决方案机制。
假设您的数据是CSV格式,以下内容符合您的要求,返回包含ID,基因名称和相关chromasones的数据框,按chromasone分组。
文件:genometest.py
import pandas as pd
columns = ['id', 'chromasone', 'start', 'end', 'gene_name']
te_locations = pd.read_csv('Sequences/te.bed', delimiter='\t', header=None, names=columns)
gene_locations = pd.read_csv('Sequences/gene.bed', delimiter='\t', header=None, names=columns)
dataframe = pd.merge(te_locations, gene_locations, on=['gene_name', 'chromasone'], how='outer', suffixes=('_te', '_ge'))
dataset = dataframe.query('start_te >= start_ge & start_te <= end_ge')[['peak_id_te', 'gene_name', 'chromasone']]
dataset.groupby('chromasone')
输入尺寸
输出尺寸
<强>性能强>
$ python3 -m timeit 'import genometest'
10 loops, best of 3: 0.391 usec per loop