2015-06-18 13 views
20

Tôi đã xem xét tài liệu và cũng có các câu hỏi khác ở đây, nhưng có vẻ như tôi chưa bị treo trong các mảng cố định.Đặt một mảng có dải màu 2D

Tôi có một mảng NumPy, và vì lợi ích của đối số, để cho nó được định nghĩa như sau:

import numpy as np 
a = np.arange(100) 
a.shape = (10,10) 
# array([[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 
#  [10, 11, 12, 13, 14, 15, 16, 17, 18, 19], 
#  [20, 21, 22, 23, 24, 25, 26, 27, 28, 29], 
#  [30, 31, 32, 33, 34, 35, 36, 37, 38, 39], 
#  [40, 41, 42, 43, 44, 45, 46, 47, 48, 49], 
#  [50, 51, 52, 53, 54, 55, 56, 57, 58, 59], 
#  [60, 61, 62, 63, 64, 65, 66, 67, 68, 69], 
#  [70, 71, 72, 73, 74, 75, 76, 77, 78, 79], 
#  [80, 81, 82, 83, 84, 85, 86, 87, 88, 89], 
#  [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]]) 

bây giờ tôi muốn chọn hàng và cột của a xác định bởi vectơ n1n2. Như một ví dụ:

n1 = range(5) 
n2 = range(5) 

Nhưng khi tôi sử dụng:

b = a[n1,n2] 
# array([ 0, 11, 22, 33, 44]) 

Sau đó, chỉ các yếu tố đường chéo thứ năm đầu tiên được lựa chọn, không phải là khối toàn bộ 5x5. Giải pháp tôi đã tìm thấy là làm như sau:

b = a[n1,:] 
b = b[:,n2] 
# array([[ 0, 1, 2, 3, 4], 
#  [10, 11, 12, 13, 14], 
#  [20, 21, 22, 23, 24], 
#  [30, 31, 32, 33, 34], 
#  [40, 41, 42, 43, 44]]) 

Nhưng tôi chắc chắn có cách để thực hiện tác vụ đơn giản này chỉ trong một lệnh.

Trả lời

17

Bạn đã có một số ví dụ hay về cách làm những gì bạn muốn. Tuy nhiên, nó cũng hữu ích để hiểu những gì đang xảy ra và tại sao mọi thứ hoạt động theo cách họ làm. Có một vài quy tắc đơn giản sẽ giúp bạn trong tương lai.

Có sự khác biệt lớn giữa lập chỉ mục "ưa thích" (tức là sử dụng danh sách/chuỗi) và lập chỉ mục "bình thường" (sử dụng một lát). Lý do cơ bản có liên quan đến việc mảng có thể được "thường xuyên bị xáo trộn" hay không và do đó có cần phải thực hiện một bản sao hay không. Do đó, các chuỗi tùy ý phải được xử lý khác nhau, nếu chúng ta muốn có thể tạo ra "các khung nhìn" mà không tạo bản sao.

Trong trường hợp của bạn:

import numpy as np 

a = np.arange(100).reshape(10,10) 
n1, n2 = np.arange(5), np.arange(5) 

# Not what you want 
b = a[n1, n2] # array([ 0, 11, 22, 33, 44]) 

# What you want, but only for simple sequences 
# Note that no copy of *a* is made!! This is a view. 
b = a[:5, :5] 

# What you want, but probably confusing at first. (Also, makes a copy.) 
# np.meshgrid and np.ix_ are basically equivalent to this. 
b = a[n1[:,None], n2[None,:]] 

indexing Fancy với chuỗi 1D về cơ bản là tương đương với nén chúng lại với nhau và lập chỉ mục với kết quả.

print "Fancy Indexing:" 
print a[n1, n2] 

print "Manual indexing:" 
for i, j in zip(n1, n2): 
    print a[i, j] 

Tuy nhiên, nếu chuỗi bạn đang lập chỉ mục với trận đấu chiều của mảng bạn đang lập chỉ mục (2D, trong trường hợp này), Các chỉ số được xử lý khác nhau. Thay vì "nén hai" lại với nhau, hãy sử dụng các chỉ mục như mặt nạ.

Nói cách khác, a[[[1, 2, 3]], [[1],[2],[3]]] được xử lý hoàn toàn khác với a[[1, 2, 3], [1, 2, 3]], vì chuỗi/mảng mà bạn đang truyền vào là hai chiều.

In [4]: a[[[1, 2, 3]], [[1],[2],[3]]] 
Out[4]: 
array([[11, 21, 31], 
     [12, 22, 32], 
     [13, 23, 33]]) 

In [5]: a[[1, 2, 3], [1, 2, 3]] 
Out[5]: array([11, 22, 33]) 

Để được chính xác hơn một chút,

a[[[1, 2, 3]], [[1],[2],[3]]] 

được xử lý một cách chính xác như:

i = [[1, 1, 1], 
    [2, 2, 2], 
    [3, 3, 3]]) 
j = [[1, 2, 3], 
    [1, 2, 3], 
    [1, 2, 3]] 
a[i, j] 

Nói cách khác, cho dù đầu vào là một vector hàng/cột được một cách viết tắt về cách các chỉ số nên lặp lại trong việc lập chỉ mục.


np.meshgridnp.ix_ nhiều cách chỉ convienent để biến chuỗi 1D của bạn vào các phiên bản 2D của họ cho chỉ mục:

In [6]: np.ix_([1, 2, 3], [1, 2, 3]) 
Out[6]: 
(array([[1], 
     [2], 
     [3]]), array([[1, 2, 3]])) 

Tương tự như vậy (đối số sparse sẽ làm cho nó giống với ix_ trên):

In [7]: np.meshgrid([1, 2, 3], [1, 2, 3], indexing='ij') 
Out[7]: 
[array([[1, 1, 1], 
     [2, 2, 2], 
     [3, 3, 3]]), 
array([[1, 2, 3], 
     [1, 2, 3], 
     [1, 2, 3]])] 
+0

Cảm ơn bạn đã giải thích. Trở nên quen thuộc hơn với MATLAB, tôi tìm thấy quy ước đặt cược trong một chút kỳ quặc, nhưng ít nhất bây giờ tôi biết làm thế nào để làm điều đó đúng. – CrossEntropy

6

Bạn có thể sử dụng np.meshgrid để cung cấp cho các n1, n2 mảng hình dạng thích hợp để thực hiện việc lập chỉ mục mong muốn:

In [104]: a[np.meshgrid(n1,n2, sparse=True, indexing='ij')] 
Out[104]: 
array([[ 0, 1, 2, 3, 4], 
     [10, 11, 12, 13, 14], 
     [20, 21, 22, 23, 24], 
     [30, 31, 32, 33, 34], 
     [40, 41, 42, 43, 44]]) 

Hoặc, mà không meshgrid:

In [117]: a[np.array(n1)[:,np.newaxis], np.array(n2)[np.newaxis,:]] 
Out[117]: 
array([[ 0, 1, 2, 3, 4], 
     [10, 11, 12, 13, 14], 
     [20, 21, 22, 23, 24], 
     [30, 31, 32, 33, 34], 
     [40, 41, 42, 43, 44]]) 

Có một tương tự ví dụ với giải thích về cách hoạt động của tài liệu này integer array indexing trong tài liệu.

Xem thêm công thức Cookbook Picking out rows and columns.

8

Một cách nhanh chóng để xây dựng các chỉ số mong muốn là sử dụng chức năng np.ix_:

>>> a[np.ix_(n1, n2)] 
array([[ 0, 1, 2, 3, 4], 
     [10, 11, 12, 13, 14], 
     [20, 21, 22, 23, 24], 
     [30, 31, 32, 33, 34], 
     [40, 41, 42, 43, 44]]) 

này cung cấp một cách thuận tiện để xây dựng một lưới mở cửa từ trình tự của các chỉ số.

0

Dường như trường hợp sử dụng cho câu hỏi cụ thể của bạn sẽ xử lý thao tác hình ảnh n. Trong phạm vi mà bạn đang sử dụng ví dụ của bạn để chỉnh sửa mảng numpy phát sinh từ hình ảnh, bạn có thể sử dụng thư viện hình ảnh Python (PIL).

# Import Pillow: 
from PIL import Image 

# Load the original image: 
img = Image.open("flowers.jpg") 

# Crop the image 
img2 = img.crop((0, 0, 5, 5)) 

Đối tượng img2 là mảng mờ của hình ảnh đã cắt.

Bạn có thể đọc thêm về thao tác hình ảnh tại đây với Pillow package (một ngã ba thân thiện với người dùng trên gói PIL):

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