Срез индекса Numpy без потери информации об измерении


100

Я использую 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 очень хорошо обрабатывает широковещательные массивы, поэтому обычно нет особых причин сохранять размерность массива, из которого был получен срез. Если да, то такие вещи, как:

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

либо не сработает, либо будет намного сложнее реализовать.

(Или, по крайней мере, это мое предположение о рассуждениях numpy dev об удалении информации о размерах при нарезке)


6
@ Лиза: x[None, 10]буду делать то, что ты хочешь.
naught101

Ага. Поместите ваш Nones рядом с тусклыми лампами, которые вы рубите.
Mad Physicist

1
В примере отсутствуют дополнительные скобки для кортежа в присвоении b; так и должно быть b = np.zeros((100,10)).
Jerzy

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

9
« обычно нет причин сохранять размерность массива » ... Ну, это, безусловно, полностью и полностью испортит умножение матриц ( np.matmul()или@ ). Просто обгорел от этого.
Жан-Франсуа Корбетт,

93

Другое решение - сделать

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)как положено. Более того, см. Комментарий выше для странного крайнего случая с одним индексом. В целом кажется, что у этого метода слишком много крайних случаев.
Бен Усман

30

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

1) использовать numpy.take(X,[10],0)

2) используйте эту странную индексацию X[10:11:, :]

В идеале это должно быть значение по умолчанию. Я так и не понял, зачем вообще сбрасываются габариты. Но это обсуждение numpy ...


2
«измерения» удаляются при индексировании списков Python alist[0]и сохраняются при их разрезании.
hpaulj

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

Вариант 2, похоже, можно записать как X[10:11, :]в Python 3.7.5 (то есть без лишнего двоеточия после 11)
Джо

7

Вот альтернатива, которая мне больше нравится. Вместо индексации с одним числом, индексируйте с диапазоном. То есть использовать 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.