Có một số cách bạn có thể thực hiện việc này. Việc đầu tiên mà nói đến cái tâm là np.einsum
:
# some fake data
gen = np.random.RandomState(0)
ni, nj, nk = 10, 20, 100
U = gen.randn(ni, nj, nk)
V = gen.randn(nj, nk)
res1 = np.zeros((ni, nk))
for k in range(nk):
res1[:,k] = U[:,:,k].dot(V[:,k])
res2 = np.einsum('ijk,jk->ik', U, V)
print(np.allclose(res1, res2))
# True
np.einsum
sử dụng Einstein notation thể hiện co thắt tensor. Trong biểu thức 'ijk,jk->ik'
ở trên, i
, j
và k
là các bảng con tương ứng với các kích thước khác nhau của U
và V
. Mỗi nhóm được phân cách bằng dấu phẩy tương ứng với một trong các toán hạng được chuyển đến np.einsum
(trong trường hợp này là U
có kích thước ijk
và V
có kích thước jk
). Phần '->ik'
chỉ định kích thước của mảng đầu ra. Bất kỳ kích thước với subscripts mà không có trong chuỗi đầu ra được tổng hợp hơn.
np.einsum
là cực kỳ hữu ích để thực hiện các cơn co thắt phức tạp, nhưng có thể mất một lúc để hoàn toàn quấn đầu của bạn xung quanh cách hoạt động. Bạn nên xem các ví dụ trong tài liệu (được liên kết ở trên).
Một số tùy chọn khác: nhân
Element-khôn ngoan với broadcasting, tiếp theo là tổng kết:
res3 = (U * V[None, ...]).sum(1)
inner1d
với một tải của transposing:
from numpy.core.umath_tests import inner1d
res4 = inner1d(U.transpose(0, 2, 1), V.T)
Một số tiêu chuẩn:
In [1]: ni, nj, nk = 100, 200, 1000
In [2]: %%timeit U = gen.randn(ni, nj, nk); V = gen.randn(nj, nk)
....: np.einsum('ijk,jk->ik', U, V)
....:
10 loops, best of 3: 23.4 ms per loop
In [3]: %%timeit U = gen.randn(ni, nj, nk); V = gen.randn(nj, nk)
(U * V[None, ...]).sum(1)
....:
10 loops, best of 3: 59.7 ms per loop
In [4]: %%timeit U = gen.randn(ni, nj, nk); V = gen.randn(nj, nk)
inner1d(U.transpose(0, 2, 1), V.T)
....:
10 loops, best of 3: 45.9 ms per loop
phần mềm gì bạn đang sử dụng để vẽ hình ảnh của bạn? – hlin117
@ hlin117 - Tôi đã sử dụng bài phát biểu chính. – Matteo