Косинусное вычисление расстояния между двумя массивами – Python

Вопрос: Я хочу применить функцию fn, которая по существу cosine distance на двух больших массивах numpy форм (10000, 100) и (5000, 100) по ряду, т.е. я вычисляю значение для каждой комбинации строк в этих массивах. Моя реализация: import math def fn(v1,v2): sumxx, sumxy, sumyy = 0, 0, 0 for i in range(len(v1)): x = v1[i];

Вопрос:

Я хочу применить функцию fn, которая по существу cosine distance на двух больших массивах numpy форм (10000, 100) и (5000, 100) по ряду, т.е. я вычисляю значение для каждой комбинации строк в этих массивах.

Моя реализация:

import math def fn(v1,v2): sumxx, sumxy, sumyy = 0, 0, 0 for i in range(len(v1)): x = v1[i]; y = v2[i] sumxx += x*x sumyy += y*y sumxy += x*y return sumxy/math.sqrt(sumxx*sumyy) val = [] for i in range(array1.shape[0]): for j in range(array2.shape[0]): val.append(fn(array1[i, :], array2[j, :]))

Функция очень быстрая и занимает всего несколько мс:

CPU times: user 4 ms, sys: 0 ns, total: 4 ms Wall time: 1.24 ms

Есть ли эффективный способ сделать это?

Лучший ответ:

Подход №1: мы могли бы просто использовать Scipy cdist с его функциональностью на cosine расстояние –

from scipy.spatial.distance import cdist val_out = 1 — cdist(array1, array2, ‘cosine’)

Подход №2: Другой подход, использующий matrix-multiplication

def cosine_vectorized(array1, array2): sumyy = (array2**2).sum(1) sumxx = (array1**2).sum(1, keepdims=1) sumxy = array1.dot(array2.T) return (sumxy/np.sqrt(sumxx))/np.sqrt(sumyy)

Подход № 3: Использование np.einsum для вычисления np.einsum для другого –

def cosine_vectorized_v2(array1, array2): sumyy = np.einsum(‘ij,ij->i’,array2,array2) sumxx = np.einsum(‘ij,ij->i’,array1,array1)[:,None] sumxy = array1.dot(array2.T) return (sumxy/np.sqrt(sumxx))/np.sqrt(sumyy)

Подход №4: Приведение в модуль numexpr для выгрузки вычислений с square-root для другого метода –

import numexpr as ne def cosine_vectorized_v3(array1, array2): sumyy = np.einsum(‘ij,ij->i’,array2,array2) sumxx = np.einsum(‘ij,ij->i’,array1,array1)[:,None] sumxy = array1.dot(array2.T) sqrt_sumxx = ne.evaluate(‘sqrt(sumxx)’) sqrt_sumyy = ne.evaluate(‘sqrt(sumyy)’) return ne.evaluate(‘(sumxy/sqrt_sumxx)/sqrt_sumyy’)

Тест времени выполнения

# Using same sizes as stated in the question In [185]: array1 = np.random.rand(10000,100) …: array2 = np.random.rand(5000,100) …: In [194]: %timeit 1 — cdist(array1, array2, ‘cosine’) 1 loops, best of 3: 366 ms per loop In [195]: %timeit cosine_vectorized(array1, array2) 1 loops, best of 3: 287 ms per loop In [196]: %timeit cosine_vectorized_v2(array1, array2) 1 loops, best of 3: 283 ms per loop In [197]: %timeit cosine_vectorized_v3(array1, array2) 1 loops, best of 3: 217 ms per loop

Оцените статью
Добавить комментарий