2012-08-13 16 views
6

Tôi đang làm việc với mảng Numpy đa chiều. Tôi đã nhận thấy một số hành vi không nhất quán khi truy cập các mảng này với các mảng chỉ mục khác. Ví dụ:Đặt chỉ mục mảng đa chiều nhiều lần hoán đổi lệnh trục

import numpy as np 
start = np.zeros((7,5,3)) 
a  = start[:,:,np.arange(2)] 
b  = start[0,:,np.arange(2)] 
c  = start[0,:,:2] 
print 'a:', a.shape 
print 'b:', b.shape 
print 'c:', c.shape 

Trong ví dụ này, tôi nhận được kết quả:

a: (7, 5, 2) 
b: (2, 5) 
c: (5, 2) 

này confuses me. Tại sao "b" và "c" không có cùng kích thước? Tại sao "b" hoán đổi trật tự trục, nhưng không phải "a"?

Tôi đã có thể thiết kế mã của mình xung quanh những mâu thuẫn này nhờ rất nhiều bài kiểm tra đơn vị, nhưng việc hiểu những gì đang diễn ra sẽ được đánh giá cao.

Để tham khảo, tôi đang sử dụng Python 2.7.3 và Numpy 1.6.2 qua MacPorts.

Trả lời

8

Về mặt cú pháp, điều này có vẻ không nhất quán, nhưng về mặt ngữ nghĩa, bạn đang thực hiện hai điều rất khác nhau ở đây. Trong định nghĩa của bạn là ab, bạn đang thực hiện advanced indexing, đôi khi được gọi là fancy indexing, trả về một bản sao dữ liệu. Trong định nghĩa của bạn là c, bạn đang thực hiện basic slicing, trả về chế độ xem dữ liệu.

Để biết sự khác biệt, nó giúp hiểu cách các chỉ mục được chuyển tới các đối tượng python. Dưới đây là một số ví dụ:

>>> class ShowIndex(object): 
...  def __getitem__(self, index): 
...   print index 
... 
>>> ShowIndex()[:,:] 
(slice(None, None, None), slice(None, None, None)) 
>>> ShowIndex()[...,:] 
(Ellipsis, slice(None, None, None)) 
>>> ShowIndex()[0:5:2,::-1] 
(slice(0, 5, 2), slice(None, None, -1)) 
>>> ShowIndex()[0:5:2,np.arange(3)] 
(slice(0, 5, 2), array([0, 1, 2])) 
>>> ShowIndex()[0:5:2] 
slice(0, 5, 2) 
>>> ShowIndex()[5, 5] 
(5, 5) 
>>> ShowIndex()[5] 
5 
>>> ShowIndex()[np.arange(3)] 
[0 1 2] 

Như bạn có thể thấy, có nhiều cấu hình khác nhau càng tốt. Đầu tiên, các vật phẩm riêng lẻ có thể được chuyển đi, hoặc các vật phẩm có thể được truyền đi. Thứ hai, các bộ dữ liệu có thể chứa các đối tượng slice, Ellipsis đối tượng, các số nguyên đơn giản hoặc các mảng numpy.

cắt cơ bản được kích hoạt khi bạn vượt qua chỉ đối tượng như int, slice, hoặc Ellipsis đối tượng, hoặc None (mà cũng giống như numpy.newaxis). Đây có thể được thông qua đơn lẻ hoặc trong một tuple. Đây là những gì các tài liệu có thể nói về cách cơ bản cắt được kích hoạt:

cắt cơ bản xảy ra khi obj là một đối tượng lát (được xây dựng bởi sự khởi đầu: stop: ký hiệu bước bên trong dấu ngoặc), một số nguyên, hoặc một tuple của các đối tượng slice và các số nguyên. Các đối tượng Ellipsis và newaxis có thể được xen kẽ với các đối tượng này. Để duy trì tương thích ngược với cách sử dụng phổ biến trong Numeric, việc cắt cơ bản cũng được khởi tạo nếu đối tượng chọn là bất kỳ chuỗi nào (như danh sách) chứa các đối tượng slice, đối tượng Ellipsis hoặc đối tượng newaxis, nhưng không có mảng nguyên hoặc khác trình tự nhúng.

Lập chỉ mục nâng cao được kích hoạt khi bạn vượt qua một mảng numpy, một chuỗi không tuple chỉ chứa số nguyên hoặc chứa bất kỳ loại nào hoặc một bộ chứa mảng hoặc chuỗi.

Để biết chi tiết về cách lập chỉ mục nâng cao và cắt cơ bản khác nhau, hãy xem tài liệu (được liên kết ở trên). Nhưng trong trường hợp đặc biệt này, nó rõ ràng với tôi những gì đang xảy ra.Nó phải làm với hành vi sau đây khi sử dụng lập chỉ mục từng phần:

Quy tắc để lập chỉ mục một phần là hình dạng của kết quả (hoặc hình dạng thông dịch của đối tượng được sử dụng trong cài đặt) là hình dạng của x với không gian con được lập chỉ mục được thay thế bằng không gian con lập chỉ mục được phát sóng. Nếu các không gian chỉ mục nằm ngay cạnh nhau, thì không gian lập chỉ mục được phát trực tiếp sẽ thay thế tất cả các không gian con được lập chỉ mục trong x. Nếu các không gian con lập chỉ mục được phân cách (bởi các đối tượng slice), thì không gian lập chỉ mục được phát sóng đầu tiên, tiếp theo là không gian con được chia cắt của x.

Trong định nghĩa của bạn về a, trong đó sử dụng chỉ mục nâng cao, bạn có hiệu quả thông qua các chuỗi [0, 1] trong như mục thứ ba của tuple, và vì không có phát sóng xảy ra (vì không có trình tự khác), tất cả mọi thứ xảy ra như mong đợi .

Trong định nghĩa của bạn về b, cũng sử dụng chỉ mục nâng cao, bạn có hiệu quả vượt qua hai trình tự, [0], mục đầu tiên (được chuyển đổi thành một mảng intp), và [0, 1], mục thứ ba. Hai mục này được phát cùng nhau và kết quả có cùng hình dạng với mục thứ ba. Tuy nhiên, kể từ khi phát sóng đã xảy ra, chúng tôi đang phải đối mặt với một vấn đề: nơi mà trong hình dạng mới tuple làm chúng tôi chèn hình dạng phát sóng? Theo tài liệu, hãy đọc

không có nơi nào rõ ràng để thả vào không gian con lập chỉ mục, do đó nó được gắn vào đầu.

Vì vậy, kết quả từ phát sóng được chuyển đến đầu bộ túp hình, tạo ra chuyển vị rõ ràng.

+0

Cảm ơn bạn đã giải thích chi tiết. Điều đó khá hữu ích. Các hành vi kỳ lạ do slicing + phát sóng lập chỉ mục vẫn còn bất ngờ đủ để nó khó khăn để mã xung quanh. Ví dụ: bắt đầu [0,:, np.arange (2)] = np.ones ((5,2)) có vẻ hợp pháp, nhưng do trục đặt lại nó không phải là – gbarter

+0

@gbarter Để giữ hình dạng ban đầu bạn phải sử dụng lát. Tức là, điều này sẽ hoạt động: 'start [: 1,:, np.arange (2)] = np.ones ((5,2))' – jorgeca

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