Зріз індексу Numpy без втрати інформації про розмір


98

Я використовую numpy і хочу проіндексувати рядок, не втрачаючи інформацію про розмірність.

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

У цьому прикладі xslice тепер 1 вимір, але я хочу, щоб це було (1,10). У R я б використовував X [10,:, drop = F]. Чи є щось подібне в numpy. Я не зміг знайти його в документації і не побачив подібного запитання.

Дякую!

Відповіді:


59

Це, мабуть, найпростіше зробити x[None, 10, :]або еквівалентно (але більш читабельно) x[np.newaxis, 10, :].

Що стосується того, чому це не за замовчуванням, особисто я вважаю, що постійне наявність масивів з одномісними розмірами дуже швидко дратує. Я думаю, numpy розробники відчували те саме.

Крім того, numpy дуже добре обробляє масиви мовлення, тому, як правило, мало підстав зберігати розмірність масиву, з якого отримано зріз. Якщо ви це зробили, то такі речі:

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

або не буде працювати, або буде набагато складнішим для реалізації.

(Або, принаймні, це моє припущення щодо міркувань розробника numpy, за яким випадає інформація про розміри при нарізанні)


6
@Lisa: x[None, 10]робитиме те, що ти хочеш.
naught101

Так. Покладіть свої Nones поруч із димами, які ви рубите.
Божевільний фізик

1
У прикладі відсутні додаткові дужки для кортежу у присвоєнні b; це повинно бути b = np.zeros((100,10)).
Єжи

У чому причина використання всього 3 індексів замість лише двох? Я маю на увазі X[10,None](використовуючи ваш код як приклад).
greenoldman

8
" як правило, мало причин для збереження розмірності масиву " ... Ну це, безумовно, повністю і повністю зіпсує множення матриці ( np.matmul()або@ ). Просто від цього обпеклась.
Жан-Франсуа Корбетт

89

Інше рішення - це зробити

X[[10],:]

або

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

Розмірність масиву зберігається, коли індексація виконується списком (або масивом) індексів. Це приємно, оскільки це залишає вам вибір між збереженням розміру та стисканням.


2
Це копіює масив даних
За

Це не завжди так. Дивіться: x = np.array([[1,2,3,4]]) якщо ви потім наріжете його разом із x[[0],[1,2]] собою, отримаєте одновимірний. На array([2, 3]) мою думку, при виборі векторів стовпців або рядків найкраще зробити зріз простим, а потім використовувати np.reshape, отже, у моєму прикладі це будеnp.reshape(x[0,[1,2]],[1,2])
Олександр

1
інші, майте на увазі, зрештою, крапку з комою - це важливо, X[[10]]буде тлумачитися як, X[10]і форма буде меншою; аналогічно, X[[10, 20]] == X[10, 20]і форма ще менша
Бен Усман,

1
Попередження : не змішуйте цей спосіб індексації з просто цілочисельним індексуванням! Якщо ви мали aформу (10, 20, 30), тоді a[0, :, [0]]матимете форму (1, 20), ні (20, 1), бо в останніх транслюються індекси, на a[[0], :, [0]]які часто буває не зовсім те, що ви очікуєте! Тоді a[0, :, :1]як дадуть вам, (20, 1)як очікували. Більше того, див. Наведений вище коментар щодо дивного краю з одним індексом. Загалом, здається, що цей метод має занадто багато випадків краю.
Ben Usman

30

Я знайшов кілька розумних рішень.

1) використання numpy.take(X,[10],0)

2) використовувати цю дивну індексацію X[10:11:, :]

В ідеалі це має бути за замовчуванням. Я ніколи не розумів, чому розміри колись падають. Але це дискусія для numpy ...


1
"розміри" випадають під час індексації списків Python alist[0]і зберігаються при їх нарізуванні.
hpaulj

4
Варіант 2 (який можна записати як slice(n, n+1)для вилучення індексу n) повинен бути прийнятою відповіддю, оскільки він єдиний, який природно поширюється на n-вимірний випадок.
norok2

Здається, варіант 2 можна писати як X[10:11, :]у Python 3.7.5 (тобто без зайвої двокрапки після 11)
Джо

6

Ось альтернатива, яка мені більше подобається. Замість індексації одним числом індексуйте діапазоном. Тобто використовувати X[10:11,:]. (Зверніть увагу, що 10:11не включає 11).

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

Це полегшує розуміння з більшою кількістю розмірів, без Noneжонглювання та з'ясування, яку вісь використовувати, який індекс. Також не потрібно зайвого бухгалтерського обліку щодо розміру масиву, просто i:i+1для будь-якого, iщо ви б використовували при звичайному індексуванні.

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

Це особливо дратує, якщо ви індексуєте масив довжиною 1 під час виконання. Для цього випадку є np.ix_:

some_array[np.ix_(row_index,column_index)]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.