Не на 100% уверен, что это именно то, что вам нужно, но он получает правильные формы.
Сначала создайте диагностические входы
>>> a1 = np.empty((2, 2, 2, 3, 4), 'U1')
>>> for i, x in enumerate(np.ogrid[:2, :2, :2, :3]):
... a1[..., i] = x
...
>>> a2 = a1 = a1.view('U4').reshape(a1.shape[:-1])
>>> a1
array([[[['0000', '0001', '0002'],
['0010', '0011', '0012']],
[['0100', '0101', '0102'],
['0110', '0111', '0112']]],
[[['1000', '1001', '1002'],
['1010', '1011', '1012']],
[['1100', '1101', '1102'],
['1110', '1111', '1112']]]], dtype='<U4')
Далее, выделите вывод
>>> A1, A2 = (np.empty((a.shape[0], *a.shape), a.dtype) for a in (a1, a2))
Заполните, используя трансляцию
>>> A1[...] = a1[:, None]
>>> A2[...] = a2[None]
Объедините первые две оси
>>> A1, A2 = (A.reshape(-1, *A.shape[2:]) for A in (A1, A2))
Готово
>>> A1
array([[[['0000', '0001', '0002'],
['0010', '0011', '0012']],
[['0100', '0101', '0102'],
['0110', '0111', '0112']]],
[[['0000', '0001', '0002'],
['0010', '0011', '0012']],
[['0100', '0101', '0102'],
['0110', '0111', '0112']]],
[[['1000', '1001', '1002'],
['1010', '1011', '1012']],
[['1100', '1101', '1102'],
['1110', '1111', '1112']]],
[[['1000', '1001', '1002'],
['1010', '1011', '1012']],
[['1100', '1101', '1102'],
['1110', '1111', '1112']]]], dtype='<U4')
>>> A2
array([[[['0000', '0001', '0002'],
['0010', '0011', '0012']],
[['0100', '0101', '0102'],
['0110', '0111', '0112']]],
[[['1000', '1001', '1002'],
['1010', '1011', '1012']],
[['1100', '1101', '1102'],
['1110', '1111', '1112']]],
[[['0000', '0001', '0002'],
['0010', '0011', '0012']],
[['0100', '0101', '0102'],
['0110', '0111', '0112']]],
[[['1000', '1001', '1002'],
['1010', '1011', '1012']],
[['1100', '1101', '1102'],
['1110', '1111', '1112']]]], dtype='<U4')