Наружное равенство выполняет работу для векторизованного решения -
In [90]: np.equal.outer(a[:,1:],a[:,1:]).any(axis=(1,3)).view('i1')
Out[90]:
array([[1, 1, 0, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[1, 0, 1, 1, 1]], dtype=int8)
Объяснение
По сути, мы выполняем сравнение парных равенств для всех строк и внутри каждогоСтрока парного сравнения на равенство с np.equal.outer(..)
. Сравнение на равенство представляет собой массив 4D. Таким образом, для среза a[:,1:]
, имеющего форму (m,n)
, мы получили бы массив сравнения равенств формы (m,n,m,n)
. Итак, затем мы ANY
уменьшаем его по осям - 1
и 3
, чтобы получить двумерный логический массив формы (m,m)
, и это наш окончательный результат после преобразования в массив int.
Альтернатива с явным расширением измерения была бы -
In [92]: (a[:,1:,None,None]==a[:,1:]).any(axis=(1,3)).view('i1')
Out[92]:
array([[1, 1, 0, 1, 1],
[1, 1, 0, 0, 0],
[0, 0, 1, 0, 1],
[1, 0, 0, 1, 1],
[1, 0, 1, 1, 1]], dtype=int8)
Таким образом, единственное изменение заключается в том, что мы добавляем новые оси для первой версии среза с помощью None/np.newaxis
для создания4D версия. Затем это сравнивается с исходной 2D-версией для получения логического массива по сравнению с 4D-равенством.