Векторизация в numpy обеспечит повышение производительности численных вычислений по сравнению с l oop, потому что это сокращает некоторые накладные расходы интерпретатора Python на динамическое определение некоторых характеристик данных (например, его тип и местоположение) во время выполнения.
Объект ndarray
выполняет множество мощных функций, оптимизирующих скорость вычислений, например, обеспечивает однородность и непрерывность данных в памяти.
Для n-мерных данных по умолчанию numpy сохраняет значения в C упорядочении (основная строка) , так что последовательные элементы строки хранятся рядом друг с другом.
Это также полосатое представление блока данных, что означает, что при его инициализации вы также указываете, сколько байтов памяти занимает каждый элемент внутри - в других словами, какой большой шаг вам нужно сделать, чтобы перейти к следующему.
Когда вы используете векторизованную функцию для объекта ndarray
, он ведет себя m или вроде C код, чем как Python. Другими словами, он работает непосредственно со значениями в памяти и изменяет их, а также пользуется преимуществами всех оптимизаций хранения и типов.
Я подозреваю, что когда вы не векторизуете свою функцию f
, вы сильно увеличиваете накладные расходы интерпретатора Python. При успешной векторизации большая часть этой функции будет выполняться в C и избежать большей части замедления, которое вносит Python. Я задавался вопросом, не смог ли enumerate
воспользоваться преимуществами базовой структуры данных так, как объект numpy nditer
, но я протестировал nditer
, numpy ufuncs и явный цикл for с enumerate
и enumerate
на самом деле был самым быстрым итератором, поэтому я предполагаю, что ваша пользовательская функция, вероятно, является виновником времени. Это имеет смысл, особенно с учетом того, что PyPy имеет намного более драматическое c замедление.
Примеры тестов:
a = np.ndarray()
>>> %%time
>>> for x in np.nditer(a, flags=['external_loop']):
>>> .... x*x
CPU times: user 201 ms, sys: 219 ms, total: 420 ms
Wall time: 420 ms
>>> %%time
>>> np.square(a)
CPU times: user 201 ms, sys: 180 ms, total: 381 ms
Wall time: 380 ms
>>> %%time
>>> for i, x in enumerate(a):
>>> .... x*x
CPU times: user 78.5 ms, sys: 1.79 ms, total: 80.3 ms
Wall time: 79.4 ms