Эффективное осевое декартово произведение множественных двумерных матриц с 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)