Итерация операции с двумя массивами с использованием numpy - PullRequest
0 голосов
/ 08 июня 2018

Я работаю с двумя разными массивами (75x4) и применяю алгоритм кратчайшего расстояния между двумя массивами.

Поэтому я хочу:

  • выполнитьоперация с одной строкой первого массива с каждой отдельной строкой второго массива, итерация для получения 75 значений
  • , поиск минимального значения и сохранение этого значения в новом массиве
  • , повторите это свторая строка первого массива, еще раз повторяя операцию для всех строк второго массива, и снова сохраняя минимальную разницу с новым массивом

Как бы я поступил так с numpy?

По сути, я хочу выполнить операцию между одной строкой массива 1 в каждой строке массива 2, найти минимальное значение и сохранить его в новом массиве.Затем сделайте то же самое для 2-й строки массива 1 и так далее для всех 75 строк массива 1.

Вот код для формулы, которую я использую.Я получаю только расстояние между каждой строкой массива 1 (тренировочные данные) и массивом 2 (тестовые данные).Но то, что я ищу, это сделать это для одной строки массива 1, повторяя все строки массива 2, сохраняя минимальное значение в новом массиве, затем делая то же самое для следующей строки массива 1, и так далее.,

arr_attributedifference = (arr_trainingdata - arr_testingdata)**2
arr_distance = np.sqrt(arr_attributedifference.sum(axis=1))

1 Ответ

0 голосов
/ 08 июня 2018

Вот два метода, один из которых использует einsum, другой KDTree:

einsum делает то, что мы также можем достичь с помощью радиовещания, например, np.einsum('ik,jk', A, B) примерно эквивалентно (A[:, None, :] * B[None, :, :]).sum(axis=2),Преимущество einsum заключается в том, что он выполняет суммирование сразу, поэтому он избегает создания промежуточного массива mxmxn.

KDTree более сложный.Мы должны заранее инвестировать в создание дерева, но после этого очень эффективен запрос ближайших соседей.

import numpy as np
from scipy.spatial import cKDTree as KDTree

def f_einsum(A, B):
    B2AB = np.einsum('ij,ij->i', B, B) / 2 - np.einsum('ik,jk', A, B)
    idx = B2AB.argmin(axis=1)
    D = A-B[idx]
    return np.sqrt(np.einsum('ij,ij->i', D, D)), idx

def f_KDTree(A, B):
    T = KDTree(B)
    return T.query(A, 1)

m, n = 75, 4
A, B = np.random.randn(2, m, n)

de, ie = f_einsum(A, B)
dt, it = f_KDTree(A, B)
assert np.all(ie == it) and np.allclose(de, dt)

from timeit import timeit

for m, n in [(75, 4), (500, 4)]:
    A, B = np.random.randn(2, m, n)
    print(m, n)
    print('einsum:', timeit("f_einsum(A, B)", globals=globals(), number=1000))
    print('KDTree:', timeit("f_KDTree(A, B)", globals=globals(), number=1000))

Пример выполнения:

75 4
einsum: 0.067826496087946
KDTree: 0.12196151306852698
500 4
einsum: 3.1056990439537913
KDTree: 0.85108971898444

Мы видим, что при небольшом размере задачи прямой метод(einsum) быстрее, а при больших проблемах KDTree побеждает.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...