Умножьте один и тот же массив numpy на скаляры несколько раз

#python #numpy #numpy-ndarray #tensor #array-broadcasting

Вопрос:

У меня есть массив 3D NumPy размером (9,9,200) и массив 2D размером (200,200) . Я хочу взять каждый канал форму (9,9,1) и создать массив (9,9,200) , каждый канал умноженной в 200 раз по 1 скаляр в один ряд, и средний ее так, чтобы результирующий массив (9,9,1) .
В принципе, если есть n каналы в массиве ввода, я хочу, чтобы каждый канал умножается n раза и составила в среднем — и это должно произойти для всех каналов. Есть ли эффективный способ сделать это?

Пока что у меня есть вот это —

 import numpy as np
arr = np.random.rand(9,9,200)
nchannel = arr.shape[-1]
transform = np.array([np.random.uniform(low=0.0, high=1.0, size=(nchannel,)) for i in range(nchannel)])
  for channel in range(nchannel):
    # The below line needs optimization
    temp = [arr[:,:,i] * transform[channel][i] for i in range(nchannel)]
    arr[:,:,channel] = np.sum(temp, axis=0)/nchannel
 

Редактировать :
Пример изображения, демонстрирующего то, что я ищу. Здесь nchannel = 3.
введите описание изображения здесь
Входное изображение есть arr . Конечный образ — это трансформированный arr .

Комментарии:

1. можете ли вы опубликовать минимальный исполняемый пример? Я не уверен, что такое arr и nchannel…

2. Я не уверен, что понимаю, чего вы хотите, для чего нужен 2D-массив? Откуда берутся n скаляров?

3. Возможно, чтобы добавить к комментарию sehan2 , было бы очень полезно, если бы это был игрушечный пример, которого нет 9 x 9 x 200 , но что-то вроде 2 x 2 x 3 ожидаемого результата: -) Я, к сожалению, не понимаю вашей проблемы из вопроса..

4. Спасибо, что указали на это @sehan2. @user16648691 двумерный массив представляет собой nxn матрицу, каждая строка которой соответствует n скалярам, на которые будет умножен один канал.

5. Если я правильно понял, это тензорное умножение на матрицу, а затем усреднение по оси -1?

Ответ №1:

Редактировать:

 import numpy as np

n_channels = 3
scalar_size = 2

t = np.ones((n_channels,scalar_size,scalar_size)) # scalar array
m = np.random.random((n_channels,n_channels)) # letters array

print(m)
print(t)
m_av = np.mean(m, axis=1)
print(m_av)

for i in range(n_channels):
    t[i] = t[i]*m_av1[i]

print(t)

 

выход:

 [[0.04601533 0.05851365 0.03893352]
 [0.7954655  0.08505869 0.83033369]
 [0.59557455 0.09632997 0.63723506]]

[[[1. 1.]
  [1. 1.]]

 [[1. 1.]
  [1. 1.]]

 [[1. 1.]
  [1. 1.]]]

[0.04782083 0.57028596 0.44304653]

[[[0.04782083 0.04782083]
  [0.04782083 0.04782083]]

 [[0.57028596 0.57028596]
  [0.57028596 0.57028596]]

 [[0.44304653 0.44304653]
  [0.44304653 0.44304653]]]

 

Комментарии:

1. Привет @user16648691, я не думаю, что это правильное решение. Я добавил диаграмму, чтобы лучше подчеркнуть то, что я ищу.

2. итак, здесь у нас есть скалярный массив 2x2x3 и массив 3×3, содержащий каналы, верно? Сначала для каждого канала размера 3 мы получаем массив 2x2x3, который в основном является элементом умножения скалярного массива на каждый элемент канала ? Таким образом, вы в конечном итоге получаете массив 2x2x3x3, который вы, наконец, усреднили на последнем axxis, чтобы получить массив 2x2x3 ? Поправьте меня, если я ошибаюсь

3. Если это так, я бы сначала усреднил каждый канал, чтобы вы получили массив 1D размером n_channel, который вы можете поэлементно умножить на свой скалярный массив. Я отредактирую свой ответ.

Ответ №2:

То, о чем вы просите, — это простое матричное умножение вдоль последней оси:

 import numpy as np

arr = np.random.rand(9,9,200)
transform = np.random.uniform(size=(200, 200)) / 200

arr = arr @ transform