2015-10-25 36 views
5

Tôi quan tâm đến việc tính toán một mảng NumPy lớn. Tôi có một mảng lớn A có chứa một loạt các số. Tôi muốn tính toán tổng các kết hợp khác nhau của những con số này. Cấu trúc của dữ liệu như sau:Vectorize phép nhân NumPy lớn

A = np.random.uniform(0,1, (3743, 1388, 3)) 
Combinations = np.random.randint(0,3, (306,3)) 
Final_Product = np.array([ np.sum(A*cb, axis=2) for cb in Combinations]) 

Câu hỏi của tôi là nếu có cách thanh lịch và hiệu quả hơn để tính toán điều này? Tôi thấy khó chịu khi làm việc với np.dot() khi có mảng 3-D.

Nếu được, hình dạng Final_Product lý tưởng nên là (3743, 306, 1388). Hiện tại, Final_Product có hình dạng (306, 3743, 1388), vì vậy tôi có thể định hình lại để đến đó.

Trả lời

5

np.dot() sẽ không cung cấp cho bạn kết quả mong muốn, trừ khi bạn liên quan đến các bước phụ có thể sẽ bao gồm reshaping. Dưới đây là một vectorized cách tiếp cận sử dụng np.einsum để làm điều đó một shot mà không cần bất kỳ bộ nhớ overhead thêm -

Final_Product = np.einsum('ijk,lk->lij',A,Combinations) 

Đối đầy đủ, đây là với np.dotreshaping như đã thảo luận trước đó -

M,N,R = A.shape 
Final_Product = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 

kiểm tra Runtime và xác minh đầu ra -

In [138]: # Inputs (smaller version of those listed in question) 
    ...: A = np.random.uniform(0,1, (374, 138, 3)) 
    ...: Combinations = np.random.randint(0,3, (30,3)) 
    ...: 

In [139]: %timeit np.array([ np.sum(A*cb, axis=2) for cb in Combinations]) 
1 loops, best of 3: 324 ms per loop 

In [140]: %timeit np.einsum('ijk,lk->lij',A,Combinations) 
10 loops, best of 3: 32 ms per loop 

In [141]: M,N,R = A.shape 

In [142]: %timeit A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 
100 loops, best of 3: 15.6 ms per loop 

In [143]: Final_Product =np.array([np.sum(A*cb, axis=2) for cb in Combinations]) 
    ...: Final_Product2 = np.einsum('ijk,lk->lij',A,Combinations) 
    ...: M,N,R = A.shape 
    ...: Final_Product3 = A.reshape(-1,R).dot(Combinations.T).T.reshape(-1,M,N) 
    ...: 

In [144]: print np.allclose(Final_Product,Final_Product2) 
True 

In [145]: print np.allclose(Final_Product,Final_Product3) 
True 
+0

Cảm ơn! Tôi cũng tìm thấy câu trả lời của @ajcr rất hữu ích. Sử dụng tensor tôi giảm một nửa thời gian sử dụng trong 'np.einsum' – Julien

+0

@Julien tôi thích giải pháp của ajcr! Tôi nghĩ đó là một phiên bản ngắn gọn về những gì 'dấu chấm' làm ở đây. – Divakar

5

Inst ead của dot bạn có thể sử dụng tensordot. Phương pháp hiện tại của bạn tương đương với:

np.tensordot(A, Combinations, [2, 1]).transpose(2, 0, 1) 

Lưu ý rằng transpose ở cuối để đặt các trục theo đúng thứ tự.

Giống như dot, chức năng tensordot có thể gọi xuống thư viện BLAS/LAPACK nhanh (nếu bạn đã cài đặt) và vì vậy sẽ hoạt động tốt cho các mảng lớn.

+0

Ngắn và đơn giản, tôi thích nó! – Divakar

+0

@Divakar: cảm ơn! Tôi vẫn thích 'einsum' mặc dù :-) –

+0

Tôi cũng vậy !! Tôi đã có cảm giác này khi 'einsum' đặt ra một mảng 3D, nó không hiệu quả như việc giảm thành một mảng' 2D' hoặc tốt nhất là một 'vô hướng'. – Divakar

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