Я пытаюсь написать операцию соединения между двумя массивами Numpy и был удивлен, обнаружив, что Numpy recfunctions.join_by
не обрабатывает повторяющиеся значения.
Подход, который я использую, заключается в использовании объединяемого столбца и поиске сопоставления индексов между ними. Судя по поиску в Интернете, большинство решений, использующих только Numpy, страдают от одной и той же проблемы: они не могут обрабатывать дубликаты (вы поймете, что я имею в виду, в разделе кода).
Я хочу полностью оставаться в библиотеке Numpy, если это вообще возможно, чтобы воспользоваться преимуществами векторизованных операций, поэтому в идеале нет собственного кода Python, Pandas (по другим причинам) или индексации numpy.
Ниже приведены несколько вопросов, которые я рассмотрел:
Как сопоставить один массив с другим в numpy?Найдите сопоставление индексов между двумя массивами numpyNumpy: для каждого элемента в одном массиве найдите индекс в другом массивеСопоставление индексов между двумя отсортированными частично перекрывающимися массивами numpy
Например, массивы X
и Y
, которые необходимо объединить по столбцу каждого из них, x
и y
соответственно.
Отображение определяется как, и f
— это то, что мне нужно
mapping = f(x, y)
x = y[mapping]
Так, например,
x = np.array([1,1,2,100])
y = np.array([1,2,3,4,5,6,7])
mapping = [0, 0, 1, -] # '-' indicates masked
x = y[mapping]
Просматривая подобные вопросы в Интернете, найдите сопоставление от x
до y
, где есть np.where(np.isin(x,y))
, которое дедуплицирует значения. Существует также np.searchsorted(x,y)
, который вообще не обрабатывает дубликаты в x
. Мне интересно, можно ли сделать что-то еще.
Ниже приведено неправильное сопоставление из-за дубликатов в x
.
import numpy as np
x = np.array([1,1,2,100])
y = np.array([1,2,3,4,5,6,7])
mapping = np.searchsorted(x, y)
# [0 2 3 3 3 3 3]
Это также неправильное отображение, поскольку отображение должно иметь ту же длину, что и x
.
import numpy as np
x = np.array([1,1,2,100])
y = np.array([1,2,3,4,5,6,7])
mapping = np.where(np.isin(x, y))[0]
# [0, 1, 2]
Как именно следует обращаться с дубликатами? Приведите рабочий пример с итерациями, если необходимо, чтобы мы дали четкое представление о том, что должно произойти.
Я не уверен, что правильно понял ваш вопрос, но вы можете использовать np.searchsorted
с обратными аргументами:
import numpy as np
x = np.array([1, 1, 2, 100])
y = np.array([1, 2, 3, 4, 5, 6, 7])
mapping = np.searchsorted(y, x)
mapping[mapping >= len(y)] = -1 # -1 to indicate "masked" values
print(mapping)
Распечатки:
[ 0 0 1 -1]
Используя np.isin()
, мы можем буквально создать маску, которая показывает нам, какие значения уже есть в другом массиве, а когда они у вас есть, вам нужно только выяснить индексы.
import numpy as np
# Arrays to be joined
x = np.array([1, 1, 2, 100, 4, 5, 3, 75])
y = np.array([1, 2, 3, 4, 5, 6, 7])
# Get mask with True and False values
mask = np.isin(x, y)
# [ True True True False True True True False]
# Get indices of every element
indices = np.searchsorted(y, x)
# [0 0 1 7 3 4 2 7]
# Match indices with mask
mapping = np.where(mask, indices, -1)
# [ 0 0 1 -1 3 4 2 -1]
Мы создаем маску, получаем индексы и затем сопоставляем индексы с маской. Значения, которых нет в y, получают значение -1
Это решение полностью остается внутри библиотеки Numpy.
Это
join_by
образует структурированный массив. Я не изучал этот конкретный вариант, но ониrecfunctiins
обычно создают массив нужного размера и типа. и заполните его по полю кодом Python. То есть они не компилируются, но избегают итераций по (обычно) большему измерению записи.