Векторизация координатных расстояний в Numpy - PullRequest
0 голосов
/ 21 апреля 2020

Я пытаюсь понять Numpy, применяя векторизацию. Я пытаюсь найти самую быструю функцию для этого.

def get_distances3(coordinates):
    return np.linalg.norm(
        coordinates[:, None, :] - coordinates[None, :, :],
        axis=-1)
coordinates = np.random.rand(1000, 3)
%timeit get_distances3(coordinates)

Приведенная выше функция выполняла 10 циклов, лучшее из 3: 35,4 мс на л oop. Из библиотеки numpy есть также опция np.vectorize, чтобы сделать это.

def get_distances4(coordinates):
  return np.vectorize(coordinates[:, None, :] - coordinates[None, :, :],axis=-1)

%timeit get_distances4(coordinates)

Я пробовал использовать np.vectorize ниже, но в итоге получил следующую ошибку.

Ошибка типа: __init __ () получила неожиданный аргумент ключевого слова 'axis'

Как найти векторизацию в get_distances4? Как мне отредактировать код lsat, чтобы избежать ошибки? Я никогда не использовал np.vectorize, поэтому я мог что-то упустить.

1 Ответ

1 голос
/ 21 апреля 2020

Вы не правильно звоните np.vectorize(). Я предлагаю обратиться к документации .

Vectorize принимает в качестве аргумента функцию , написанную для работы с скалярными значениями, и преобразует ее в функцию, которую можно векторизовать над значениями в массивах в соответствии с Numpy правилами вещания. В основном это похоже на причудливый map() для Numpy массива.

, т. Е. Как вы знаете, Numpy уже имеет встроенные векторизованные версии многих общих функций, но если у вас есть какая-то пользовательская функция, например "my_special_function ( x) "и вы хотели иметь возможность вызывать его для Numpy массивов, вы могли бы использовать my_special_function_ufunc = np.vectorize(my_special_function).

В приведенном выше примере вы могли бы" векторизовать "вашу функцию расстояния, например:

>>> norm = np.linalg.norm
>>> get_distance4 = np.vectorize(lambda a, b: norm(a - b))
>>> get_distance4(coordinates[:, None, :], coordinates[None, :, :])

Однако вы обнаружите, что это невероятно медленно:

>>> %timeit get_distance4(coordinates[:, None, :], coordinates[None, :, :])
1 loop, best of 3: 10.8 s per loop

Это потому, что ваш первый пример get_distance3 уже использует встроенные в Numpy быстрые реализации этих операций, в то время как версия np.vectorize требует вызова функции Python, которую я определил около 3000 раз.

Фактически в соответствии с документацией:

Функция векторизации предоставляется в основном для удобства, не для производительности. Реализация, по сути, для l oop.

Если вам нужна потенциально более быстрая функция для преобразования расстояний между векторами, вы можете использовать scipy.spacial.distance.pdist:

>>> %timeit get_distances3(coordinates)
10 loops, best of 3: 24.2 ms per loop
>>> %timeit distance.pdist(coordinates)
1000 loops, best of 3: 1.77 ms per loop

Стоит отметить, что это имеет другую форму возврата. Вместо массива 1000x1000 он использует сжатый формат, который исключает записи i = j и записи i > j. Если вы используете sh, вы можете использовать scipy.spatial.distance.squareform для преобразования обратно в квадратный матричный формат.

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