Python / Numpy — Получение индекса в основной массив из подмножества

#python #indexing #numpy

#python #индексирование #numpy

Вопрос:

Допустим, у меня есть массив numpy из 100 элементов. Я выполняю некоторые вычисления для подмножества этого массива — возможно, 20 элементов, где выполняется некоторое условие. Затем я выбираю индекс в этом подмножестве, как я могу (эффективно) восстановить индекс в первом массиве? Я не хочу выполнять вычисление для всех значений в a, потому что это дорого, поэтому я хочу выполнять это только там, где это требуется (где выполняется это условие).

Вот некоторый псевдокод, демонстрирующий, что я имею в виду («условием» здесь является понимание списка):

 a = np.arange(100)                                 # size = 100
b = some_function(a[[i for i in range(0,100,5)]])  # size = 20
Index = np.argmax(b)

# Index gives the index of the maximum value in b,
# but what I really want is the index of the element
# in a
  

Редактировать:

Я не очень четко выразился, поэтому привел более полный пример. Я надеюсь, это прояснит мою цель. Я чувствую, что есть какой-то умный и эффективный способ сделать это, без каких-либо циклов или поисков.

код:

 import numpy as np

def some_function(arr):
   return arr*2.0

a = np.arange(100)*2.                              # size = 100
b = some_function(a[[i for i in range(0,100,5)]])  # size = 20
Index = np.argmax(b)

print Index
# Index gives the index of the maximum value in b, but what I really want is
# the index of the element in a

# In this specific case, Index will be 19.  So b[19] is the largest value
# in b.  Now, what I REALLY want is the index in a.  In this case, that would
# 95 because some_function(a[95]) is what made the largest value in b.
print b[Index]
print some_function(a[95])

# It is important to note that I do NOT want to change a.  I will perform
# several calculations on SOME values of a, then return the indices of 'a' where
# all calculations meet some condition.
  

Комментарии:

1. Не уверен, правильно ли я понял ваш вопрос, но вы хотите узнать 20 индексов, вычисленных на втором шаге? Как к этому относится финал Index ?

2. @ejel: Чтобы попытаться объяснить это, давайте просто скажем, что some_function игнорирует входной массив и просто возвращает массив случайных переменных той же длины, что и входные данные. Тогда Index будет содержать индекс в b, который имеет наибольшее (случайное) число. Индекс в b действительно соответствует некоторому индексу в a, и этот индекс в a — это то, что я хочу.

Ответ №1:

Я не уверен, понял ли я ваш вопрос. Итак, поправьте меня, если я ошибаюсь.

Допустим, у вас есть что-то вроде

 a = np.arange(100)
condition = (a % 5 == 0) amp; (a % 7 == 0)
b = a[condition]
index = np.argmax(b)
# The following should do what you want
a[condition][index]
  

Или, если вы не хотите работать с масками:

 a = np.arange(100)
b_indices = np.where(a % 5 == 0)
b = a[b_indices]
index = np.argmax(b)
# Get the value of 'a' corresponding to 'index'
a[b_indices][index]
  

Это то, чего вы хотите?

Комментарии:

1. Я обновил свой вопрос, чтобы сделать его более понятным. В вашем коде a[condition][index] возвращает значение в a, но я хочу, чтобы ИНДЕКС был в a, так что a[INDEX] = a[condition][index] . Есть ли простой способ получить индекс из условия и индекса? Я предполагаю, что есть, но для меня это не очевидно.

2. np.arange(len(a))[condition][index] возможно?

3. @ScottB вы также могли бы сделать b_indices[index]

4. @AlokSinghal нам не нужен, np.where(a % 5 == 0)[0] поскольку np.where возвращает кортеж (в данном случае длиной один)?

5. @drevicko np.where() возвращает кортеж той же длины, что и размер массива, поэтому его всегда можно использовать в качестве индекса: a[np.where(a > 0)] работает для любого n-мерного массива a . Для одномерного использования первый элемент кортежа, возвращаемый np.where() , имеет тот же эффект. Но не так для многомерных массивов: docs.scipy.org/doc/numpy/user /…

Ответ №2:

Используйте вторичный массив, a_index , который является просто индексами элементов a, so a_index[3,5] = (3,5) . Затем вы можете получить исходный индекс как a_index[condition == True][Index] .

Если вы можете гарантировать, что b является представлением в a, вы можете использовать информацию о расположении памяти в двух массивах, чтобы найти перевод между индексами b и a.

Ответ №3:

Работает ли что-то подобное?

 mask = S == 1
ind_local = np.argmax(X[mask])

G = np.ravel_multi_index(np.where(mask), mask.shape)
ind_global = np.unravel_index(G[ind_local], mask.shape)

return ind_global
  

Это возвращает глобальный индекс argmax .

Ответ №4:

Обычно вы сохраняете индекс на основе условия, прежде чем вносить какие-либо изменения в массив. Вы используете индекс для внесения изменений.

Если a это ваш массив:

 >>> a = np.random.random((10,5))
>>> a
array([[ 0.22481885,  0.80522855,  0.1081426 ,  0.42528799,  0.64471832],
       [ 0.28044374,  0.16202575,  0.4023426 ,  0.25480368,  0.87047212],
       [ 0.84764143,  0.30580141,  0.16324907,  0.20751965,  0.15903343],
       [ 0.55861168,  0.64368466,  0.67676172,  0.67871825,  0.01849056],
       [ 0.90980614,  0.95897292,  0.15649259,  0.39134528,  0.96317126],
       [ 0.20172827,  0.9815932 ,  0.85661944,  0.23273944,  0.86819205],
       [ 0.98363954,  0.00219531,  0.91348196,  0.38197302,  0.16002007],
       [ 0.48069675,  0.46057327,  0.67085243,  0.05212357,  0.44870942],
       [ 0.7031601 ,  0.50889065,  0.30199446,  0.8022497 ,  0.82347358],
       [ 0.57058441,  0.38748261,  0.76947605,  0.48145936,  0.26650583]])
  

И b является ли ваш подмассив:

 >>> b = a[2:4,2:7]
>>> b
array([[ 0.16324907,  0.20751965,  0.15903343],
       [ 0.67676172,  0.67871825,  0.01849056]])
  

Можно показать, что a все еще владеет данными в b :

 >>> b.base
array([[ 0.22481885,  0.80522855,  0.1081426 ,  0.42528799,  0.64471832],
       [ 0.28044374,  0.16202575,  0.4023426 ,  0.25480368,  0.87047212],
       [ 0.84764143,  0.30580141,  0.16324907,  0.20751965,  0.15903343],
       [ 0.55861168,  0.64368466,  0.67676172,  0.67871825,  0.01849056],
       [ 0.90980614,  0.95897292,  0.15649259,  0.39134528,  0.96317126],
       [ 0.20172827,  0.9815932 ,  0.85661944,  0.23273944,  0.86819205],
       [ 0.98363954,  0.00219531,  0.91348196,  0.38197302,  0.16002007],
       [ 0.48069675,  0.46057327,  0.67085243,  0.05212357,  0.44870942],
       [ 0.7031601 ,  0.50889065,  0.30199446,  0.8022497 ,  0.82347358],
       [ 0.57058441,  0.38748261,  0.76947605,  0.48145936,  0.26650583]])
  

Вы можете вносить изменения в оба a и b двумя способами:

 >>> b =1
>>> b
array([[ 1.16324907,  1.20751965,  1.15903343],
       [ 1.67676172,  1.67871825,  1.01849056]])
>>> a
array([[ 0.22481885,  0.80522855,  0.1081426 ,  0.42528799,  0.64471832],
       [ 0.28044374,  0.16202575,  0.4023426 ,  0.25480368,  0.87047212],
       [ 0.84764143,  0.30580141,  1.16324907,  1.20751965,  1.15903343],
       [ 0.55861168,  0.64368466,  1.67676172,  1.67871825,  1.01849056],
       [ 0.90980614,  0.95897292,  0.15649259,  0.39134528,  0.96317126],
       [ 0.20172827,  0.9815932 ,  0.85661944,  0.23273944,  0.86819205],
       [ 0.98363954,  0.00219531,  0.91348196,  0.38197302,  0.16002007],
       [ 0.48069675,  0.46057327,  0.67085243,  0.05212357,  0.44870942],
       [ 0.7031601 ,  0.50889065,  0.30199446,  0.8022497 ,  0.82347358],
       [ 0.57058441,  0.38748261,  0.76947605,  0.48145936,  0.26650583]])
  

Или:

 >>> a[2:4,2:7] =1
>>> a
array([[ 0.22481885,  0.80522855,  0.1081426 ,  0.42528799,  0.64471832],
       [ 0.28044374,  0.16202575,  0.4023426 ,  0.25480368,  0.87047212],
       [ 0.84764143,  0.30580141,  1.16324907,  1.20751965,  1.15903343],
       [ 0.55861168,  0.64368466,  1.67676172,  1.67871825,  1.01849056],
       [ 0.90980614,  0.95897292,  0.15649259,  0.39134528,  0.96317126],
       [ 0.20172827,  0.9815932 ,  0.85661944,  0.23273944,  0.86819205],
       [ 0.98363954,  0.00219531,  0.91348196,  0.38197302,  0.16002007],
       [ 0.48069675,  0.46057327,  0.67085243,  0.05212357,  0.44870942],
       [ 0.7031601 ,  0.50889065,  0.30199446,  0.8022497 ,  0.82347358],
       [ 0.57058441,  0.38748261,  0.76947605,  0.48145936,  0.26650583]])
>>> b
array([[ 1.16324907,  1.20751965,  1.15903343],
       [ 1.67676172,  1.67871825,  1.01849056]])
  

Оба эквивалентны, и ни один из них не дороже другого. Поэтому, пока вы сохраняете индексы, b из a которых созданы, вы всегда можете просмотреть измененные данные в базовом массиве. Часто даже нет необходимости создавать подмассив при выполнении операций над фрагментами.

Редактировать

Предполагается, что some_func возвращает индексы в подмассиве, где выполняется некоторое условие.

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

 >>> def some_func(a):
...     return np.where(a>.8)
>>> a = np.random.random((10,4))
>>> a
array([[ 0.94495378,  0.55532342,  0.70112911,  0.4385163 ],
       [ 0.12006191,  0.93091941,  0.85617421,  0.50429453],
       [ 0.46246102,  0.89810859,  0.31841396,  0.56627419],
       [ 0.79524739,  0.20768512,  0.39718061,  0.51593312],
       [ 0.08526902,  0.56109783,  0.00560285,  0.18993636],
       [ 0.77943988,  0.96168229,  0.10491335,  0.39681643],
       [ 0.15817781,  0.17227806,  0.17493879,  0.93961027],
       [ 0.05003535,  0.61873245,  0.55165992,  0.85543841],
       [ 0.93542227,  0.68104872,  0.84750821,  0.34979704],
       [ 0.06888627,  0.97947905,  0.08523711,  0.06184216]])
>>> i_off, j_off = 3,2
>>> b = a[i_off:,j_off:]  #b
>>> i = some_func(b) #indicies in b
>>> i
(array([3, 4, 5]), array([1, 1, 0]))
>>> map(sum, zip(i,(i_off, j_off))) # indicies in a
[array([6, 7, 8]), array([3, 3, 2])]
  

Редактировать 2

Предполагается, что some_func возвращается измененная копия подмассива b .

Ваш пример будет выглядеть примерно так:

 import numpy as np

def some_function(arr):
   return arr*2.0

a = np.arange(100)*2.                              # size = 100
idx = np.array(range(0,100,5))
b = some_function(a[idx])  # size = 20
b_idx = np.argmax(b)
a_idx = idx[b_idx]  # indices in a translated from indices in b

print b_idx, a_idx
print b[b_idx], a[a_idx]

assert b[b_idx] == 2* a[a_idx]  #true!
  

Комментарии:

1. Да, я понимаю, как я могу использовать индексы подобным образом. Но для моего конкретного приложения это не то, что мне нужно. Вероятно, мой пример был не самым лучшим. Этот код переходит в функцию, и функции необходимо вернуть индексы в массив, где выполняются определенные условия. Таким образом, функция может быть чем-то вроде def some_function(arr) и она возвращает индексы в arr, которые соответствуют ряду условий. Я не намерен когда-либо изменять значения массива.

2. Смотрите мою правку. Я не вижу никакого способа получить индексы, которые определяют местоположение подмассива в его базовом массиве. Это было бы неплохо. Я думаю, вам просто нужно сохранить индексы (базового массива), которые вы использовали для создания подмассива, а затем применить их в качестве смещения к возвращаемым индексам (подмассива).

3. Если idx вместо этого является логическим массивом (выполняя что-то вроде idx = a% 5 ==0), то это не сработает, хотя с небольшой модификацией это могло бы сработать. Затем это заканчивается тем, что очень похоже на то, что сказал Алок. Как всегда, спасибо за предложения, Пол.