numpy.векторизация сигнатуры функции

#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). ОДНАКО я придумал эту фиктивную функцию только потому, что вы не предоставили свою. Я предполагаю, что у вас все немного сложнее.