Bagaimana cara mengakses kolom ke-i dari array multidimensi NumPy?

463

Misalkan saya punya:

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

test[i]membuat saya baris ke-i array (misalnya [1, 2]). Bagaimana saya bisa mengakses kolom ke - i ? (misalnya [1, 3, 5]). Juga, apakah ini operasi yang mahal?

lpl
sumber

Jawaban:

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

Demikian pula,

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

memungkinkan Anda mengakses baris. Ini dicakup dalam Bagian 1.4 (Pengindeksan) dari referensi NumPy . Ini cepat, setidaknya dalam pengalaman saya. Ini tentu jauh lebih cepat daripada mengakses setiap elemen dalam satu lingkaran.

mtrw
sumber
11
Ini membuat salinan, apakah mungkin untuk mendapatkan referensi, seperti saya mendapatkan referensi ke kolom, setiap perubahan dalam referensi ini tercermin dalam array asli.
harmands
@harmand Ini tidak membuat salinan, itu menciptakan tampilan.
rinspy
69

Dan jika Anda ingin mengakses lebih dari satu kolom sekaligus, Anda dapat melakukannya:

>>> 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]])
Akavall
sumber
meskipun tentu saja dalam hal ini Anda tidak hanya mengakses data; Anda mengembalikan salinan (pengindeksan mewah)
John Greenall
14
test[:,[0,2]]hanya mengakses data, misalnya, test[:, [0,2]] = somethingakan memodifikasi tes, dan tidak membuat array lain. Tetapi copy_test = test[:, [0,2]]apakah sebenarnya membuat salinan seperti yang Anda katakan.
Akavall
3
Ini membuat salinan, apakah mungkin untuk mendapatkan referensi, seperti saya mendapatkan referensi ke beberapa kolom, setiap perubahan dalam referensi ini tercermin dalam array asli?
harmands
@ harman786 Anda bisa menugaskan kembali array yang diubah ke yang lama.
Tamoghna Chowdhury
Mengapa test[:,[0,2]]hanya mengakses data sementara test[:, [0, 2]][:, [0, 1]]tidak? Tampaknya sangat tidak intuitif bahwa melakukan hal yang sama lagi memiliki hasil yang berbeda.
mapf
65
>>> test[:,0]
array([1, 3, 5])

perintah ini memberi Anda vektor baris, jika Anda hanya ingin mengulanginya, tidak apa-apa, tetapi jika Anda ingin hstack dengan beberapa array lain dengan dimensi 3xN, Anda akan memiliki

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

sementara

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

memberi Anda vektor kolom, sehingga Anda dapat melakukan operasi gabungan atau hstack.

misalnya

>>> np.hstack((test, test[:,[0]]))
array([[1, 2, 1],
       [3, 4, 3],
       [5, 6, 5]])
Awan
sumber
1
pengindeksan juga berfungsi dengan lebih dari satu kolom dalam satu waktu, jadi contoh terakhir dapat berupa pengujian [:, [0,1,0]] atau pengujian [:, [rentang (test.shape [1]) + [0]] ]
Lib
5
+1 untuk menentukan [:, [0]] vs [:, 0] untuk mendapatkan vektor kolom daripada vektor baris. Persis perilaku yang saya cari. Juga memberi +1 ke lib untuk catatan pengindeksan tambahan. Jawaban ini harus ada di atas sana dengan jawaban teratas.
dhj
1
Jawaban ini harus dipilih
Gusev Slava
22

Anda juga dapat mengubah posisi dan mengembalikan baris:

In [4]: test.T[0]
Out[4]: array([1, 3, 5])
Hotschke
sumber
Saya sudah melakukan ini beberapa saat sebelum mencari cara tercepat untuk mengakses kolom, saya bertanya-tanya apakah ini lebih cepat, lebih lambat, atau sama seperti tes [:, [0]]
José Chamorro
6

Untuk mendapatkan beberapa kolom independen, cukup:

> test[:,[0,2]]

Anda akan mendapatkan kolum 0 dan 2

Alberto Perez
sumber
2
Apa bedanya dengan jawaban Akavall ?
Semua Pekerja Sangat Penting
5

Meskipun pertanyaan telah dijawab, izinkan saya menyebutkan beberapa nuansa.

Katakanlah Anda tertarik pada kolom pertama array

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

Seperti yang sudah Anda ketahui dari jawaban lain, untuk mendapatkannya dalam bentuk "vektor baris" (array bentuk (3,)), Anda menggunakan slicing:

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

Untuk memeriksa apakah array adalah tampilan atau salinan array lain, Anda dapat melakukan hal berikut:

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

lihat ndarray.base .

Selain perbedaan yang jelas antara keduanya (modifikasi arr_c1_refakan mempengaruhi arr), jumlah byte-langkah untuk melintasi masing-masing berbeda:

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

lihat langkah . Mengapa ini penting? Bayangkan Anda memiliki array yang sangat besar, Abukan arr:

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

dan Anda ingin menghitung jumlah semua elemen kolom pertama, yaitu A_c1_ref.sum()atau A_c1_copy.sum(). Menggunakan versi yang disalin jauh lebih cepat:

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

Ini karena perbedaan jumlah langkah yang disebutkan sebelumnya:

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

Meskipun mungkin terlihat bahwa menggunakan salinan kolom lebih baik, itu tidak selalu benar karena alasan membuat salinan memerlukan waktu dan menggunakan lebih banyak memori (dalam hal ini butuh sekitar 200 μs untuk membuat A_c1_copy). Namun jika kita memerlukan salinan di tempat pertama, atau kita perlu melakukan banyak operasi berbeda pada kolom spesifik dari array dan kita setuju dengan mengorbankan memori untuk kecepatan, maka membuat salinan adalah cara yang harus dilakukan.

Jika kami tertarik bekerja sebagian besar dengan kolom, mungkin ide yang baik untuk membuat array kami dalam urutan kolom-utama ('F') alih-alih urutan baris-utama ('C') (yang merupakan default ), lalu lakukan pengiris seperti sebelumnya untuk mendapatkan kolom tanpa menyalinnya:

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

Sekarang, melakukan operasi penjumlahan (atau lainnya) pada tampilan kolom jauh lebih cepat.

Akhirnya saya perhatikan bahwa transposing array dan menggunakan slice baris sama dengan menggunakan slice kolom pada array asli, karena transposing dilakukan dengan hanya menukar bentuk dan langkah array asli.

A.T[1,:].strides[0]  # 40000
X Æ A-12
sumber
3
>>> test
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])

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

Kemudian Anda dapat memilih kolom 2 - 4 dengan cara ini:

>>> test[0:, 1:(ncol - 1)]
array([[1, 2, 3],
       [6, 7, 8]])
Mac
sumber