Учитывая массив A NumPy , каков самый быстрый / наиболее эффективный способ применить одну и ту же функцию f к каждой ячейке?
Предположим, что мы присвоим A (i, j) значение f (A (i, j)) .
Функция f не имеет двоичного вывода, поэтому операции маски (ing) не помогут.
Является ли "очевидная" итерация двойного цикла (через каждую ячейку) оптимальным решением?
Ответы:
Вы можете просто векторизовать функцию, а затем применять ее непосредственно к массиву Numpy каждый раз, когда она вам нужна:
Вероятно, лучше указать явный тип вывода напрямую при векторизации:
источник
vectorize
описании функции: функция векторизации предназначена в первую очередь для удобства, а не для повышения производительности. Реализация по сути представляет собой цикл for. Так что это, скорее всего, совсем не ускорит процесс.vectorize
определяется возвращаемый тип. Это привело к ошибкам.frompyfunc
немного быстрее, но возвращает массив объектов dtype. Оба питают скаляры, а не строки или столбцы.np.vectorize
моей функции (которая использует RK45) дает мне ускорение в ~ 20 раз.Аналогичный вопрос: отображение массива NumPy на месте . Если вы можете найти ufunc для своего f (), вам следует использовать параметр out.
источник
Если вы работаете с числами и
f(A(i,j)) = f(A(j,i))
, вы можете использовать scipy.spatial.distance.cdist, определяя f как расстояние междуA(i)
иA(j)
.источник
Я считаю, что нашел лучшее решение. Идея изменить функцию на универсальную функцию Python (см. Документацию ), которая может выполнять параллельные вычисления под капотом.
Можно написать свою собственную настройку
ufunc
на C, что, безусловно, более эффективно, или путем вызоваnp.frompyfunc
встроенного фабричного метода. После тестирования это более эффективно, чемnp.vectorize
:Я также протестировал образцы большего размера, и улучшение пропорционально. Для сравнения производительности других методов см. Этот пост
источник
Когда 2d-массив (или nd-массив) является C- или F-смежным, тогда эта задача отображения функции на 2d-массив практически такая же, как задача отображения функции на 1d-массив - мы просто нужно рассматривать это таким образом, например, через
np.ravel(A,'K')
.Возможное решение для 1d-массива обсуждалось, например, здесь .
Однако, когда память 2d-массива не является непрерывной, тогда ситуация немного усложняется, потому что хотелось бы избежать возможных промахов кеша, если оси обрабатываются в неправильном порядке.
У Numpy уже есть оборудование для обработки топоров в наилучшем возможном порядке. Одна из возможностей использовать эту технику
np.vectorize
. Однако в документации numpynp.vectorize
указано, что она «предоставляется в первую очередь для удобства, а не для производительности» - медленная функция python остается медленной функцией python со всеми связанными накладными расходами! Другая проблема - это огромное потребление памяти - см., Например, этот SO-пост .Когда кто-то хочет иметь производительность C-функции, но использовать механизм numpy, хорошим решением является использование numba для создания ufunc, например:
Он легко превосходит,
np.vectorize
но также, когда та же функция будет выполняться как умножение / сложение массива numpy, т.е.См. Приложение к этому ответу для кода измерения времени:
Версия Numba (зеленая) примерно в 100 раз быстрее, чем функция python (т.е.
np.vectorize
), что неудивительно. Но это также примерно в 10 раз быстрее, чем numpy-функциональность, потому что версия numbas не требует промежуточных массивов и, таким образом, использует кеш более эффективно.Хотя подход numba к ufunc - это хороший компромисс между удобством использования и производительностью, это все еще не лучшее, что мы можем сделать. Тем не менее, не существует серебряной пули или наилучшего подхода для любой задачи - нужно понимать, в чем заключаются ограничения и как их можно уменьшить.
Например, для трансцендентных функций (например
exp
,sin
,cos
) Numba не дает каких - либо преимуществ по сравнению с NumPy - хnp.exp
(нет временных массивов , созданных - основной источник ускорения). Однако моя установка Anaconda использует Intel VML для векторов больше 8192 - он просто не может этого сделать, если память не является непрерывной. Поэтому, возможно, лучше скопировать элементы в непрерывную память, чтобы иметь возможность использовать Intel VML:Для справедливости сравнения я отключил распараллеливание VML (см. Код в приложении):
Как можно видеть, как только VML начинает работать, накладные расходы на копирование более чем компенсируются. Однако, когда объем данных становится слишком большим для кэша L3, преимущество становится минимальным, поскольку задача снова становится ограниченной пропускной способностью памяти.
С другой стороны, numba также может использовать Intel SVML, как объясняется в этом посте :
а использование VML с распараллеливанием дает:
Версия numba имеет меньше накладных расходов, но для некоторых размеров VML превосходит SVML, даже несмотря на дополнительные накладные расходы на копирование, что неудивительно, поскольку ufuncs numba не распараллеливаются.
Тэг:
A. сравнение полиномиальной функции:
Б. сравнение
exp
:источник
Все приведенные выше ответы хорошо сравниваются, но если вам нужно использовать настраиваемую функцию для сопоставления, а у вас есть
numpy.ndarray
, и вам нужно сохранить форму массива.У меня сравните всего два, но форма сохранит
ndarray
. Для сравнения я использовал массив с 1 миллионом записей. Здесь я использую квадратную функцию. Я представляю общий случай для n-мерного массива. Для двухмерного просто сделайтеiter
для 2D.Вывод
здесь вы можете четко видеть
numpy.fromiter
функцию квадрата пользователя, используйте любую на ваш выбор. Если ваша функция зависит отi, j
индексов массива, повторяйте размер массива, напримерfor ind in range(arr.size)
, используйте,numpy.unravel_index
чтобы получитьi, j, ..
на основе вашего 1D-индекса и формы массива numpy.unravel_indexЭти ответы вдохновлены моим ответом на другой вопрос здесь
источник