Phần chỉ mục khó hiểu mà không làm mất thông tin thứ nguyên


98

Tôi đang sử dụng numpy và muốn lập chỉ mục một hàng mà không làm mất thông tin thứ nguyên.

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10,:]
xslice.shape   # >> (10,)  

Trong ví dụ này, xslice hiện là 1 chiều, nhưng tôi muốn nó là (1,10). Trong R, tôi sẽ sử dụng X [10,:, drop = F]. Có một cái gì đó tương tự trong numpy. Tôi không thể tìm thấy nó trong tài liệu và không thấy một câu hỏi tương tự được hỏi.

Cảm ơn!

Câu trả lời:


59

Nó có lẽ dễ thực hiện nhất x[None, 10, :]hoặc tương đương (nhưng dễ đọc hơn) x[np.newaxis, 10, :].

Về lý do tại sao nó không phải là mặc định, theo cá nhân tôi, tôi thấy rằng việc liên tục có các mảng với kích thước singleton sẽ gây khó chịu rất nhanh. Tôi đoán các nhà phát triển numpy cũng cảm thấy như vậy.

Ngoài ra, các mảng phát sóng numpy xử lý rất tốt, vì vậy thường có rất ít lý do để giữ lại kích thước của mảng mà lát cắt xuất phát. Nếu bạn đã làm vậy, thì những thứ như:

a = np.zeros((100,100,10))
b = np.zeros(100,10)
a[0,:,:] = b

hoặc sẽ không hoạt động hoặc sẽ khó thực hiện hơn nhiều.

(Hoặc ít nhất đó là suy đoán của tôi về lý do của nhà phát triển numpy đằng sau việc giảm thông tin thứ nguyên khi cắt)


6
@Lisa: x[None, 10]sẽ làm những gì bạn muốn.
naught101

Đúng vậy. Đặt chữ Nones của bạn bên cạnh các vết mờ bạn đang cắt.
Mad Physicist,

1
Ví dụ thiếu dấu ngoặc phụ cho bộ giá trị trong phép gán cho b; nó nên được b = np.zeros((100,10)).
Jerzy

Lý do sử dụng tổng cộng 3 chỉ số thay vì chỉ hai chỉ số là gì? Ý tôi là X[10,None](sử dụng mã của bạn làm ví dụ).
greenoldman

8
" thường có rất ít lý do để giữ lại kích thước của mảng " ... Chà, chắc chắn, hoàn toàn có thể làm np.matmul()hỏng@ phép nhân ( hoặc ) ma trận . Chỉ bị đốt cháy bởi điều này.
Jean-François Corbett

89

Một giải pháp khác là làm

X[[10],:]

hoặc là

I = array([10])
X[I,:]

Kích thước của một mảng được giữ nguyên khi việc lập chỉ mục được thực hiện bởi một danh sách (hoặc một mảng) các chỉ mục. Điều này là tốt vì nó cho bạn sự lựa chọn giữa giữ nguyên kích thước và ép chặt.


2
Điều này sao chép dữ liệu mảng
Mỗi

Đây không phải là luôn luôn như vậy. Xem: x = np.array([[1,2,3,4]]) nếu bạn sau đó cắt nó với x[[0],[1,2]] bạn sẽ có được một chiều array([2, 3]) Ý kiến của tôi là khi lựa chọn vectơ cột hoặc hàng nó tốt nhất để làm cho lát đơn giản và sau đó sử dụng np.reshape, Vì vậy, trong ví dụ của tôi nó sẽ lànp.reshape(x[0,[1,2]],[1,2])
Alexander

1
những người khác, cuối cùng hãy lưu ý đến dấu chấm phẩy - điều quan trọng là, X[[10]]sẽ được hiểu là X[10]và hình dạng sẽ nhỏ hơn; tương tự, X[[10, 20]] == X[10, 20]và hình dạng thậm chí còn nhỏ hơn
Ben Usman

1
Cảnh báo : không kết hợp cách lập chỉ mục này với chỉ lập chỉ mục số nguyên! Nếu bạn có ahình dạng (10, 20, 30), thì a[0, :, [0]]sẽ có hình dạng (1, 20), không phải (20, 1), bởi vì trong các chỉ mục sau này được phát sóng a[[0], :, [0]]thường không hoàn toàn như những gì bạn mong đợi! Ngược lại a[0, :, :1]sẽ cho bạn (20, 1)như mong đợi. Hơn nữa, hãy xem nhận xét ở trên cho trường hợp cạnh kỳ lạ với chỉ mục duy nhất. Nhìn chung, có vẻ như phương pháp này có quá nhiều trường hợp cạnh.
Ben Usman,

30

Tôi đã tìm thấy một vài giải pháp hợp lý.

1) sử dụng numpy.take(X,[10],0)

2) sử dụng lập chỉ mục kỳ lạ này X[10:11:, :]

Tốt nhất, đây nên là mặc định. Tôi không bao giờ hiểu tại sao kích thước lại bị giảm. Nhưng đó là một cuộc thảo luận cho numpy ...


1
'kích thước' bị loại bỏ khi lập chỉ mục danh sách Python alist[0]và được giữ lại khi cắt chúng.
hpaulj

4
Tùy chọn 2 (có thể được viết như slice(n, n+1)để trích xuất chỉ mục n) nên là câu trả lời được chấp nhận, vì nó là phương án duy nhất mở rộng tự nhiên cho trường hợp n chiều.
norok2

Tùy chọn 2 dường như có thể được viết bằng X[10:11, :]Python 3.7.5 (tức là không có dấu hai chấm thừa sau dấu 11)
Joe

6

Đây là một giải pháp thay thế tôi thích hơn. Thay vì lập chỉ mục với một số duy nhất, hãy lập chỉ mục với một phạm vi. Đó là, sử dụng X[10:11,:]. (Lưu ý rằng 10:11không bao gồm 11).

import numpy as np
X = np.zeros((100,10))
X.shape        # >> (100, 10)
xslice = X[10:11,:]
xslice.shape   # >> (1,10)

Điều này làm cho nó dễ hiểu với nhiều kích thước hơn, không phải Nonetung hứng và tìm ra trục nào để sử dụng chỉ mục nào. Cũng không cần phải ghi sổ kế toán thêm liên quan đến kích thước mảng, chỉ i:i+1đối với bất kỳ thứ igì bạn đã sử dụng trong lập chỉ mục thông thường.

b = np.ones((2, 3, 4))
b.shape # >> (2, 3, 4)
b[1:2,:,:].shape  # >> (1, 3, 4)
b[:, 2:3, :].shape .  # >> (2, 1, 4)


0

Điều này đặc biệt khó chịu nếu bạn đang lập chỉ mục bởi một mảng có thể có độ dài 1 trong thời gian chạy. Đối với trường hợp đó, có np.ix_:

some_array[np.ix_(row_index,column_index)]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.