многократное умножение массива с массивами произвольных измерений

У меня есть numpy массив A, который имеет форму (10,).

У меня также есть на данный момент массив с множеством B с формой (10,3,5). Я хочу сделать умножение между этими двумя, чтобы получить C, что C [0,:,:] = A [0] * B [0,:,:], C [1] = A [1] * B [1 ,:,:], и т.д.

Я не хочу работать с петлями, одной из причин является эстетика вещи, а другая заключается в том, что этот код должен быть очень общим. Я хочу, чтобы пользователь мог вносить практически любой B любой формы, если ведущий размер равен 10. Например, я хочу, чтобы пользователь мог также ввести B формы (10,4).

Итак: как я могу реализовать это умножение с помощью numpy? Благодарю.

ДОБАВЛЕНИЕ: Просили, например. Пойдет меньше. Предположим, что A – это массив numpy [1,2,3], а B – массив numpy [[1,2], [4,5], [7,8]]. Я хочу, чтобы их умножение приводило к [[1,2], [8,10], [21,24]]. …

>>> a array([1, 2, 3]) >>> b array([[1, 2], [4, 5], [7, 8]]) >>> #result >>> c array([[ 1, 2], [ 8, 10], [21, 24]]) >>> 

Вы можете использовать None (или np.newaxis ) для расширения A для соответствия B :

 >>> A = np.arange(10) >>> B = np.random.random((10,3,5)) >>> C0 = np.array([A[i]*B[i,:,:] for i in range(len(A))]) >>> C1 = A[:,None,None] * B >>> np.allclose(C0, C1) True 

Но это будет работать только на 2 случая. Заимствуя с @ajcr, с достаточным количеством транспозиций, мы можем получить неявное вещание для работы в общем случае:

 >>> C3 = (A * BT).T >>> np.allclose(C0, C3) True 

В качестве альтернативы вы можете использовать einsum для обеспечения общности. Оглядываясь назад, это, вероятно, будет излишним по сравнению с транспонированным маршрутом, но это удобно, когда умножения сложнее.

 >>> C2 = np.einsum('i,i...->i...', A, B) >>> np.allclose(C0, C2) True 

а также

 >>> B = np.random.random((10,4)) >>> D0 = np.array([A[i]*B[i,:] for i in range(len(A))]) >>> D2 = np.einsum('i,i...->i...', A, B) >>> np.allclose(D0, D2) True 

Хотя мне нравится нотация einsum , я добавлю немного разнообразия в микс ….

Вы можете добавить достаточно дополнительных измерений в a чтобы он транслировался через b .

 >>> a.shape (3,) >>> b.shape (3,2) 

b имеет больше размеров, чем

 extra_dims = b.ndim - a.ndim 

Добавьте дополнительные размеры (а) к

 new_shape = a.shape + (1,)*extra_dims # (3,1) new_a = a.reshape(new_shape) 

Умножение

 new_a * b 

Как функция:

 def f(a, b): '''Product across the first dimension of b. Assumes a is 1-dimensional. Raises AssertionError if a.ndim > b.ndim or - the first dimensions are different ''' assert a.shape[0] == b.shape[0], 'First dimension is different' assert b.ndim >= a.ndim, 'a has more dimensions than b' # add extra dimensions so that a will broadcast extra_dims = b.ndim - a.ndim newshape = a.shape + (1,)*extra_dims new_a = a.reshape(newshape) return new_a * b