Làm cách nào để truy cập cột thứ i của mảng đa chiều NumPy?


463

Giả sử tôi có:

test = numpy.array([[1, 2], [3, 4], [5, 6]])

test[i]lấy cho tôi dòng thứ i của mảng (ví dụ [1, 2]). Làm thế nào tôi có thể truy cập cột thứ i ? (ví dụ [1, 3, 5]). Ngoài ra, đây sẽ là một hoạt động đắt tiền?

Câu trả lời:


687
>>> test[:,0]
array([1, 3, 5])

Tương tự

>>> test[1,:]
array([3, 4])

cho phép bạn truy cập các hàng. Điều này được trình bày trong Mục 1.4 (Lập chỉ mục) của tham chiếu NumPy . Điều này là nhanh chóng, ít nhất là theo kinh nghiệm của tôi. Nó chắc chắn nhanh hơn nhiều so với việc truy cập từng phần tử trong một vòng lặp.


11
Điều này tạo ra một bản sao, có thể có được tham chiếu, như tôi có được một tham chiếu đến một cột, bất kỳ thay đổi nào trong tham chiếu này được phản ánh trong mảng ban đầu.
hòa hợp vào

@harmands Điều này không tạo ra một bản sao, nó tạo ra một khung nhìn.
rinspy

69

Và nếu bạn muốn truy cập nhiều cột cùng một lúc, bạn có thể làm:

>>> test = np.arange(9).reshape((3,3))
>>> test
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> test[:,[0,2]]
array([[0, 2],
       [3, 5],
       [6, 8]])

mặc dù tất nhiên trong trường hợp này bạn không chỉ truy cập dữ liệu; bạn đang trả lại một bản sao (lập chỉ mục ưa thích)
John Greenall

14
test[:,[0,2]]chỉ cần truy cập dữ liệu, ví dụ, test[:, [0,2]] = somethingsẽ sửa đổi kiểm tra và không tạo ra một mảng khác. Nhưng copy_test = test[:, [0,2]]trên thực tế tạo ra một bản sao như bạn nói.
Akavall

3
Điều này tạo ra một bản sao, có thể có được tham chiếu, như tôi có được một tham chiếu đến một số cột, bất kỳ thay đổi nào trong tham chiếu này được phản ánh trong mảng ban đầu không?
hòa hợp vào

@ harman786 bạn chỉ có thể gán lại mảng đã sửa đổi thành mảng cũ.
Tamoghna Chowdhury

Tại sao test[:,[0,2]]chỉ truy cập dữ liệu trong khi test[:, [0, 2]][:, [0, 1]]không? Có vẻ rất không trực quan khi làm điều tương tự một lần nữa có kết quả khác nhau.
mapf

65
>>> test[:,0]
array([1, 3, 5])

lệnh này cung cấp cho bạn một vectơ hàng, nếu bạn chỉ muốn lặp qua nó, thì tốt thôi, nhưng nếu bạn muốn hstack với một số mảng khác có kích thước 3xN, bạn sẽ có

ValueError: all the input arrays must have same number of dimensions

trong khi

>>> test[:,[0]]
array([[1],
       [3],
       [5]])

cung cấp cho bạn một vectơ cột, để bạn có thể thực hiện thao tác ghép hoặc hstack.

ví dụ

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])

1
việc lập chỉ mục cũng hoạt động với nhiều hơn một cột một lần, vì vậy ví dụ cuối cùng có thể là test [:, [0,1,0]] hoặc test [:, [phạm vi (test.shape [1]) + [0]] ]
lib

5
+1 để chỉ định [:, [0]] so với [:, 0] để lấy vectơ cột thay vì vectơ hàng. Chính xác là hành vi tôi đang tìm kiếm. Ngoài ra +1 để lib cho ghi chú lập chỉ mục bổ sung. Câu trả lời này phải ở ngay trên đó với câu trả lời hàng đầu.
dhj

1
Câu trả lời này phải được chọn
Gusev Slava

22

Bạn cũng có thể hoán chuyển và trả về một hàng:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])

Tôi đã làm điều này một thời gian trước khi tìm cách nhanh nhất để truy cập các cột, tôi tự hỏi liệu điều này nhanh hơn, chậm hơn hay giống như thử nghiệm [:, [0]]
José Chamorro


5

Mặc dù câu hỏi đã được trả lời, hãy để tôi đề cập đến một số sắc thái.

Giả sử bạn quan tâm đến cột đầu tiên của mảng

arr = numpy.array([[1, 2],
                   [3, 4],
                   [5, 6]])

Như bạn đã biết từ các câu trả lời khác, để có được nó ở dạng "vectơ hàng" (mảng hình dạng (3,) ), bạn sử dụng cắt:

arr_c1_ref = arr[:, 1]  # creates a reference to the 1st column of the arr
arr_c1_copy = arr[:, 1].copy()  # creates a copy of the 1st column of the arr

Để kiểm tra xem một mảng là một khung nhìn hay một bản sao của một mảng khác, bạn có thể làm như sau:

arr_c1_ref.base is arr  # True
arr_c1_copy.base is arr  # False

xem ndarray.base .

Bên cạnh sự khác biệt rõ ràng giữa hai (sửa đổi arr_c1_refsẽ ảnh hưởngarr ), số bước byte để duyệt qua từng bước là khác nhau:

arr_c1_ref.strides[0]  # 8 bytes
arr_c1_copy.strides[0]  # 4 bytes

xem sải chân . Sao nó lại quan trọng? Hãy tưởng tượng rằng bạn có một mảng rất lớn Athay vìarr :

A = np.random.randint(2, size=(10000,10000), dtype='int32')
A_c1_ref = A[:, 1] 
A_c1_copy = A[:, 1].copy()

và bạn muốn tính tổng của tất cả các phần tử của cột đầu tiên, tức là A_c1_ref.sum()hoặc A_c1_copy.sum(). Sử dụng phiên bản sao chép nhanh hơn nhiều:

%timeit A_c1_ref.sum()  # ~248 µs
%timeit A_c1_copy.sum()  # ~12.8 µs

Điều này là do số bước tiến khác nhau được đề cập trước đó:

A_c1_ref.strides[0]  # 40000 bytes
A_c1_copy.strides[0]  # 4 bytes

Mặc dù có vẻ như việc sử dụng các bản sao cột là tốt hơn, nhưng không phải lúc nào cũng đúng vì lý do tạo một bản sao cần có thời gian và sử dụng nhiều bộ nhớ hơn (trong trường hợp này, tôi phải mất khoảng 200 Van để tạo ra A_c1_copy). Tuy nhiên, nếu chúng ta cần bản sao ở vị trí đầu tiên hoặc chúng ta cần thực hiện nhiều thao tác khác nhau trên một cột cụ thể của mảng và chúng ta vẫn ổn với việc hy sinh bộ nhớ cho tốc độ, thì việc tạo một bản sao là cách tốt nhất.

Trong trường hợp chúng tôi quan tâm đến việc làm việc chủ yếu với các cột, có thể là một ý tưởng tốt để tạo mảng của chúng tôi theo thứ tự cột chính ('F') thay vì thứ tự hàng chính ('C') (là mặc định ), và sau đó thực hiện cắt lát như trước để có được một cột mà không cần sao chép nó:

A = np.asfortranarray(A)  # or np.array(A, order='F')
A_c1_ref = A[:, 1]
A_c1_ref.strides[0]  # 4 bytes
%timeit A_c1_ref.sum()  # ~12.6 µs vs ~248 µs

Bây giờ, thực hiện thao tác tính tổng (hoặc bất kỳ thao tác nào khác) trên chế độ xem cột nhanh hơn nhiều.

Cuối cùng, tôi xin lưu ý rằng việc hoán chuyển một mảng và sử dụng tính năng cắt hàng cũng giống như sử dụng việc cắt cột trên mảng ban đầu, bởi vì việc hoán vị được thực hiện chỉ bằng cách hoán đổi hình dạng và các bước của mảng ban đầu.

A.T[1,:].strides[0]  # 40000

3
>>> test
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

>>> ncol = test.shape[1]
>>> ncol
5L

Sau đó, bạn có thể chọn cột thứ 2 - 4 theo cách này:

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])
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.