Кредитное плечо broadcasting
после расширения - входные данные для двух 4D
версий, так что мы можем сравнивать блоки массива pairiwise-array друг с другом вдоль первой оси, сохраняя при этомвыровненные последние две оси -
result = (M[:,None] == M).all((2,3))
Мы можем расширить это до общего случая массива n-dim, используя последние две оси в качестве входных данных для .all()
-
(M[:,None] == M).all((-2,-1))
Кредитное плечо views
иметь более эффективную память и, следовательно, более высокую производительность -
# https://stackoverflow.com/a/44999009/ @Divakar
def view1D(a): # a is array
a = np.ascontiguousarray(a)
void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[1]))
return a.view(void_dt).ravel()
M1D = view1D(M.reshape(M.shape[0],-1))
result = M1D[:,None] == M1D
Время для большого массива -
In [48]: np.random.seed(0)
...: M = np.random.randint(0,10,(100,100,100))
In [49]: %timeit (M[:,None] == M).all((-2,-1))
10 loops, best of 3: 92.2 ms per loop
In [50]: %%timeit
...: M1D = view1D(M.reshape(M.shape[0],-1))
...: M1D[:,None] == M1D
1000 loops, best of 3: 627 µs per loop
Исходное значение -
In [54]: %%timeit
...: result = np.zeros((M.shape[0], M.shape[0]))
...: for i in range(M.shape[0]):
...: for j in range(M.shape[0]):
...: result[i,j] = numpy.array_equal(M[i], M[j])
10 loops, best of 3: 125 ms per loop
Вывод будет- Удалить петли, но следите за использованием памяти.Если возможно, найдите другие способы, позволяющие сохранить векторизацию и эффективность памяти.