Сравнение двух массивов numpy на соответствие двум условиям

Aug 18 2020

Рассмотрим два массива numpy одинаковой формы, A и B, состоящие из единиц и нулей. Показан небольшой пример:

A = [[1 0 0 1]         B = [[0 0 0 0]
     [0 0 1 0]              [0 0 0 0]
     [0 0 0 0]              [1 1 0 0]
     [0 0 0 0]              [0 0 1 0]
     [0 0 1 1]]             [0 1 0 1]]

Теперь я хочу присвоить значения двум логическим переменным test1 и test2 следующим образом:

test1 : есть ли хотя бы один случай, когда 1 в Aстолбце и 1 в ТО ЖЕ Bстолбце имеют разницу строк ровно 1 или 2? Если да, то test1 = True, в противном случае - False.

В приведенном выше примере столбец 0 обоих массивов содержит единицы, разделенные двумя строками, поэтому test1 = True. (в столбце 2 есть и другие экземпляры, но это не имеет значения - нам нужен только один экземпляр.)

test2 : Имеют ли значения 1 Aи Bвсе разные адреса массива? Если да, то test2 = True, в противном случае - False.

В приведенном выше примере оба массива имеют [4,3] = 1, поэтому test2 = False.

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

Ответы

1 MadPhysicist Aug 18 2020 at 09:53

Вот простой способ проверить, есть ли у двух массивов запись в одном столбце, разделенная на один элемент (только в одном направлении):

(A[1:, :] * B[:-1, :]).any(axis=None)

Так ты можешь сделать

test1 = (A[1:, :] * B[:-1, :] + A[:-1, :] * B[1:, :]).any(axis=None) or (A[2:, :] * B[:-2, :] + A[:-2, :] * B[2:, :]).any(axis=None)

Второй тест можно выполнить, преобразовав местоположения в индексы, сложив их вместе и используя np.uniqueдля подсчета количества дубликатов. Дубликаты могут поступать только из одного и того же индекса в двух массивах, поскольку в массиве никогда не будет повторяющихся индексов. Мы можем еще больше ускорить расчет, используя flatnonzeroвместо nonzero:

test2 = np.all(np.unique(np.concatenate((np.flatnonzero(A), np.flatnonzero(B))), return_counts=True)[1] == 1)

Более эффективный тест будет использовать np.intersect1dаналогичным образом:

test2 = not np.intersect1d(np.flatnonzero(A), np.flatnonzero(B)).size
1 Ehsan Aug 18 2020 at 08:14

Вы можете использовать masked_arrays, а для второй задачи вы можете:

A_m = np.ma.masked_equal(A, 0)
B_m = np.ma.masked_equal(B, 0)

test2 = np.any((A_m==B_m).compressed())

И наивный способ выполнить первую задачу:

test1 = np.any((np.vstack((A_m[:-1],A_m[:-2],A_m[1:],A_m[2:]))==np.vstack((B_m[1:],B_m[2:],B_m[:-1],B_m[:-2]))).compressed())

вывод:

True
True
ArundeepChohan Aug 18 2020 at 09:56

Для Test2: вы можете просто проверить, нашли ли они аналогичные индексы, найденные для значения 1.

A =  np.array([[1, 0, 0, 1],[0, 0, 1, 0],[0, 0, 0, 0],[0, 0, 0, 0],[0, 0, 1, 1]])
B = np.array([[0, 0, 0, 0],[0, 0, 0, 0],[1, 1, 0, 0],[0, 0, 1, 0],[0, 1, 0, 1]])
print(len(np.intersect1d(np.flatnonzero(A==1),np.flatnonzero(B==1)))>0))