Есть ли эквивалент функции R apply в Python?

Я пытаюсь найти Python, эквивалентный функции R apply, но с многомерными массивами.

Например, при вызове следующего кода:

z <- array(1, dim = 2:4)
apply(z, 1, sum)

Результат:

[1] 12 12

и при вызове с двумя значениями маржи:

apply(z, c(1,2), sum)

Результат:

     [,1] [,2] [,3]
[1,]    4    4    4
[2,]    4    4    4

Я обнаружил, что функцию sum в numpy можно использовать, но не так последовательно:

Например:

import numpy as np

xx= np.ones((2,3,4))
np.sum(xx,axis=(1,2))

Результат:

array([12., 12.])

но я не могу найти функцию, эквивалентную apply, особенно при работе с margin=c(1,2). Может ли кто-нибудь помочь?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
3
0
1 097
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Эквивалент в NumPy:

xx.sum(axis=2)

То есть вы суммируете по оси 2 (последнее измерение), длина которой равна 4, а два других измерения (2,3) остаются формой результата:

array([[4., 4., 4.],
       [4., 4., 4.]])

Возможно, более буквальный перевод вашего кода R будет таким:

np.apply_over_axes(np.sum, xx, 2)

Что дает аналогичный результат, но транспонированный. Однако это, вероятно, будет медленнее и не является идиоматичным, если фактическая операция, которую вы выполняете, не является чем-то более сложным, чем сумма.

Я использовал np.apply_along_axis, пока не обнаружил это

AnhHao Trần 12.08.2021 12:50

np.apply_over_axes отличается от apply R по нескольким параметрам.

Во-первых, np.apply_over_axes необходимо указать сворачивающие оси, тогда как R's apply требует указания оставшихся осей.

Во-вторых, np.apply_over_axes итеративно применяет функцию, как указано ниже документация. Результат такой же для np.sum, но может отличаться для других функций.

func is called as res = func(a, axis), where axis is the first element of axes. The result res of the function call must have either the same dimensions as a or one less dimension. If res has one less dimension than a, a dimension is inserted before axis. The call to func is then repeated for each axis in axes, with res as the first argument.

И func для np.apply_over_axes должен быть в определенном формате, и возврат func должен быть в определенной форме, чтобы np.apply_over_axes работал правильно.

Вот пример того, как np.apply_over_axes терпит неудачу

>>> arr.shape
(5, 4, 3, 2)
>>> np.apply_over_axes(np.mean, arr, (0,1))
array([[[[ 0.05856732, -0.14844212],
         [ 0.34214183,  0.24319846],
         [-0.04807454,  0.04752829]]]])
>>> np_mean = lambda x: np.mean(x)
>>> np.apply_over_axes(np_mean, arr, (0,1))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<__array_function__ internals>", line 5, in apply_over_axes
  File "/Users/kwhkim/opt/miniconda3/envs/rtopython2-pip/lib/python3.8/site-packages/numpy/lib/shape_base.py", line 495, in apply_over_axes
    res = func(*args)
TypeError: <lambda>() takes 1 positional argument but 2 were given

Поскольку похоже, что в Python нет эквивалентной функции, Я сделал функцию, похожую на R apply

def np_apply(arr, axes_remain, fun, *args, **kwargs):
    axes_remain = tuple(set(axes_remain))
    arr_shape = arr.shape
    axes_to_move = set(range(len(arr.shape)))
    for axis in axes_remain:
        axes_to_move.remove(axis)
    axes_to_move = tuple(axes_to_move)
    arr, axes_to_move
    arr2 = np.moveaxis(arr, axes_to_move, [-x for x in list(range(1,len(axes_to_move)+1))]).copy()
    #if arr2.flags.c_contiguous:
    arr2 = arr2.reshape([arr_shape[x] for x in axes_remain]+[-1])

    return np.apply_along_axis(fun, -1, arr2, *args, **kwargs)

Он отлично работает, по крайней мере, для приведенного выше примера примера (не совсем то же самое, что и результат выше, но math.close() возвращает True почти для всех элементов)

>>> np_apply(arr, (2,3), np.mean)
array([[ 0.05856732, -0.14844212],
       [ 0.34214183,  0.24319846],
       [-0.04807454,  0.04752829]])
>>> np_apply(arr, (2,3), np_mean)
array([[ 0.05856732, -0.14844212],
       [ 0.34214183,  0.24319846],
       [-0.04807454,  0.04752829]])

Чтобы функция работала гладко для большого многомерного массива, его нужно оптимизировать. Например, следует запретить копирование массива.

Во всяком случае, это, кажется, работает как доказательство концепции, и я надеюсь, что это поможет.

ПС) arr генерируется arr = np.random.normal(0,1,(5,4,3,2))

Другие вопросы по теме