Использование `numpy.vectorize` для создания многомерного массива приводит к ValueError: установка элемента массива с последовательностью
Эта проблема возникает только тогда, когда мой dummy
Функция возвращает массив и, таким образом, создается многомерный массив.
Я сократил проблему до следующего примера:
def dummy(x):
y = np.array([np.sin(x), np.cos(x)])
return y
x = np.array([0, np.pi/2, np.pi])
Код, который я хочу оптимизировать, выглядит следующим образом:
y = []
for x_i in x:
y_i = dummy(x_i)
y.append(y_i)
y = np.array(y)
Поэтому я подумал, я мог бы использовать vectorize
избавиться от медленной петли:
y = np.vectorize(dummy)(x)
Но это приводит к
ValueError: setting an array element with a sequence.
Где даже последовательность, о которой говорит ошибка?!
2 ответа
Ваша функция возвращает массив при наличии скаляра:
In [233]: def dummy(x):
...: y = np.array([np.sin(x), np.cos(x)])
...: return y
...:
...:
In [234]: dummy(1)
Out[234]: array([0.84147098, 0.54030231])
In [235]: f = np.vectorize(dummy)
In [236]: f([0,1,2])
...
ValueError: setting an array element with a sequence.
vectorize
создает пустой массив результатов и пытается поместить в него результат каждого вычисления. Но ячейка целевого массива не может принять массив.
Если мы укажем otypes
параметр, он работает:
In [237]: f = np.vectorize(dummy, otypes=[object])
In [238]: f([0,1,2])
Out[238]:
array([array([0., 1.]), array([0.84147098, 0.54030231]),
array([ 0.90929743, -0.41614684])], dtype=object)
То есть каждый dummy
массив помещается в элемент массива результатов shape (3,).
Поскольку массивы компонентов имеют одинаковую форму, мы можем stack
их:
In [239]: np.stack(_)
Out[239]:
array([[ 0. , 1. ],
[ 0.84147098, 0.54030231],
[ 0.90929743, -0.41614684]])
Но, как уже отмечалось, vectorize
не обещает ускорение. Я подозреваю, что мы могли бы также использовать более новый signature
параметр, но это еще медленнее.
vectorize
Имеет смысл, если ваша функция принимает несколько скалярных аргументов, и вы хотели бы использовать бесполезную трансляцию при передаче наборов значений. Но в качестве замены простой итерации по 1d-массиву это не улучшение.
Я не очень понимаю ошибку, но с Python 3.6.3 вы можете просто написать:
y = dummy(x)
так что это автоматически векторизация.
Также в официальной документации написано следующее:
Функция векторизации предоставляется в первую очередь для удобства, а не для производительности. Реализация по сути является циклом for.
Я надеюсь, что это было хоть немного помощи.