Как проверить, совпадают ли все значения в столбцах матрицы numpy?

Я хочу проверить, совпадают ли все значения в столбцах массива numpy/matrix. Я попытался использовать reduce ufunc equal, но, похоже, он не работает во всех случаях:

In [55]: a = np.array([[1,1,0],[1,-1,0],[1,0,0],[1,1,0]])

In [56]: a
Out[56]: 
array([[ 1,  1,  0],
       [ 1, -1,  0],
       [ 1,  0,  0],
       [ 1,  1,  0]])

In [57]: np.equal.reduce(a)
Out[57]: array([ True, False,  True], dtype=bool)

In [58]: a = np.array([[1,1,0],[1,0,0],[1,0,0],[1,1,0]])

In [59]: a
Out[59]: 
array([[1, 1, 0],
       [1, 0, 0],
       [1, 0, 0],
       [1, 1, 0]])

In [60]: np.equal.reduce(a)
Out[60]: array([ True,  True,  True], dtype=bool)

Почему средний столбец во втором случае также оценивается как True, тогда как он должен быть False?

Спасибо за любую помощь!

Ответы

Ответ 1

In [45]: a
Out[45]: 
array([[1, 1, 0],
       [1, 0, 0],
       [1, 0, 0],
       [1, 1, 0]])

Сравните каждое значение с соответствующим значением в первой строке:

In [46]: a == a[0,:]
Out[46]: 
array([[ True,  True,  True],
       [ True, False,  True],
       [ True, False,  True],
       [ True,  True,  True]], dtype=bool)

Столбец имеет общее значение, если все значения в этом столбце равны True:

In [47]: np.all(a == a[0,:], axis = 0)
Out[47]: array([ True, False,  True], dtype=bool)

Проблема с np.equal.reduce может быть замечена путем микроанализа, что происходит, когда оно применяется к [1, 0, 0, 1]:

In [49]: np.equal.reduce([1, 0, 0, 1])
Out[50]: True

Первые два элемента 1 и 0 проверяются на равенство, а результат False:

In [51]: np.equal.reduce([False, 0, 1])
Out[51]: True

Теперь False и 0 проверяются на равенство, а результат True:

In [52]: np.equal.reduce([True, 1])
Out[52]: True

Но True и 1 равны, поэтому общий результат True, что не является желаемым результатом.

Проблема заключается в том, что reduce пытается скопировать результат "локально", в то время как нам нужен "глобальный" тест, например np.all.

Ответ 2

Учитывая ubuntu удивительное объяснение, вы можете использовать reduce для решения своей проблемы, но вы должны применить его к bitwise_and и bitwise_or, а не к equal. Как следствие, это не будет работать с массивами с плавающей запятой:

In [60]: np.bitwise_and.reduce(a) == a[0]
Out[60]: array([ True, False,  True], dtype=bool)

In [61]: np.bitwise_and.reduce(b) == b[0]
Out[61]: array([ True, False,  True], dtype=bool)

В принципе, вы сравниваете бит каждого элемента в столбце. Идентичные биты не изменяются. Различные биты устанавливаются на ноль. Таким образом, любое число, которое имеет нуль вместо одного бита, изменит приведенное значение. bitwise_and не будет улавливать случай, когда биты вводятся, а не удаляются:

In [62]: c = np.array([[1,0,0],[1,0,0],[1,0,0],[1,1,0]])

In [63]: c
Out[63]: 
array([[1, 0, 0],
       [1, 0, 0],
       [1, 0, 0],
       [1, 1, 0]])

In [64]: np.bitwise_and.reduce(c) == c[0]
Out[64]: array([ True,  True,  True], dtype=bool)

Второй кумин явно ошибочен. Нам нужно использовать bitwise_or для захвата новых бит:

In [66]: np.bitwise_or.reduce(c) == c[0]
Out[66]: array([ True, False,  True], dtype=bool)

Итоговый ответ

In [69]: np.logical_and(np.bitwise_or.reduce(a) == a[0], np.bitwise_and.reduce(a) == a[0])
Out[69]: array([ True, False,  True], dtype=bool)

In [70]: np.logical_and(np.bitwise_or.reduce(b) == b[0], np.bitwise_and.reduce(b) == b[0])
Out[70]: array([ True, False,  True], dtype=boo

In [71]: np.logical_and(np.bitwise_or.reduce(c) == c[0], np.bitwise_and.reduce(c) == c[0])
Out[71]: array([ True, False,  True], dtype=bool)

Этот метод более ограничительный и менее элегантный, чем ubunut предложение использования all, но оно имеет то преимущество, что не создает огромные временные массивы, если ваш вход огромен. Временные массивы должны быть такими же большими, как первая строка вашей матрицы.

ИЗМЕНИТЬ

Основываясь на этом Q/A и ошибка, которую я подал с помощью numpy, решение предоставляется только потому, что ваш массив содержит нули и единицы. Как бы то ни было, показанные операции bitwise_and.reduce() могут возвращать только нуль или один, потому что bitwise_and.identity есть 1, а не -1. Я сохраняю этот ответ в надежде, что numpy фиксируется, и ответ становится действительным.

Edit

Похоже, на самом деле скоро произойдет изменение в numpy. Конечно, bitwise_and.identity, а также, возможно, необязательный параметр для уменьшения.

Edit

Хорошая новость. Идентификатор для np.bitwise_and был установлен в -1 с версии 1.12.0.