2013-08-21 65 views
7

Tôi có một mảng NumPy với một hình dạng của:Nhận nghĩa của 2D lát một mảng 3D trong NumPy

(11L, 5L, 5L) 

tôi muốn để tính toán giá trị trung bình trong 25 yếu tố của mỗi 'lát cắt' của mảng [ 0,:,:], [1,:,:] v.v., trả về 11 giá trị.

Có vẻ như ngớ ngẩn, nhưng tôi không thể tìm ra cách để thực hiện việc này. Tôi đã nghĩ rằng các chức năng mean(axis=x) sẽ làm điều này, nhưng tôi đã thử tất cả các kết hợp có thể có của trục và không ai trong số họ cho tôi kết quả tôi muốn.

Tôi rõ ràng có thể làm điều này bằng cách sử dụng vòng lặp for và cắt, nhưng chắc chắn có cách nào tốt hơn?

Trả lời

11

Sử dụng một tuple cho trục:

>>> a = np.arange(11*5*5).reshape(11,5,5) 
>>> a.mean(axis=(1,2)) 
array([ 12., 37., 62., 87., 112., 137., 162., 187., 212., 
     237., 262.]) 

Edit: This wor ks chỉ với phiên bản numpy 1.7+.

+2

Nó hoạt động? Người ta sẽ nghĩ như vậy cho 1,7 và sau đó, nhưng các tài liệu vẫn chỉ nói một trục. – Jaime

+1

Đã không nghĩ về phiên bản khó khăn, tôi có 1.7.1 và nó hoạt động. Nó không có trong tài liệu nhưng các thay đổi đang nói về ufuncs: http://www.softpedia.com/progChangelog/Numpy-Changelog-103892.html –

+2

Thật tuyệt, không biết điều này đã được thêm vào! – lmjohns3

4

Bạn có thể reshape(11, 25) và sau đó gọi mean chỉ một lần (nhanh hơn):

a.reshape(11, 25).mean(axis=1) 

Ngoài ra, bạn có thể gọi np.mean gấp đôi (khoảng 2X chậm hơn trên máy tính của tôi):

a.mean(axis=2).mean(axis=1) 
+1

Tôi nghĩ rằng đây là câu trả lời đơn giản nhất, mặc dù einsum có vẻ nhanh hơn. – lmjohns3

5

thể luôn luôn sử dụng np.einsum:

>>> a = np.arange(11*5*5).reshape(11,5,5) 
>>> np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
array([ 12, 37, 62, 87, 112, 137, 162, 187, 212, 237, 262]) 

Hoạt động trên các mảng nhiều chiều hơn (tất cả các phương pháp này sẽ nếu nhãn trục được thay đổi):

>>> a = np.arange(10*11*5*5).reshape(10,11,5,5) 
>>> (np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2])).shape 
(10, 11) 

nhanh hơn để khởi động:

a = np.arange(11*5*5).reshape(11,5,5) 

%timeit a.reshape(11, 25).mean(axis=1) 
10000 loops, best of 3: 21.4 us per loop 

%timeit a.mean(axis=(1,2)) 
10000 loops, best of 3: 19.4 us per loop 

%timeit np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
100000 loops, best of 3: 8.26 us per loop 

Cân tốt hơn một chút thì các phương pháp khác làm tăng kích thước mảng.

Sử dụng dtype=np.float64 không thay đổi timings trên đáng, vì vậy chỉ để kiểm tra lại:

a = np.arange(110*50*50,dtype=np.float64).reshape(110,50,50) 

%timeit a.reshape(110,2500).mean(axis=1) 
1000 loops, best of 3: 307 us per loop 

%timeit a.mean(axis=(1,2)) 
1000 loops, best of 3: 308 us per loop 

%timeit np.einsum('...ijk->...i',a)/(a.shape[-1]*a.shape[-2]) 
10000 loops, best of 3: 145 us per loop 

Ngoài ra một điều gì đó thú vị:

%timeit np.sum(a) #37812362500.0 
100000 loops, best of 3: 293 us per loop 

%timeit np.einsum('ijk->',a) #37812362500.0 
100000 loops, best of 3: 144 us per loop 
+1

Tôi nghĩ rằng tốc độ đến từ cuộc gọi của bạn tới 'np.einsum' bằng cách sử dụng bộ tích lũy' int', thay vì 'float' hoặc' double', không chắc chắn rằng 'np.mean' sử dụng. Đó là một điều rủi ro để làm với thống kê máy tính, vì bạn có thể tràn bộ tích lũy và nhận được kết quả rất sai. Việc đưa 'np.einsum' vào' dtype = np.float' hoặc 'dtype = np.double' sẽ làm cho phép tính mạnh mẽ hơn, và (tôi đoán ở đây) tương tự về hiệu năng với các hàm chuẩn. Tuy nhiên, 'np.einsum' vẫn là một chức năng cực kỳ thú vị, vì vậy bạn nhận +1 của mình ... – Jaime

+0

@Jamie. Đó cũng là suy nghĩ của tôi, nhưng trong thử nghiệm trực tiếp của tôi cho thấy rằng 'einsum' thực sự nhanh hơn cho bất kỳ kích thước và dtype nào.Tôi đã cập nhật bài đăng với thời gian 'np.double'. – Daniel

+0

@Ophion ... thật kỳ lạ là 'sum()' không cho tốc độ tương tự mà 'einsum()' ... được quan sát rất tốt ... thực sự là phương pháp nhanh thứ hai để tính giá trị trung bình sẽ là: 'timeit a.sum (axis = (1,2))/a.shape [-1] /a.shape [-2] ' –

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