2012-02-27 41 views
16

tôi đi qua các kỳ quặc sau trong NumPy mà có thể hoặc không thể là một lỗi:Mảng dedpe có tên: Sự khác biệt giữa [0] ['tên'] và ['tên'] [0]?

import numpy as np 
dt = np.dtype([('tuple', (int, 2))]) 
a = np.zeros(3, dt) 
type(a['tuple'][0]) # ndarray 
type(a[0]['tuple']) # ndarray 

a['tuple'][0] = (1,2) # ok 
a[0]['tuple'] = (1,2) # ValueError: shape-mismatch on array construction 

tôi lại có thể ngờ rằng cả hai tùy chọn dưới đây làm việc. Ý kiến?

+1

Mẹo: khi đăng mã lên SO, vui lòng đăng bit chúng tôi có thể cắt và dán; trong trường hợp của Python, điều đó có nghĩa là sử dụng '#' cho các chú thích được chèn vào, không phải '%'. – DSM

+1

Những thứ vui nhộn, tôi cũng thấy điều này cho kết quả tương tự theo cách sử dụng 1.6.1 ... –

+0

Một chút lẻ, nhưng 'a [0] ['tuple'] [:] = (1,2)' hoạt động, có thể có một đầu mối ở đó ... –

Trả lời

1

Đây là lỗi ngược dòng, được sửa là NumPy PR #5947, với bản sửa lỗi trong 1.9.3.

8

tôi nhận được một lỗi khác so với bạn làm (sử dụng 1.7.0.dev NumPy):

ValueError: setting an array element with a sequence. 

nên giải thích dưới đây có thể không được chính xác cho hệ thống của bạn (hoặc thậm chí nó có thể là sai giải thích cho những gì tôi thấy).

Đầu tiên, hãy chú ý rằng chỉ mục liên tiếp của một structured array mang đến cho bạn một đối tượng numpy.void (xem data type docs)

import numpy as np 
dt = np.dtype([('tuple', (int, 2))]) 
a = np.zeros(3, dt) 
print type(a[0]) # = numpy.void 

Từ những gì tôi hiểu, void là loại giống như một danh sách Python vì nó có thể giữ các đối tượng khác nhau các kiểu dữ liệu, có ý nghĩa vì các cột trong một mảng có cấu trúc có thể là các kiểu dữ liệu khác nhau.

Nếu, thay vì lập chỉ mục, bạn cắt ra hàng đầu tiên, bạn nhận được một ndarray:

print type(a[:1]) # = numpy.ndarray 

Điều này giống như cách danh sách Python làm việc:

b = [1, 2, 3] 
print b[0] # 1 
print b[:1] # [1] 

Cắt lát trả về một phiên bản rút gọn của chuỗi gốc, nhưng việc lập chỉ mục trả về một phần tử (ở đây, một số int; ở trên, loại void).

Vì vậy, khi bạn cắt thành các hàng của mảng có cấu trúc, bạn sẽ mong đợi nó hoạt động giống như mảng ban đầu của bạn (chỉ với ít hàng hơn). Tiếp tục với ví dụ của bạn, bây giờ bạn có thể gán cho các 'tuple' cột của hàng đầu tiên:

a[:1]['tuple'] = (1, 2) 

Vì vậy, ... tại sao không a[0]['tuple'] = (1, 2) làm việc?

Vâng, hãy nhớ rằng a[0] trả về đối tượng void. Vì vậy, khi bạn gọi

a[0]['tuple'] = (1, 2) # this line fails 

bạn đang gán một tuple tới phần tử 'tuple' của đối tượng void. Lưu ý: mặc dù thực tế bạn đã gọi chỉ số này 'tuple', nó được lưu trữ dưới dạng ndarray:

print type(a[0]['tuple']) # = numpy.ndarray 

Vì vậy, điều này có nghĩa các tuple cần mà bị quăng vào một ndarray. Nhưng, đối tượng void không thể truyền bài tập (đây chỉ là phỏng đoán) vì nó có thể chứa các loại dữ liệu tùy ý nên không biết loại nào sẽ truyền.Để giải quyết vấn đề này, bạn có thể tự mình nhập dữ liệu vào:

a[0]['tuple'] = np.array((1, 2)) 

Thực tế là chúng tôi gặp phải lỗi trên cho bạn vì không truyền địa chỉ lỗi mà tôi nhận được --- không phải địa chỉ bạn nhận được .

Phụ Lục:

Vậy tại sao các công việc sau đây?

a[0]['tuple'][:] = (1, 2) 

Ở đây, bạn đang lập chỉ mục vào mảng đó khi bạn thêm [:], nhưng không có điều đó, bạn đang lập chỉ mục vào đối tượng void. Nói cách khác, a[0]['tuple'][:] nói "thay thế các phần tử của mảng được lưu trữ" (được xử lý bởi mảng), a[0]['tuple'] nói "thay thế mảng đã lưu trữ" (được xử lý bởi void).

Epilogue:

Lạ lùng thay, tiếp cận hàng (ví dụ: lập chỉ mục với 0) dường như thả các mảng cơ sở, nhưng nó vẫn cho phép bạn gán cho mảng cơ sở.

print a['tuple'].base is a # = True 
print a[0].base is a # = False 
a[0] = ((1, 2),) # `a` is changed 

lẽ void là không thực sự một mảng vì vậy nó không có một mảng cơ sở, ... nhưng sau đó tại sao nó có một thuộc tính base?

+0

tiền thưởng cho bạn – bmu

9

Tôi đã hỏi điều đó trong danh sách thảo luận. Travis Oliphant đã trả lời here.

Trích dẫn câu trả lời của mình:

The short answer is that this is not really a "normal" bug, but it could be considered a "design" bug (although the issues may not be straightforward to resolve). What that means is that it may not be changed in the short term --- and you should just use the first spelling.

Structured arrays can be a confusing area of NumPy for several of reasons. You've constructed an example that touches on several of them. You have a data-type that is a "structure" array with one member ("tuple"). That member contains a 2-vector of integers.

First of all, it is important to remember that with Python, doing

a['tuple'][0] = (1,2)

is equivalent to

b = a['tuple']; b[0] = (1,2)

In like manner,

a[0]['tuple'] = (1,2)

is equivalent to

b = a[0]; b['tuple'] = (1,2)

To understand the behavior, we need to dissect both code paths and what happens. You built a (3,) array of those elements in 'a'. When you write b = a['tuple'] you should probably be getting a (3,) array of (2,)-integers, but as there is currently no formal dtype support for (n,)-integers as a general dtype in NumPy, you get back a (3,2) array of integers which is the closest thing that NumPy can give you. Setting the [0] row of this object via

a['tuple'][0] = (1,2)

works just fine and does what you would expect.

On the other hand, when you type:

b = a[0]

you are getting back an array-scalar which is a particularly interesting kind of array scalar that can hold records. This new object is formally of type numpy.void and it holds a "scalar representation" of anything that fits under the "VOID" basic dtype.

For some reason:

b['tuple'] = [1,2]

is not working. On my system I'm getting a different error: TypeError: object of type 'int' has no len()

I think this should be filed as a bug on the issue tracker which is for the time being here: http://projects.scipy.org/numpy

The problem is ultimately the void->copyswap function being called in voidtype_setfields if someone wants to investigate. I think this behavior should work.

Giải thích cho điều này được đưa ra trong a numpy bug report.

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