In [321]: vec1=np.array([0,0.5,1,0.5]); vec2=np.array([2,0.5,1,0.5])
...: vec=np.transpose(np.stack((vec1,vec2)))
In [322]: vec1.shape
Out[322]: (4,)
In [323]: vec.shape
Out[323]: (4, 2)
Приятной особенностью функции stack
является то, что мы можем указать ось, пропуская транспонирование:
In [324]: np.stack((vec1,vec2), axis=1).shape
Out[324]: (4, 2)
Почему сочетание np.
и n.
?NameError: name 'n' is not defined
.Такие вещи почти отсылают меня прочь.
In [326]: mat = np.moveaxis(np.array([[[0,1,2,3],[0,1,2,3],[0,1,2,3],[0,1,2,3]],[[-1,2.,0
...: ,1.],[0,0,-1,2.],[0,1,-1,2.],[1,0.1,1,1]]]),0,2)
In [327]: mat.shape
Out[327]: (4, 4, 2)
In [328]: outvec=np.zeros((4,2))
...: for i in range(2):
...: outvec[:,i]=np.dot(mat[:,:,i],vec[:,i])
...:
In [329]: outvec
Out[329]:
array([[ 4. , -0.5 ],
[ 4. , 0. ],
[ 4. , 0.5 ],
[ 4. , 3.55]])
In [330]: # (4,4,2) (4,2) 'kji,ji->ki'
Из вашей петли расположение оси i
(размер 2) понятно - последнее во всех 3 массивах.Это оставляет одну ось для vec
, давайте назовем это j
.Он соединяется с последним (рядом с i
из mat
).k
переносится с mat
на outvec
.
In [331]: np.einsum('kji,ji->ki', mat, vec)
Out[331]:
array([[ 4. , -0.5 ],
[ 4. , 0. ],
[ 4. , 0.5 ],
[ 4. , 3.55]])
Часто строка einsum
записывается сама.Например, если mat
было описано как (m, n, k) и vec
как (n, k), с результатом (m, k)
В этом случае только j
измерение суммируется - оно появляется слева, но справа.Последнее измерение, i
в моей записи, не суммируется, потому что, если оно появляется с обеих сторон, так же, как и в вашей итерации.Я думаю об этом как о том, что нужно ехать.Он не является частью продукта dot
.
По сути, вы накладываетесь на последнее измерение, размер 2.Обычно мы ставим на первое, но вы транспонируете оба, чтобы поместить это последнее.
Ваша «неудачная» попытка выполняется и может быть воспроизведена как:
In [332]: np.einsum('ijk,il->ik', mat, vec)
Out[332]:
array([[12. , 4. ],
[ 6. , 1. ],
[12. , 4. ],
[ 6. , 3.1]])
In [333]: mat.sum(axis=1)*vec.sum(axis=1)[:,None]
Out[333]:
array([[12. , 4. ],
[ 6. , 1. ],
[12. , 4. ],
[ 6. , 3.1]])
j
и l
размеры не отображаются справа, поэтому они суммируются.Их можно суммировать до умножения, потому что они появляются только в одном слагаемом.Я добавил None
для включения трансляции (умножив ik
на i
).
np.einsum('ik,i->ik', mat.sum(axis=1), vec.sum(axis=1))
Если вы сложили на первом, и добавил измерение для vec
(2,4,1), это будет matmul
с (2,4,4) мат.mat @ vec[...,None]
.
In [337]: m1 = mat.transpose(2,0,1)
In [338]: m1@v1[...,None]
Out[338]:
array([[[ 4. ],
[ 4. ],
[ 4. ],
[ 4. ]],
[[-0.5 ],
[ 0. ],
[ 0.5 ],
[ 3.55]]])
In [339]: _.shape
Out[339]: (2, 4, 1)