Как проверить, равны ли все строки в numpy

В numpy, есть ли хороший идиоматический способ тестирования, если все строки равны в массиве 2d?

Я могу сделать что-то вроде

np.all([np.array_equal(M[0], M[i]) for i in xrange(1,len(M))])

Кажется, что смешивает списки python с массивами numpy, которые являются уродливыми и предположительно также медленными.

Есть ли более приятный способ?

Ответ 1

Один из способов - вычесть первую строку из всех строк вашего массива и проверить, что каждая запись равна 0:

>>> a = np.arange(9).reshape(3, 3)
>>> b = np.ones((3, 3))
>>> ((a - a[0]) == 0).all()
False
>>> ((b - b[0]) == 0).all()
True

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

Несколько более быстрый метод с использованием одной и той же базовой идеи:

(arr == arr[0]).all()

то есть. что каждая строка arr равна первой строке arr.

Ответ 2

Просто проверьте, если число, если уникальные элементы массива: 1:

>>> arr = np.array([[1]*10 for _ in xrange(5)])
>>> len(np.unique(arr)) == 1
True

Забастовкa >

Решение, основанное на unutbu answer:

>>> arr = np.array([[1]*10 for _ in xrange(5)])
>>> np.all(np.all(arr == arr[0,:], axis = 1))
True

Одна проблема с вашим кодом заключается в том, что вы сначала создаете весь список перед тем, как применить к нему np.all(). Из-за этого в вашей версии не происходит короткого замыкания, вместо этого было бы лучше, если бы вы использовали Python all() с выражением генератора:

Сравнение времени:

>>> M = arr = np.array([[3]*100] + [[2]*100 for _ in xrange(1000)])
>>> %timeit np.all(np.all(arr == arr[0,:], axis = 1))
1000 loops, best of 3: 272 µs per loop
>>> %timeit (np.diff(M, axis=0) == 0).all()
1000 loops, best of 3: 596 µs per loop
>>> %timeit np.all([np.array_equal(M[0], M[i]) for i in xrange(1,len(M))])
100 loops, best of 3: 10.6 ms per loop
>>> %timeit all(np.array_equal(M[0], M[i]) for i in xrange(1,len(M)))
100000 loops, best of 3: 11.3 µs per loop

>>> M = arr = np.array([[2]*100 for _ in xrange(1000)])
>>> %timeit np.all(np.all(arr == arr[0,:], axis = 1))
1000 loops, best of 3: 330 µs per loop
>>> %timeit (np.diff(M, axis=0) == 0).all()
1000 loops, best of 3: 594 µs per loop
>>> %timeit np.all([np.array_equal(M[0], M[i]) for i in xrange(1,len(M))])
100 loops, best of 3: 9.51 ms per loop
>>> %timeit all(np.array_equal(M[0], M[i]) for i in xrange(1,len(M)))
100 loops, best of 3: 9.44 ms per loop