Сравнение массива двух 3D-матриц в Numpy без циклов for - PullRequest
0 голосов
/ 19 февраля 2019

Все эксперты Numpy, это, наверное, довольно просто для вас, ребята.Этот вопрос должен существовать, но я не нашел что-то точное, решающее его.Нечто похожее было Сравнение двух матриц по строкам по вхождению в NumPy и Сравнительный массив Numpy с несколькими скалярами одновременно , но не совсем там.

Мне нужно вычислить numpy.array_equal для многомерного массива, но я уверен, что мне не нужно использовать двойные циклы for.Однако, если бы я вычислял с использованием двойных циклов for, это выглядело бы следующим образом:

M = numpy.array(
     [
         [
            [1,2,3],
            [1,3,4]
         ],
         [
            [3,4,5],
            [1,2,3]
         ],
         [
            [1,2,3],
            [1,3,4]
         ]
     ])

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

Я должен получить большую таблицу истинности M.shape[0]^2, где по крайней мере диагональ истинна.

1 Ответ

0 голосов
/ 19 февраля 2019

Кредитное плечо 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

Вывод будет- Удалить петли, но следите за использованием памяти.Если возможно, найдите другие способы, позволяющие сохранить векторизацию и эффективность памяти.

...