Нашли ошибку?
продвинутыйNumPy 2.5.3

apply_along_axis

Применить функцию к каждой строке или столбцу — и понять, когда можно обойтись без этого.

Нужно знать:Оси: axis и keepdimsВекторизация вместо циклов

Содержание статьи

Коротко

  • np.apply_along_axis(func, axis, a) вызывает func для каждого одномерного среза вдоль axis: при axis=1 — для каждой строки.
  • Функция может вернуть число или массив — результаты собираются в новый массив.
  • Внутри — обычный цикл Python, поэтому это не быстрее цикла. Выигрыш только в краткости.
  • Если функция собрана из агрегаций NumPy (max, mean, sort…), вызовите их сразу с axis — это в разы быстрее.
  • apply_along_axis оправдан для функций без параметра axis: bincount, interp, свои функции с ветвлениями.

Синтаксис

np.apply_along_axis(func1d, axis, arr, *args, **kwargs)
np.apply_along_axis(f, 1, a)      # f(строка) для каждой строки
np.apply_along_axis(f, 0, a)      # f(столбец) для каждого столбца

Параметры

ПараметрЧто делаетПо умолчанию
func1dфункция от одномерного массиваобязательный
axisось, вдоль которой берутся срезы: 1 — строки, 0 — столбцыобязательный
*args, **kwargsдополнительные аргументы для func1dобязательный

Примеры

Данные для примеровиспользуются во всех примерах ниже
# оценки 3 учеников по 5 работам
scores = np.array([[4, 5, 3, 5, 4],
                   [3, 3, 4, 2, 5],
                   [5, 5, 5, 4, 5]])
Функция для каждой строки
def spread(row):
    return row.max() - row.min()

np.apply_along_axis(spread, 1, scores)       # функция получает каждую строку
Вывод
array([2, 3, 1])
Функция возвращает массив
def top2(row):
    return np.sort(row)[-2:]                 # функция возвращает массив

np.apply_along_axis(top2, 1, scores)
Вывод
array([[5, 5],
       [4, 5],
       [5, 5]])
Функция без параметра axis
def mode(row):
    return np.bincount(row).argmax()         # у bincount нет параметра axis

np.apply_along_axis(mode, 1, scores)         # самая частая оценка каждого ученика
Вывод
array([4, 3, 5])
Для каждого столбца
np.apply_along_axis(np.median, 0, scores)    # по столбцам — функция получает каждый столбец
Вывод
array([4., 5., 4., 4., 5.])

Подводные камни

apply_along_axis там, где хватит axis=

Первый пример переписывается без цикла: у max и min есть axis.

Векторная версия
scores.max(axis=1) - scores.min(axis=1)      # то же без apply_along_axis
Вывод
array([2, 3, 1])