2013-09-05 38 views
9

Tôi có một mảng và tôi muốn tạo ra một mảng nhỏ hơn bằng cách quét một cửa sổ không chồng chéo 2x2 và nhận được tối đa. Dưới đây là một ví dụ:Cửa sổ tối đa ở mức tối đa

import numpy as np 

np.random.seed(123) 
np.set_printoptions(linewidth=1000,precision=3) 
arr = np.random.uniform(-1,1,(4,4)) 
res = np.zeros((2,2)) 
for i in xrange(res.shape[0]): 
    for j in xrange(res.shape[1]): 
     ii = i*2 
     jj = j*2 
     res[i][j] = max(arr[ii][jj],arr[ii+1][jj],arr[ii][jj+1],arr[ii+1][jj+1]) 

print arr 
print res 

Vì vậy, một ma trận như thế này:

[[ 0.393 -0.428 -0.546 0.103] 
[ 0.439 -0.154 0.962 0.37 ] 
[-0.038 -0.216 -0.314 0.458] 
[-0.123 -0.881 -0.204 0.476]] 

nên trở thành này:

[[ 0.439 0.962] 
[-0.038 0.476]]  

Làm thế nào tôi có thể làm điều này một cách hiệu quả hơn?

+0

Bạn có thể cho chúng tôi biết những gì bạn đã thử và tại sao nó không hoạt động? –

+0

mã ở trên thực hiện công việc cần thiết, nhưng điều này cần phải nhanh chóng và do đó tôi muốn loại bỏ vòng lặp cho –

+1

Cân nhắc sử dụng [NumBa] (http://numba.pydata.org/). Bạn có thể để vòng lặp đôi của bạn giống như nó, thêm khoảng 10 ký tự trong một trang trí và có được hiệu suất giống như C cho việc này. Dễ sử dụng out-of-the-box nếu bạn làm việc với Continuum Analytics ["Anaconda"] (https://store.continuum.io/cshop/anaconda/) phân phối của Python. – ely

Trả lời

9

Bạn có thể làm điều này:

print arr.reshape(2,2,2,2).swapaxes(1,2).reshape(2,2,4).max(axis=-1) 

[[ 0.439 0.962] 
[-0.038 0.476]] 

để giải thích bắt đầu với:

arr=np.array([[0.393,-0.428,-0.546,0.103], 
[0.439,-0.154,0.962,0.37,], 
[-0.038,-0.216,-0.314,0.458], 
[-0.123,-0.881,-0.204,0.476]]) 

Đầu tiên chúng ta muốn nhóm các trục thành các phần có liên quan.

tmp = arr.reshape(2,2,2,2).swapaxes(1,2) 
print tmp  

[[[[ 0.393 -0.428] 
    [ 0.439 -0.154]] 

    [[-0.546 0.103] 
    [ 0.962 0.37 ]]] 


[[[-0.038 -0.216] 
    [-0.123 -0.881]] 

    [[-0.314 0.458] 
    [-0.204 0.476]]]] 

Reshape một lần nữa để có được những nhóm dữ liệu chúng ta muốn:

tmp = tmp.reshape(2,2,4) 
print tmp 

[[[ 0.393 -0.428 0.439 -0.154] 
    [-0.546 0.103 0.962 0.37 ]] 

[[-0.038 -0.216 -0.123 -0.881] 
    [-0.314 0.458 -0.204 0.476]]] 

Cuối cùng lấy max dọc theo trục ngoái.

này có thể được khái quát hóa, đối với ma trận vuông, để:

k = arr.shape[0]/2 
arr.reshape(k,2,k,2).swapaxes(1,2).reshape(k,k,4).max(axis=-1) 

Tiếp theo ý kiến ​​của Jamie và Dougal chúng ta có thể khái quát này hơn nữa:

n = 2     #Height of window 
m = 2     #Width of window 
k = arr.shape[0]/n #Must divide evenly 
l = arr.shape[1]/m #Must divide evenly 
arr.reshape(k,n,l,m).max(axis=(-1,-3))    #Numpy >= 1.7.1 
arr.reshape(k,n,l,m).max(axis=-3).max(axis=-1)  #Numpy < 1.7.1 
+0

wow thực hiện điều đó. cảm ơn –

+1

Lưu ý rằng không có lý do nào các mảng cần phải là hình vuông, miễn là chúng có thể chia hết; bạn có thể thay đổi nó thành 'k = arr.shape [0]/n; l = arr.shape [1]/n; arr.reshape (k, n, l, n) .swapaxes (1, 2) .reshape (k, l, n * n) .max (trục = -1) ', tôi nghĩ vậy. – Dougal

+4

Lần thay đổi cuối cùng sau khi hoán đổi các trục sẽ kích hoạt bản sao của mảng đầy đủ, có thể tốn kém cho các mảng lớn.Tùy chọn tốt nhất là bỏ qua nó hoàn toàn và (sử dụng numpy> 1.7) cung cấp một tuple các trục tới '.max', nghĩa là' arr.reshape (2,2,2,2) .max (axis = (- 1, - 3)) 'Ngay cả khi bạn đang mắc kẹt với một phiên bản cũ của numpy, bạn sẽ sao chép một nửa dữ liệu nếu bạn thực hiện hai cuộc gọi đến' .max', tức là 'arr.reshape (2,2,2,2) .max (trục = -3) .max (trục = -1) '. – Jaime

2

Như tôi đã đề cập trong lĩnh vực bình luận, xem xét sử dụng NumBa. Bạn có thể để vòng lặp đôi của bạn giống như nó, thêm khoảng 10 ký tự trong một trang trí và có được hiệu suất giống như C cho việc này. Dễ sử dụng out-of-the-box nếu bạn làm việc với phân phối "Anaconda" của Continuum Analytics của Python.

Đây gần như là một trường hợp sử dụng hoàn hảo cho NumBa vì thuật toán này được thể hiện tự nhiên hơn nhiều với vòng lặp kép. Cách tiếp cận định hình lại khai thác các hoạt động mảng nhanh, nhưng nó rất khó đọc trừ khi bạn đã biết mục tiêu của chương trình. Nó rất mong muốn để lại các chức năng như thế này trong hình thức mở rộng và đạt được tốc độ bằng cách cho phép một cái gì đó khác chuyển đổi sang một ngôn ngữ cấp thấp sau khi thực tế.

+0

Tôi biết về tê giác và tốc độ tương ứng, nhưng tôi đang tìm kiếm một giải pháp gumpy tinh khiết. cảm ơn –

+4

Tôi đã tò mò về việc làm thế nào cũng tê sẽ thực sự làm về vấn đề này, vì vậy tôi đã cho nó một shot: http://nbviewer.ipython.org/c22a894f260d17876f01. Trong thử nghiệm của tôi về các phiên bản được sửa đổi một chút của các chức năng này, trên một ma trận 200x200, mã gốc mất 100ms, phiên bản numba JIT'd mất ~ 85ms, và phiên bản @ Ophion mất 0.5ms. Mở rộng quy mô, trên một numba ma trận 2k x 2k mất 8s và Ophion mất 64ms. ~ 150x tăng tốc có lẽ đáng giá một chút mất khả năng đọc; bạn có biết tôi đang làm điều gì sai ở đây khiến cho tê tê làm như vậy không? – Dougal

+0

Không chắc chắn, nhưng đối với loại hạt nhân này, nghe có vẻ rất khác thường. Tôi sẽ xem sổ ghi chép. – ely

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