Предположим, у вас есть два двумерных массива A и B, и вы хотите проверить, где строка A содержится в B. Как вы делаете это наиболее эффективно, используя numpy?
Например.
a = np.array([[1,2,3],
[4,5,6],
[9,10,11]])
b = np.array([[4,5,6],
[4,3,2],
[1,2,3],
[4,8,9]])
map = [[0,2], [1,0]] # row 0 of a is at row index 2 of array B
Я знаю, как проверить, находится ли строка A в B, используя in1d
(тест на членство в массиве 2d numpy), но это не дает карты индексов.
Цель этой карты — (окончательно) объединить два массива вместе на основе некоторых столбцов. Конечно, можно делать это построчно, но это становится очень неэффективным, так как мои массивы имеют форму (50 миллионов, 20).
Альтернативой было бы использование функция слияния панд, но я бы хотел сделать это, используя только numpy.
К сожалению, нет, они float64 без каких-либо ограничений.
Могут ли быть дубликаты (одинаковые строки) в массиве?
Нет, в моем случае нет.
Подход №1
Вот один из views
. Использует np.argwhere
(документы) для возврата индексов элемента, который соответствует условию, в данном случае членству. -
def view1D(a, b): # a, b are arrays
a = np.ascontiguousarray(a)
b = np.ascontiguousarray(b)
void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
return a.view(void_dt).ravel(), b.view(void_dt).ravel()
def argwhere_nd(a,b):
A,B = view1D(a,b)
return np.argwhere(A[:,None] == B)
Подход №2
Вот еще один, который был бы O(n)
и, следовательно, намного лучше по производительности, особенно на больших массивах -
def argwhere_nd_searchsorted(a,b):
A,B = view1D(a,b)
sidxB = B.argsort()
mask = np.isin(A,B)
cm = A[mask]
idx0 = np.flatnonzero(mask)
idx1 = sidxB[np.searchsorted(B,cm, sorter=sidxB)]
return idx0, idx1 # idx0 : indices in A, idx1 : indices in B
Подход №3
Еще один O(n)
с использованием argsort()
-
def argwhere_nd_argsort(a,b):
A,B = view1D(a,b)
c = np.r_[A,B]
idx = np.argsort(c,kind='mergesort')
cs = c[idx]
m0 = cs[:-1] == cs[1:]
return idx[:-1][m0],idx[1:][m0]-len(A)
Пример запускается с теми же входными данными, что и раньше —
In [650]: argwhere_nd_searchsorted(a,b)
Out[650]: (array([0, 1]), array([2, 0]))
In [651]: argwhere_nd_argsort(a,b)
Out[651]: (array([0, 1]), array([2, 0]))
Вы можете воспользоваться автоматической трансляцией:
np.argwhere(np.all(a.reshape(3,1,-1) == b,2))
что приводит к
array([[0, 2],
[1, 0]])
Примечание для поплавков, которые вы можете заменить ==
на np.islclose()
Числа в массиве
ints
? Если да, то положительные? Если да, то есть ли у них диапазон, которым они могут быть ограничены?