如何在Python中优化庞大列表的笛卡尔积代码
我才编程几个月,但我做了一些研究,尝试了这段代码。
我现在有两个文件。第一个文件里有大约300万个蛋白质ID(字符串)。第二个文件是每个蛋白质的编号列表,每个特征都有一个独特的编号:比如,如果蛋白质A有3个特征,它会显示为proteinA_1、proteinA_2、proteinA_3。有些蛋白质可能有多达3000个特征。
我想要一份特征交互对的列表。
到目前为止我的代码是这样的:
import csv,itertools, gzip
from collections import Counter
#opens and reads/writes files using csv and gzip
#1. Counts how many features each protein has in the second file.
cnt = Counter()
for row in cfile1:
cnt[row[0]]+=1
#2. Considers pairs of interacting proteins
for row in cfile2:
p1 = row[0]; p2=row[1]
#3.1. if both proteins have no features, just write the pair to the new file
if cnt[p1]==0 and cnt[p2]==0:
cout.writerow([p1,p2])
#3.2. if one protein has no feature, but the other has a feature write e.g. (p1_1,p2) (p1_2,p2) (p1_3,p2)... (p1_k,p2)
elif cnt[p1]!=0 and cnt[p2]==0:
x = cnt[p1]
for i in range(1,x+1):
p1n=p1+"_%d"%(i)
cout.writerow([p1n,p2])
elif cnt[p1]==0 and cnt[p2]!=0:
x = cnt[p2]
for i in range(1,x+1):
p2n=p2+"_%d"%(i)
cout.writerow([p1,p2n])
#3.3 if both proteins have features, create a list of the enumerated proteins then get the cartesian product of that list, so that you get all possible f-f interactions
elif (cnt[p1]!=0) and (cnt[p2]!=0):
x = cnt[p1];y = cnt[p2]
xprots = []; yprots=[]
for i in range(1,x+1):
p1n =p1+"_%d"%(i)
xprots.append(p1n)
for i in range(1,y+1):
p2n=p2+"_%d"%(i)
yprots.append(p2n)
for i in itertools.product(xprots,yprots):
cout.writerow([i[0],i[1]])
这段代码似乎运行得不错,但处理前15万个对花了大约18个小时。目前输出文件里几乎有20亿个交互。
有没有其他方法可以加快这个速度,除了可能减少一些特征?任何建议都非常感谢!
提前谢谢你们!
2 个回答
我觉得在Python代码优化方面的空间不大。可以建议你尝试用C或C++写一个扩展,这样可以大幅提升计算性能。
编写Python扩展的过程有很多文档说明,实际上对于需要大量计算的应用效果很好。
关于这个问题的文档网站是: https://docs.python.org/2/extending/
希望对你有帮助!
听起来你遇到的问题是因为你正在做的事情本身就很复杂,即使是最快、最优化的低级C程序也需要花费非常长的时间。
处理前150000对数据大约花了18个小时。目前输出文件中几乎有20亿个交互。
我们来看看这些数字。你说有300万个蛋白质对,每个蛋白质最多可以有3000个特征。那么输出的总行数大约是(300万)*(3000的平方),也就是270万亿行。看起来每行至少会包含10个字符(字节),所以我们在说的输出大约是270太字节。
我怀疑你的硬盘连存下这么大的文件都不够。你需要重新考虑一下你要做的事情;即使你的代码提升了1000倍,输出的大小也不会改变,而你的程序速度也不能快于它所产生的数据量。如果你真的需要这么多输出,可能更适合用超级计算机或集群进行并行计算,这样会需要根据架构进行专业的编程。