【发布时间】:2017-05-26 11:36:42
【问题描述】:
我正在尝试解决 Rosalind 的基本问题,即计算给定序列中的核苷酸,并在列表中返回结果。对于那些不熟悉生物信息学的人来说,它只是计算字符串中 4 个不同字符('A'、'C'、'G'、'T')的出现次数。
我希望collections.Counter 是最快的方法(首先是因为他们声称具有高性能,其次是因为我看到很多人使用它来解决这个特定问题)。
但令我惊讶的是这种方法最慢!
我比较了三种不同的方法,使用timeit 并运行两种类型的实验:
- 长序列运行几次
- 多次运行短序列。
这是我的代码:
import timeit
from collections import Counter
# Method1: using count
def method1(seq):
return [seq.count('A'), seq.count('C'), seq.count('G'), seq.count('T')]
# method 2: using a loop
def method2(seq):
r = [0, 0, 0, 0]
for i in seq:
if i == 'A':
r[0] += 1
elif i == 'C':
r[1] += 1
elif i == 'G':
r[2] += 1
else:
r[3] += 1
return r
# method 3: using Collections.counter
def method3(seq):
counter = Counter(seq)
return [counter['A'], counter['C'], counter['G'], counter['T']]
if __name__ == '__main__':
# Long dummy sequence
long_seq = 'ACAGCATGCA' * 10000000
# Short dummy sequence
short_seq = 'ACAGCATGCA' * 1000
# Test 1: Running a long sequence once
print timeit.timeit("method1(long_seq)", setup='from __main__ import method1, long_seq', number=1)
print timeit.timeit("method2(long_seq)", setup='from __main__ import method2, long_seq', number=1)
print timeit.timeit("method3(long_seq)", setup='from __main__ import method3, long_seq', number=1)
# Test2: Running a short sequence lots of times
print timeit.timeit("method1(short_seq)", setup='from __main__ import method1, short_seq', number=10000)
print timeit.timeit("method2(short_seq)", setup='from __main__ import method2, short_seq', number=10000)
print timeit.timeit("method3(short_seq)", setup='from __main__ import method3, short_seq', number=10000)
结果:
Test1:
Method1: 0.224009990692
Method2: 13.7929501534
Method3: 18.9483819008
Test2:
Method1: 0.224207878113
Method2: 13.8520510197
Method3: 18.9861831665
对于这两个实验,方法 1 比方法 2 和 3快!
所以我有一组问题:
是我做错了什么还是确实比其他两种方法慢?有人可以运行相同的代码并分享结果吗?
如果我的结果是正确的,(也许这应该是另一个问题)有没有比使用方法 1 更快的方法来解决这个问题?
如果
count更快,那么collections.Counter是怎么回事?
【问题讨论】:
-
这确实很有趣。您可以稍微修改第一个方法而不计算最后一个(“T”),因为它们应该是序列的
len减去“A”、“C”和“G”。我也要运行它 -
测试1:{方法1:0.24,方法2:19.73,方法3:4.63}测试2:{方法1:0.26,方法2:19.35,方法3:4.30}。至少
counter比方法 2 更快,这是没有冒犯的错误代码。 -
没什么好奇怪的。方法 1 使用 C 代码,甚至是非常简单的 C 代码。而你只做了四次。难怪它要快得多。
-
考虑到您的最后一个问题,想象有 100 个核苷酸而不是 4 个。要对方法 1 进行编码,您必须将
sequence转换为set并为集合中的元素运行循环。它可能会开始变得越来越低效
标签: python performance collections counter bioinformatics