Я пытаюсь решить основную задачу Rosalind о подсчете нуклеотидов в данной последовательности и возвращать результаты в списке. Для тех, кто не знаком с биоинформатикой, он просто подсчитывает количество вхождений четырех разных символов («A», «C», «G», «T») внутри строки.Почему Collections.counter так медленно?
Я ожидал, что 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». Я тоже буду запускать его –
Test1: {Метод 1: 0.24, Method2: 19.73, Method3: 4.63} Test2: {Метод 1: 0.26, Method2: 19.35, Method3: 4.30}. По крайней мере, 'counter' быстрее, чем метод2, который является, безвыходным, неправильным кодом. –
Ничего удивительного. Метод 1 использует код C, даже очень простой код C. И вы делаете это четыре раза. Неудивительно, что это намного быстрее. –