Numba 3x медленнее, чем numpy

У нас есть векторная функция get_pos_neg_bitwise numpy, которая использует маску = [132 20 192] и df.shape (500e3, 4), которые мы хотим ускорить с помощью numba.

from numba import jit import numpy as np from time import time def get_pos_neg_bitwise(df, mask): """ In [1]: print mask [132 20 192] In [1]: print df [[ 1 162 97 41] [ 0 136 135 171] ..., [ 0 245 30 73]] """ check = (np.bitwise_and(mask, df[:, 1:]) == mask).all(axis=1) pos = (df[:, 0] == 1) & check neg = (df[:, 0] == 0) & check pos = np.nonzero(pos)[0] neg = np.nonzero(neg)[0] return (pos, neg) 

Используя советы от @morningsun, мы сделали эту версию numba:

 @jit(nopython=True) def numba_get_pos_neg_bitwise(df, mask): posneg = np.zeros((df.shape[0], 2)) for idx in range(df.shape[0]): vandmask = np.bitwise_and(df[idx, 1:], mask) # numba fail with # if np.all(vandmask == mask): vandm_equal_m = 1 for i, val in enumerate(vandmask): if val != mask[i]: vandm_equal_m = 0 break if vandm_equal_m == 1: if df[idx, 0] == 1: posneg[idx, 0] = 1 else: posneg[idx, 1] = 1 pos = list(np.nonzero(posneg[:, 0])[0]) neg = list(np.nonzero(posneg[:, 1])[0]) return (pos, neg) 

Но это все еще в 3 раза медленнее, чем numpy one (~ 0,06s Vs ~ 0,02s).

 if __name__ == '__main__': df = np.array(np.random.randint(256, size=(int(500e3), 4))) df[:, 0] = np.random.randint(2, size=(1, df.shape[0])) # set target to 0 or 1 mask = np.array([132, 20, 192]) start = time() pos, neg = get_pos_neg_bitwise(df, mask) msg = '==> pos, neg made; p={}, n={} in [{:.4} s] numpy' print msg.format(len(pos), len(neg), time() - start) start = time() msg = '==> pos, neg made; p={}, n={} in [{:.4} s] numba' pos, neg = numba_get_pos_neg_bitwise(df, mask) print msg.format(len(pos), len(neg), time() - start) start = time() pos, neg = numba_get_pos_neg_bitwise(df, mask) print msg.format(len(pos), len(neg), time() - start) 

Я что-то упускаю ?

 In [1]: %run numba_test2.py ==> pos, neg made; p=3852, n=3957 in [0.02306 s] numpy ==> pos, neg made; p=3852, n=3957 in [0.3492 s] numba ==> pos, neg made; p=3852, n=3957 in [0.06425 s] numba In [1]: 

One Solution collect form web for “Numba 3x медленнее, чем numpy”

Попробуйте перевести вызов на np.bitwise_and вне цикла, поскольку numba не может ничего сделать, чтобы ускорить его:

 @jit(nopython=True) def numba_get_pos_neg_bitwise(df, mask): posneg = np.zeros((df.shape[0], 2)) vandmask = np.bitwise_and(df[:, 1:], mask) for idx in range(df.shape[0]): # numba fail with # if np.all(vandmask == mask): vandm_equal_m = 1 for i, val in enumerate(vandmask[idx]): if val != mask[i]: vandm_equal_m = 0 break if vandm_equal_m == 1: if df[idx, 0] == 1: posneg[idx, 0] = 1 else: posneg[idx, 1] = 1 pos = np.nonzero(posneg[:, 0])[0] neg = np.nonzero(posneg[:, 1])[0] return (pos, neg) 

Затем я получаю тайминги:

 ==> pos, neg made; p=3920, n=4023 in [0.02352 s] numpy ==> pos, neg made; p=3920, n=4023 in [0.2896 s] numba ==> pos, neg made; p=3920, n=4023 in [0.01539 s] numba 

Итак, теперь numba немного быстрее, чем numpy.

Кроме того, это не имело большого значения, но в вашей исходной функции вы возвращаете массивы numpy, в то время как в версии numba вы конвертировали pos и neg в списки.

В общем, я бы предположил, что в вызовах функций преобладают функции numpy, которые numba не может ускорить, а numpy-версия кода уже использует быстрые подпрограммы векторизации.

Обновить:

Вы можете сделать это быстрее, удалив enumerate вызов и индекс непосредственно в массив вместо захвата среза. Также разделение pos и neg на отдельные массивы помогает избежать нарезки вдоль несмежной оси в памяти:

 @jit(nopython=True) def numba_get_pos_neg_bitwise(df, mask): pos = np.zeros(df.shape[0]) neg = np.zeros(df.shape[0]) vandmask = np.bitwise_and(df[:, 1:], mask) for idx in range(df.shape[0]): # numba fail with # if np.all(vandmask == mask): vandm_equal_m = 1 for i in xrange(vandmask.shape[1]): if vandmask[idx,i] != mask[i]: vandm_equal_m = 0 break if vandm_equal_m == 1: if df[idx, 0] == 1: pos[idx] = 1 else: neg[idx] = 1 pos = np.nonzero(pos)[0] neg = np.nonzero(neg)[0] return pos, neg 

И тайминги в ноутбуке ipython:

  %timeit pos1, neg1 = get_pos_neg_bitwise(df, mask) %timeit pos2, neg2 = numba_get_pos_neg_bitwise(df, mask)​ 100 loops, best of 3: 18.2 ms per loop 100 loops, best of 3: 7.89 ms per loop 
  • запустите np.empty во второй раз
  • Как читать .npy-файлы в Matlab
  • Преобразование последовательности Python в массив NumPy, заполнение отсутствующих значений
  • Объединение словарей из массивов numpy (избегая, если это возможно, ручных петель)
  • Нумерообразный эквивалент функции Findpeaks Matlab?
  • Значения гистограммы серии Pandas
  • Как отсортировать массив numpy с ключом как isnan?
  • Numpy __getitem__ с задержкой оценки и не то же самое, что
  •  
    Interesting Posts for Van-Lav

    Координаты текстуры около 1 ведут себя странно

    ярлык python для len (список (фильтр (лямбда x: критерии, итерируемый)))

    Синхронный v / s Асинхронный

    Gunicorn не перезагружает приложение Django

    Застревание реализации простой нейронной сети

    Чистые регулярные выражения Python

    Как исправить кодирование, переносящее подпроцесс Python на unicode_literals?

    Как игнорировать определенные неопределенные переменные в Pydev Eclipse

    pandas groupby для вложенного json

    Добавить в список при итерации

    Как получить сообщения пользователей через facebook-sdk python api?

    python: открытый файл, строка фида для списка, данные списка процессов

    Python-C Api-оболочка в Objective-C сбой при вызове __getattr__ при передаче объекта Python

    Мне нужна помощь, обертывающая мою голову вокруг оператора return с помощью Python и его роли в этом рекурсивном выражении

    Pycharm Тип-подсказка полей классов / переменных экземпляра

    Python - лучший язык программирования в мире.