2011-03-17 83 views
6

Tôi đang tìm cách thực hiện thao tác sau trong python (numpy).Một phép nhân ma trận 3D không gian trong python

Matrix A is M x N x R 
Matrix B is N x 1 x R 

Ma trận nhân AB = C, trong đó C là ma trận M x 1 x R. Về cơ bản, mỗi lớp M x N của A (R của chúng) là ma trận nhân được độc lập với mỗi véc tơ N x 1 trong B. Tôi chắc chắn đây là một lớp lót. Tôi đã cố gắng sử dụng tensordot(), nhưng tôi dường như đã cho tôi câu trả lời mà tôi không mong đợi.

Tôi đã lập trình trong Igor Pro gần 10 năm rồi, và bây giờ tôi đang cố chuyển đổi các trang của nó sang python.

Trả lời

8

numpy.tensordot() là đúng cách để làm điều đó:

a = numpy.arange(24).reshape(2, 3, 4) 
b = numpy.arange(12).reshape(3, 1, 4) 
c = numpy.tensordot(a, b, axes=[1, 0]).diagonal(axis1=1, axis2=3) 

Sửa: Phiên bản đầu tiên của việc này là bị lỗi, và phiên bản này tính hơn han nó nên và ném đi hầu hết của nó. Có lẽ một vòng lặp Python trên trục cuối cùng là cách tốt hơn để làm điều đó.

Một Sửa: Tôi đã đi đến kết luận rằng numpy.tensordot()không giải pháp tốt nhất ở đây.

c = (a[:,:,None] * b).sum(axis=1) 

sẽ hiệu quả hơn (mặc dù khó nắm bắt hơn).

+0

Cảm ơn bạn đã liên hệ lại với tôi quá nhanh. Ít nhất, nó sẽ giúp tôi bắt đầu. Phần lớn các mã mà tôi sẽ cố gắng viết là ma trận hoạt động theo định hướng ... vì vậy tôi thực sự nên cố gắng hiểu những gì đang xảy ra ở đây. Điều đó đang được nói, có hai phần để mã gây nhầm lẫn cho tôi. Đầu tiên là gọi "trục" bên trong hàng chục. Tôi đang bối rối về những gì mà thực sự làm, trong đó, tôi sẽ mong đợi rằng một x b chỉ nên cung cấp cho bạn c (như cách tôi mô tả ở trên) mà không tuyên bố bất cứ điều gì đặc biệt. Có lẽ một khi tôi hiểu điều đó, tôi sẽ thấy tại sao nó là cần thiết để sử dụng .diagonal. – Jason

+0

Đó là thông minh ... Tôi không biết phải mất bao lâu để làm điều gì đó như thế này (có vẻ như bạn tạo một trục mới để nhân tổng hợp, sau đó về cơ bản tái kết hợp sau) Tôi thực sự đánh giá cao thời gian của bạn, cảm ơn nhiều! – Jason

+1

Dễ dàng nghĩ về điều này nếu thứ nguyên đầu tiên là danh sách ma trận (R), và thứ hai là kích thước ma trận chung (N) tức là hình dạng của một (4, 3, 2) và b là (4 , 3, 1). Phép toán nhân sau đó trở thành (a * b) .sum (trục = 1). (a * b) là phép nhân của các hàng và cột của mỗi phần tử trong ma trận, bạn cần tổng hợp mỗi hàng để lấy ma trận cuối cùng. Cũng giống như bạn nhiều ma trận bằng tay. –

10

Xin lỗi vì sự necromancy, nhưng câu trả lời này có thể được cải thiện đáng kể khi sử dụng np.einsum vô giá.

import numpy as np 

D,M,N,R = 1,2,3,4 
A = np.random.rand(M,N,R) 
B = np.random.rand(N,D,R) 

print np.einsum('mnr,ndr->mdr', A, B).shape 

Lưu ý rằng nó có một số ưu điểm: trước hết, nhanh chóng. np.einsum được tối ưu hóa thông thường, nhưng hơn nữa, np.einsum đủ thông minh để tránh tạo ra một mảng tạm thời MxNxR, nhưng thực hiện sự co lại trên N một cách trực tiếp.

Nhưng có lẽ quan trọng hơn, nó rất dễ đọc. Không có nghi ngờ rằng mã này là chính xác; và bạn có thể làm cho nó phức tạp hơn nhiều mà không gặp bất kỳ rắc rối nào.

Lưu ý rằng trục 'D' giả đơn giản có thể bị xóa khỏi B và báo cáo einsum nếu bạn muốn.

+0

tôi thấy rằng np.dot() cũng có thể làm một số hoạt động đa chiều, nhưng hoạt động theo một số quy tắc lạ. bạn có kiến ​​thức gì về nó không? – Martian2049

+0

kiến ​​thức của tôi có thể được tóm tắt tốt nhất là 'sử dụng einsum thay thế'. có thể tiết lộ chi tiết hơn một chút, nhưng 'rõ ràng là tốt hơn là ngầm' không bao giờ được áp dụng nhiều hơn, theo ý kiến ​​của tôi. –

Các vấn đề liên quan