Применить функцию, возвращающую одномерный массив ко всем элементам массива numpy

1

Скажем, у меня есть массив d измерений, и я хочу применить функцию, которая возвращает 1D-массив для каждого элемента, что дает массив d+1 -dimensional. Очень похоже, что поиск встраивания работает. Например:

def f(x):
    return np.array([x * i for i in range(6)])

m = np.random.randint(0,10, (2,3,4,5))

g = np.vectorize(f)
h = np.vectorize(f, otypes=[np.ndarray])

Я ожидаю, что n=g(m) будет иметь форму (2,3,4,5,6) же, как если бы я написал 4 for циклов, применяя f к каждому элементу в m.

Однако g вызывает ошибку: ValueError: setting an array element with a sequence. и h возвращает нечетный массив, заканчивающийся так:

...
[array([0, 9, 18, 27, 36, 45, 54, 63, 72]),
array([0, 5, 10, 15, 20, 25, 30, 35, 40]),
array([0, 7, 14, 21, 28, 35, 42, 49, 56]), ...,
array([0, 1, 2, 3, 4, 5, 6, 7, 8]),
array([0, 4, 8, 12, 16, 20, 24, 28, 32]),
array([0, 3, 6, 9, 12, 15, 18, 21, 24])]]]], dtype=object)

которые я не могу изменить к тому, что я ожидаю.

Я получаю комментарий @hpaulj, я просто не могу найти, как это сделать иначе.

  • 0
    Это нормально. Ваш f возвращает массив для скалярного x . Создает результирующий массив формы, соответствующей x . Он может только поместить массив в массив object dtype.
  • 0
    Я должен перефразировать: Я понимаю , почему есть проблема, вы можете думать об альтернативах , которые не подразумевают for петель?
Показать ещё 2 комментария
Теги:
arrays
numpy

1 ответ

1
Лучший ответ

vectorize добавляет параметр signature который делает то, что вы хотите. Однако он еще медленнее, чем подход otypes. Все еще для полноты, я проиллюстрирую:

In [198]: def f(x):
     ...:     return np.array([x * i for i in range(6)])
In [199]: g = np.vectorize(f, signature='()->(6)')

Он принимает любой массив фигур и возвращает новый с размером размера 6:

In [202]: g(1)
Out[202]: array([0, 1, 2, 3, 4, 5])
In [203]: g(np.array([1,2]))
Out[203]: 
array([[ 0,  1,  2,  3,  4,  5],
       [ 0,  2,  4,  6,  8, 10]])
In [204]: g(np.array([[1],[2]]))
Out[204]: 
array([[[ 0,  1,  2,  3,  4,  5]],

       [[ 0,  2,  4,  6,  8, 10]]])

Чтобы сделать это быстрее, вы записываете f таким образом, чтобы использовать скомпилированные методы numpy. Нет функции, которая будет использовать функцию Python и переписать ее быстрее.

Для этого f мы можем использовать бесчисленное вещание и писать:

In [205]: def fn(x):
     ...:     return x[...,None] * np.arange(6)
     ...: 

In [207]: fn(np.array(1))
Out[207]: array([0, 1, 2, 3, 4, 5])
In [208]: fn(np.array([1,2]))
Out[208]: 
array([[ 0,  1,  2,  3,  4,  5],
       [ 0,  2,  4,  6,  8, 10]])
In [209]: fn(np.array([[1],[2]]))
Out[209]: 
array([[[ 0,  1,  2,  3,  4,  5]],

       [[ 0,  2,  4,  6,  8, 10]]])

Здесь векторизация была легкой. Иногда это требует некоторого умного мышления, а иногда и невозможного (особенно если проблема по своей сути носит серийный характер). Существуют инструменты для создания более быстрого скомпилированного кода из итеративных решений, таких как numba и cython.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню