Numpy: для каждого элемента в одном массиве найдите индекс в другом массиве

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

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

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

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.

Ответ 1

Как сказал Джо Кингтон, 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]

Ответ 2

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

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

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

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

Ответ 3

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

Он предполагает, что каждый элемент 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]

Ответ 4

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

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

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

Ответ 5

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

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

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

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

EDIT: изменил обработку отсутствующих значений; теперь "отсутствующий" kwarg можно установить с помощью "рейза", "игнорирования" или "маски". В последнем случае вы получите маскированный массив той же длины y, на который вы можете вызвать.compressed(), чтобы получить действительные индексы. Обратите внимание, что есть также npi.contains(x, y), если это все, что вам нужно знать.

Ответ 6

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

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

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

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

Ответ 7

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

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 items in A
B.map(lambda x: np.where(A==x)[0][0]).tolist()

Результат:

[2, 3, 3, 1, 4]

Ответ 8

Используйте эту строку кода: -

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