Irisan indeks numpy tanpa kehilangan informasi dimensi

100

Saya menggunakan numpy dan ingin mengindeks baris tanpa kehilangan informasi dimensi.

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

Dalam contoh ini xslice sekarang menjadi 1 dimensi, tetapi saya menginginkannya menjadi (1,10). Di R, saya akan menggunakan X [10,:, drop = F]. Apa ada yang mirip di numpy. Saya tidak dapat menemukannya di dokumentasi dan tidak melihat pertanyaan serupa yang diajukan.

Terima kasih!

mindmatters
sumber

Jawaban:

59

Mungkin paling mudah untuk dilakukan x[None, 10, :]atau setara (tetapi lebih mudah dibaca) x[np.newaxis, 10, :].

Sejauh mengapa itu bukan default, secara pribadi, saya menemukan bahwa terus-menerus memiliki array dengan dimensi tunggal menjadi sangat cepat mengganggu. Kurasa para developer numpy merasakan hal yang sama.

Juga, numpy menangani array penyiaran dengan sangat baik, jadi biasanya ada sedikit alasan untuk mempertahankan dimensi dari array asal potongan. Jika ya, maka hal-hal seperti:

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

tidak akan berhasil atau akan jauh lebih sulit untuk diterapkan.

(Atau setidaknya itulah tebakan saya pada alasan dev yang numpy di balik menjatuhkan info dimensi saat mengiris)

Joe Kington
sumber
6
@ Lisa: x[None, 10]akan melakukan apa yang kamu inginkan.
n nothing101
Ya. Letakkan Nones Anda di samping redup yang Anda potong.
Fisikawan Gila
1
Contoh tidak ada tanda kurung tambahan untuk tupel dalam tugas ke b; seharusnya begitu b = np.zeros((100,10)).
Jerzy
Apa alasan menggunakan total 3 indeks, bukan hanya dua? Maksud saya X[10,None](menggunakan kode Anda sebagai contoh).
greenoldman
9
" Biasanya ada sedikit alasan untuk mempertahankan dimensi array " ... Yah, itu pasti, sama sekali, dan sepenuhnya mengacaukan perkalian matriks ( np.matmul()atau@ ). Baru saja terbakar oleh ini.
Jean-François Corbett
93

Solusi lain adalah melakukannya

X[[10],:]

atau

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

Dimensi array dipertahankan saat pengindeksan dilakukan oleh daftar (atau array) indeks. Ini bagus karena memberi Anda pilihan antara menjaga dimensi dan menekan.

gnebehay.dll
sumber
2
Ini menyalin data array
Per
Ini tidak selalu terjadi. Lihat: x = np.array([[1,2,3,4]]) jika Anda kemudian mengirisnya dengan x[[0],[1,2]] Anda mendapatkan satu dimensi array([2, 3]) Pendapat saya adalah ketika memilih vektor kolom atau baris yang terbaik adalah membuat potongannya sederhana dan kemudian menggunakan np.reshape, Jadi dalam contoh saya itu adalahnp.reshape(x[0,[1,2]],[1,2])
Alexander
1
yang lain, berhati-hatilah dengan titik koma pada akhirnya - itu penting, X[[10]]akan diartikan sebagai X[10]dan bentuk akan lebih kecil; serupa, X[[10, 20]] == X[10, 20]dan bentuknya bahkan lebih kecil
Ben Usman
1
Peringatan : jangan gabungkan cara pengindeksan ini hanya dengan pengindeksan integer! Jika Anda memiliki abentuk (10, 20, 30), maka a[0, :, [0]]akan memiliki bentuk (1, 20), bukan (20, 1), karena di indeks terakhir disiarkan a[[0], :, [0]]yang sering tidak seperti yang Anda harapkan! Padahal a[0, :, :1]akan memberi Anda (20, 1)seperti yang diharapkan. Selain itu, lihat komentar di atas untuk kasus tepi aneh dengan indeks tunggal. Secara keseluruhan, sepertinya metode ini memiliki terlalu banyak kasus tepi.
Ben Usman
30

Saya menemukan beberapa solusi yang masuk akal.

1) gunakan numpy.take(X,[10],0)

2) gunakan pengindeksan aneh ini X[10:11:, :]

Idealnya, ini harus menjadi default. Saya tidak pernah mengerti mengapa dimensi pernah dijatuhkan. Tapi itu pembahasan untuk numpy ...

mindmatters
sumber
2
'dimensi' dihilangkan saat mengindeks daftar Python, alist[0]dan disimpan saat memotongnya.
hpaulj
5
Opsi 2 (yang dapat ditulis slice(n, n+1)untuk mengekstraksi indeks n) harus menjadi jawaban yang diterima, karena ini adalah satu-satunya yang meluas secara alami ke kasus dimensi-n.
norok2
Opsi 2 tampaknya dapat ditulis seperti X[10:11, :]dalam Python 3.7.5 (yaitu tanpa titik dua tambahan setelah 11)
Joe
7

Inilah alternatif yang saya lebih suka. Alih-alih mengindeks dengan satu nomor, buat indeks dengan rentang. Artinya, gunakan X[10:11,:]. (Perhatikan bahwa 10:11tidak termasuk 11).

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

Ini membuatnya mudah untuk dipahami dengan lebih banyak dimensi juga, tidak ada Nonejuggling dan mencari tahu sumbu mana untuk menggunakan indeks mana. Juga tidak perlu melakukan pembukuan tambahan terkait ukuran array, hanya i:i+1untuk semua iyang akan Anda gunakan dalam pengindeksan biasa.

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)
Andrew Schwartz
sumber
0

Hal ini sangat mengganggu jika Anda mengindeks oleh array yang mungkin berukuran panjang 1 saat runtime. Untuk kasus itu, ada np.ix_:

some_array[np.ix_(row_index,column_index)]
Jthorpe
sumber