Эффективное осевое декартово произведение множественных двумерных матриц с Numpy или TensorFlow

Итак, во-первых, я думаю, что я пытаюсь достичь какого-то декартова произведения, но поэтапно, только по столбцам.

Что я пытаюсь сделать, если у вас есть несколько двумерных массивов размером [ (N,D1), (N,D2), (N,D3)...(N,Dn) ]

Таким образом, результатом должно быть комбинаторное произведение по оси =1, так что конечный результат будет иметь форму (N, D), где D=D1*D2*D3*...Dn

например

A = np.array([[1,2],
              [3,4]])
B = np.array([[10,20,30],
              [5,6,7]])

cartesian_product( [A,B], axis=1 )
>> np.array([[ 1*10, 1*20, 1*30, 2*10, 2*20, 2*30 ]
             [ 3*5,  3*6,  3*7,  4*5,  4*6,  4*7  ]])

и расширяемый до cartesian_product([A,B,C,D...], ось =1)

например

A = np.array([[1,2],
              [3,4]])
B = np.array([[10,20],
              [5,6]])
C = np.array([[50, 0],
              [60, 8]])
cartesian_product( [A,B,C], axis=1 )
>> np.array([[ 1*10*50, 1*10*0, 1*20*50, 1*20*0, 2*10*50, 2*10*0, 2*20*50, 2*20*0] 
             [ 3*5*60,  3*5*8,  3*6*60,  3*6*8,  4*5*60,  4*5*8,  4*6*60,  4*6*8]])

У меня есть рабочее решение, которое по существу создает пустую (N, D) матрицу и затем передает векторное произведение по столбцам для каждого столбца внутри вложенных циклов для каждой матрицы в представленном списке. Очевидно, это ужасно, когда массивы становятся больше!

Существует ли существующее решение в numpy или tenorflow для этого? Потенциально тот, который эффективно распараллеливается (решение с тензорным потоком было бы замечательно, но с клочком все в порядке, и если векторная логика ясна, то сделать tf-эквивалент не составит труда)

Я не уверен, нужно ли мне использовать einsum, tenordot, meshgrid или какую-либо их комбинацию для достижения этой цели. У меня есть решение, но только для одномерных векторов из /questions/19040508/numpy-dekartovo-proizvedenie-tochek-massiva-x-i-y-na-odin-massiv-tochek-2d/19040513#19040513 хотя в этом решении сказано, что он работает для массива произвольных измерений (который, кажется, означает векторы). С этим я могу сделать.prod(axis=1), но опять же, это справедливо только для векторов.

Спасибо!

1 ответ

Решение

Вот один из подходов, позволяющий делать это итеративно, накапливая broadcasting после расширения измерений для каждой пары из списка массивов для умножения по элентменту -

L = [A,B,C]  # list of arrays
n = L[0].shape[0]
out = (L[1][:,None]*L[0][:,:,None]).reshape(n,-1)
for i in L[2:]:
    out = (i[:,None]*out[:,:,None]).reshape(n,-1)
Другие вопросы по тегам