Numpy: для каждого элемента в одном массиве найдите индекс в другом массиве - PullRequest
34 голосов
/ 24 ноября 2011

У меня есть два 1D массива, x & y, один меньше другого. Я пытаюсь найти индекс каждого элемента у в х.

Я нашел два наивных способа сделать это, первый - медленный, а второй - интенсивный.

Медленный путь

indices= []
for iy in y:
    indices += np.where(x==iy)[0][0]

Память борова

xe = np.outer([1,]*len(x), y)
ye = np.outer(x, [1,]*len(y))
junk, indices = np.where(np.equal(xe, ye))

Есть ли более быстрый или менее ресурсоемкий подход? В идеале поиск должен использовать тот факт, что мы ищем не одну вещь в списке, а множество вещей, и, таким образом, он немного более поддается распараллеливанию. Бонусные баллы, если вы не предполагаете, что каждый элемент y на самом деле находится в x.

Ответы [ 7 ]

23 голосов
/ 15 апреля 2016

Я хочу предложить однострочное решение:

indices = np.where(np.in1d(x, y))[0]

В результате получается массив с индексами для массива x, который соответствует элементам из y, найденным в x.

Oneможно использовать без numpy.where, если это необходимо.

21 голосов
/ 24 ноября 2011

Как сказал Джо Кингтон, searchsorted () может искать элемент очень быстро.Чтобы иметь дело с элементами, которые не в x, вы можете проверить результат поиска с оригинальным y, и создать замаскированный массив:

import numpy as np
x = np.array([3,5,7,1,9,8,6,6])
y = np.array([2,1,5,10,100,6])

index = np.argsort(x)
sorted_x = x[index]
sorted_index = np.searchsorted(sorted_x, y)

yindex = np.take(index, sorted_index, mode="clip")
mask = x[yindex] != y

result = np.ma.array(yindex, mask=mask)
print result

результат будет:

[-- 3 1 -- -- 6]
17 голосов
/ 24 ноября 2011

Как насчет этого?

Предполагается, что каждый элемент y находится в x (и будет возвращать результаты даже для элементов, которых нет!), Но это намного быстрее.

import numpy as np

# Generate some example data...
x = np.arange(1000)
np.random.shuffle(x)
y = np.arange(100)

# Actually preform the operation...
xsorted = np.argsort(x)
ypos = np.searchsorted(x[xsorted], y)
indices = xsorted[ypos]
3 голосов
/ 06 ноября 2016

Я бы просто сделал это:

indices = np.where(y[:, None] == x[None, :])[1]

В отличие от вашей работы с памятью, здесь используется широковещательная передача для прямого генерирования двумерного логического массива без создания двумерных массивов для x и y.

3 голосов
/ 15 апреля 2016

Пакет numpy_indexed (отказ от ответственности: я его автор) содержит функцию, которая делает именно это:

import numpy_indexed as npi
indices = npi.indices(x, y, missing='mask')

В настоящее время он вызывает KeyError, если не все элементы в y присутствуют в x; но, возможно, мне стоит добавить kwarg, чтобы можно было пометить такие предметы -1 или чем-то еще.

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

РЕДАКТИРОВАТЬ: я изменил обработку пропущенных значений; «отсутствующий» kwarg теперь может быть установлен с помощью «поднимать», «игнорировать» или «маскировать». В последнем случае вы получите маскированный массив той же длины y, для которого вы можете вызвать .compressed (), чтобы получить действительные индексы. Обратите внимание, что есть также npi.contains (x, y), если это все, что вам нужно знать.

2 голосов
/ 12 сентября 2018

Я думаю, что это более ясная версия:

np.where(y.reshape(y.size, 1) == x)[1]

, чем indices = np.where(y[:, None] == x[None, :])[1].Вам не нужно транслировать х в 2D.

Этот тип решения мне показался лучшим, потому что в отличие от решений на основе searchsorted () или in1d (), которые были опубликованы здесь или в другом месте, вышеприведенное работает с дубликатами и не заботится, отсортировано ли что-либо.Это было важно для меня, потому что я хотел, чтобы х был в определенном пользовательском порядке.

0 голосов
/ 21 декабря 2017

Более прямое решение, которое не ожидает сортировки массива.

import pandas as pd
A = pd.Series(['amsterdam', 'delhi', 'chromepet', 'tokyo', 'others'])
B = pd.Series(['chromepet', 'tokyo', 'tokyo', 'delhi', 'others'])

# Find index position of B's items in A
B.map(lambda x: np.where(A==x)[0][0]).tolist()

Результат:

[2, 3, 3, 1, 4]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...