NumPy сумма медленнее, чем количество строк - PullRequest
0 голосов
/ 22 апреля 2019

Я сравнивал производительность подсчета количества букв 'C' в очень длинной строке, используя numpy array символов и строковый метод count.
геном - этоочень длинная строка

g1 = genome 
g2 =  np.array([i for i in genome])

%timeit np.sum(g2=='C')                                                                                                                                                                             
4.43 s ± 230 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit g1.count('C')                                                                                                                                                                               
955 ms ± 6.42 ms per loop (mean ± std. dev. of 7 runs, 1 loop each).   

Я ожидал, что простой массив будет вычислять его быстрее, но я ошибаюсь.

Может кто-нибудь объяснить мне, как работает метод подсчета и что это быстрее, чем использование массива numpy?

Спасибо!

1 Ответ

2 голосов
/ 22 апреля 2019

Давайте рассмотрим некоторые варианты проблемы.Я не буду пытаться сделать строку такой же большой, как ваша.

In [393]: astr = 'ABCDEF'*10000                                                      

Сначала подсчитаем количество строк:

In [394]: astr.count('C')                                                            
Out[394]: 10000
In [395]: timeit astr.count('C')                                                     
70.2 µs ± 115 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Теперь попробуйте массив из 1 элемента с этой строкой:

In [396]: arr = np.array(astr)                                                       
In [397]: arr.shape                                                                  
Out[397]: ()
In [398]: np.char.count(arr, 'C')                                                    
Out[398]: array(10000)
In [399]: timeit np.char.count(arr, 'C')                                             
200 µs ± 2.97 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [400]: arr.dtype                                                                  
Out[400]: dtype('<U60000')

Мой опыт использования char заключается в том, что он выполняет итерации для элементов массива и применяет строковый метод.Так что это не может быть быстрее, чем применять метод string напрямую.Я полагаю, что в остальное время это какая-то непонятная накладная нагрузка.

Составьте список из строки - по одному символу на элемент списка:

In [402]: alist = list(astr)                                                         
In [403]: alist.count('C')                                                           
Out[403]: 10000
In [404]: timeit alist.count('C')                                                    
955 µs ± 18.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

Счетчик списка должен проходить по циклуэлементы, и сделайте тест против C каждый раз.Тем не менее это быстрее, чем sum(i=='C' for i in alist) (и варианты).

Теперь создайте массив из этого списка - односимвольные элементы:

In [405]: arr1 = np.array(alist)                                                     
In [406]: arr1.shape                                                                 
Out[406]: (60000,)
In [407]: timeit arr1=='C'                                                           
634 µs ± 12.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
In [408]: timeit np.sum(arr1=='C')                                                   
740 µs ± 23.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

np.sum относительно быстро.Больше всего времени занимает проверка на «С».

Если я построю числовой массив того же размера, время подсчета будет немного быстрее.Проверка на равенство с числом выполняется быстрее, чем проверка на эквивалентную строку.

In [431]: arr2 = np.resize(np.array([1,2,3,4,5,6]),arr1.shape[0])                    
In [432]: np.sum(arr2==3)                                                            
Out[432]: 10000
In [433]: timeit np.sum(arr2==3)                                                     
155 µs ± 1.66 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

numpy не обещает быть более быстрым для всех операций Python.В большинстве случаев при работе со строковыми элементами он сильно зависит от собственного строкового кода Python.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...