#python #numpy #array-broadcasting #numpy-ufunc
#питон #тупица #массив-вещание #numpy-ufunc
Вопрос:
У меня есть 2 массива:
gt;gt;gt; a.shape (9, 3, 11) gt;gt;gt; b.shape (9,)
Я хотел бы вычислить эквивалент c[i, j] = f(a[i, j, :], b[i])
того, где f(a0, b0)
находится функция, которая принимает 2 параметра, с len(a0) == 11
и len(b0) == 9
. Здесь i
повторяется range(9)
и j
повторяется range(3)
.
Есть ли способ закодировать это с помощью numpy.vectorize
? Или это проще с помощью какой-нибудь умной трансляции?
Я пытаюсь уже 2 часа и просто не понимаю, как заставить это работать… Я пытался транслировать или использовать подписи, но безрезультатно.
Комментарии:
1.
np.array([f(a[i,j,:], b[i]) for j in range(3)] for i in range(9)])
.a b[:,None,None]
будет работать, но результат (9,3,11). Или, можетnp.sum(a b[:,None,None]).axis=2)
быть, если вы хотите (9,3), но тогда вы могли быnp.sum(a, axis=2)
сначала.2.
np.vectorize
в режиме по умолчанию передает скалярные значения функции. Существуетsignature
опция, которая позволяет передавать массивы, но ее сложнее использовать и даже медленнее.apply_along_axis
может повторять вашиi,j
измеренияa
(медленно), но не может, в то же время повторять дальшеb
. Это всего лишь итератор с одним массивом. Понимание вложенного списка, вероятно, является вашим лучшим вариантом.3. Пример функции может помочь. Также вам нужно четко указать, что возвращает функция. Является ли он скалярным, поэтому
c
может быть числовым массивом dtype. Это требует, я полагаю, некоторого уменьшения размера 11.4. @hpaulj, в конце концов я смог найти решение:
np.vectorize(f, signature="(k),(1)-gt;()")
и тогда я должен назвать это такf(a, b[:, None, None]
. Как вы думаете, это будет намного медленнее, чем цикл?
Ответ №1:
В конце концов, я мог бы заставить это работать вот так:
gt;gt;gt; f = np.vectorize(f, signature="(k),(1)-gt;()") gt;gt;gt; print(a.shape) (9, 3, 11) gt;gt;gt; print(b.shape) (9,) gt;gt;gt; print(f(a, b[:, None, None]).shape) (9, 3)
Это гарантирует, что вызывается с правильными формами и выполняется правильно. f
Откровенно говоря, из документации Numpy непросто понять, как использовать a (1)
в подписи для этой цели.
Ответ №2:
numpy.apply_along_axis
это то, что тебе нужно.
import numpy as np a = np.ones( (9,3,11) ) b = np.ones( 9 ) def f(a0, b0): return sum(a0[:9] b0) c = np.apply_along_axis( f, 2, a, b ) print(c)
c
его форма равна (9,3).
Комментарии:
1. Я получаю форму (9, 3, 9)
c
.2. Хорошо,
f
нужно вернуть одно значение. не список из 9. Сейчасc
это (9,3).3. Вы могли бы сделать это просто
return np.sum(a0) b0
, поэтому нам не нужен индекс в определении функции! Важно вернуть скалярное значение.4. Это не сработает, потому
b0
что это массив из 9. Он выполнит скалярное сложение и вернет список, в котором я в первую очередь получил (9,3,9). ОДНАКО я придумал эту фиктивную функцию только потому, что вы не предоставили свою. Я предполагаю, что у вас все немного сложнее.