2013-02-13 3 views
15

Я хочу проверить, совпадают ли все значения в столбцах матрицы/матрицы numpy. Я пытался использовать reduce из ufuncequal, но это не похоже на работу во всех случаях:Как проверить, совпадают ли все значения в столбцах матрицы numpy?

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

Эта проблема прослушивает меня некоторое время. В то время как решение @ Ubuntu достаточно изящно, не очень приятно пытаться запустить это на 4096 ** 3 двойном массиве только для того, чтобы получить булевский массив, который запустил всю оставшуюся память. Я играл с чистой реализацией Python, используя 'np.equal (a, a [:, 0, None])', но это заканчивается той же проблемой. Поэтому я работаю над PR для numpy, чтобы добавить новую функцию 'np.same', чтобы обрабатывать именно такую ​​ситуацию. –

ответ

24
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) 

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

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.

+0

Отличный ответ. Есть ли способ сделать что-то подобное для больших массивов без создания массива масок? Возможно, это был первоначальный призыв OP к использованию 'reduce'. –

+1

Я не знаю ни одного метода NumPy, с помощью которого вы могли бы создать результат без tempory (boolean) массивов. Если вы работаете с очень большим массивом и памятью , вы можете «разбить» массив на куски (например, массивы, состоящие из строк N ) и протестировать каждую деталь отдельно. Затем объедините и протестируйте фигуры, суммируя результат, . – unutbu

+1

Вы также можете посмотреть в [numpy.memmap] (http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.memmap.html), или [Pytables] (http://www.pytables.org/) или [h5py] (http://www.h5py.org/) для хранения большого массива на диске, чтобы вы могли извлечь и работать с одним фрагментом массив на время, не требующее сохранения всего массива в памяти. Таким образом, у вас может быть больше места для временных массивов NumPy (обычно). – unutbu

7

удивительным объяснение, данное в 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) 

Второй coumn явно не так.Нам нужно использовать 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, но он имеет преимущество не создавая огромные временные массивы, если ваш вход огромен. Временные массивы должны быть только размером с первую строку вашей матрицы.

EDIT

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

Редактировать

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

Редактировать

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

Смежные вопросы