Как сравнить numpy массивы кортежей?

#numpy

#numpy

Вопрос:

Вот MWE, который иллюстрирует проблему, с которой я столкнулся:

 import numpy as np

arr = np.full((3, 3), -1, dtype="i,i")

doesnt_work = arr == (-1, -1)

n_arr = np.full((3, 3), -1, dtype=int)

works = n_arr == 10
 

arr предполагается, что это массив кортежей, но он ведет себя не так, как ожидалось.

works это массив логических значений, как и ожидалось, но doesnt_work есть False . Есть ли способ заставить numpy выполнять поэлементные сравнения для более сложных типов, или мне нужно прибегнуть к пониманию списка, сглаживанию и изменению формы?

Есть вторая проблема:

 f = arr[(0, 0)] == (-1, -1)
 

f является False , потому arr[(0,0)] что имеет тип numpy.void , а не кортеж. Таким образом, даже если бы сравнение по компонентам сработало, это дало бы неверный результат. Есть ли умный numpy способ сделать это или я должен просто прибегнуть к пониманию списка?

Комментарии:

1. Обратите внимание, что вы можете использовать Numpy views для переноса представления массива заданного типа в другой тип, чтобы сравнение работало (как объясняется в ответе Саймона).

2. numpy используется () для обозначения records структурированного массива, но это для того, чтобы отличать их от [] используемых для обозначения измерений. Таким образом, while () используется для ввода и отображения, вы должны использовать arr[0,0].item() для получения фактического tuple .

Ответ №1:

Обе проблемы на самом деле являются одной и той же проблемой! И оба связаны с пользовательским типом данных, который вы создали при указании dtype="i,i" .

Если вы запустите arr.dtype , вы получите dtype([('f0', '<i4'), ('f1', '<i4')]) . Это 2 целых числа со знаком, которые помещаются в один непрерывный блок памяти. Это не кортеж python. Таким образом, понятно, почему наивное сравнение завершается неудачей, поскольку (-1,-1) является кортежем python и не представлен в памяти так же, как тип данных numpy.

Однако, если вы сравните с a_comp = np.array((-1,-1), dtype="i,i") , вы получите точное поведение, которое вы ожидаете!

Вы можете прочитать больше о том, как работает пользовательский dtype, в документах numpy: https://numpy.org/doc/stable/reference/arrays.dtypes.html

О, и для решения того, что np.void есть: это исходит из идеи, что это пустой указатель c, что по сути означает, что это адрес непрерывного блока памяти неопределенного типа. Но, если вы (программист) знаете, что будет храниться в этой памяти (в данном случае два целых числа подряд), все в порядке, если вы будете осторожны (сравните с тем же пользовательским типом данных).