Модифицированная косинусная эффективность подобия - PullRequest
0 голосов
/ 15 октября 2019

Проблема

Я пытаюсь вычислить косинусное сходство между двумя массивами, но есть небольшое изменение в базовой формуле. А именно, я забочусь только о компонентах, которые перекрываются с «ссылочным» массивом. Например, если бы мы вычислили косинусное сходство между следующими двумя массивами:

A = [1 0 1]     B = [1 1 0]
    [0 1 1]         [0 1 1]

Допустим, B является эталонным массивом. Затем A изменяется относительно каждой строки в B, чтобы включить только те компоненты, которые перекрываются с этой строкой. Например, первая строка в B равна [1 1 0], поэтому вычисление подобия выполняется с модифицированной матрицей A:

[1 0 0]
[0 1 0]

Чтобы вычислить следующие сходства с помощью [0 1 1], измененное значение A становится:

[0 0 1]
[0 1 1]

Мой вопрос: есть ли способ внедрить эту модификацию без существенного снижения производительности (по сравнению со встроенными опциями сходства косинусов, такими как sklearn.metrics.pairwise.cosine_similarity)? Я понимаю, что ничто не будет таким же быстрым, как стандартное вычисление сходства косинусов, но сейчас мои попытки ввести это изменение привели к замедлению почти в 100 раз, поэтому любое улучшение этого было бы большим.

Попытки

На самом деле я не знаю ни одного способа сделать это, кроме как проходить строку за строкой через массив ссылок, маскировать другой массив в соответствии с текущей строкой, а затем выполнять косинус-подобие матрицы-вектора. Примерно так:

def modified_cosine_sim(arr1, arr2):
    # arr2 is reference array
    final_arr = []
    for row in arr2:
        masked_arr1 = arr1 * np.where(row > 0, 1, 0)
        final_arr.append(cosine_similarity(masked_arr1, row))

    return final_arr 

Хотя это довольно неэффективно. Я проверил, есть ли какой-нибудь умный способ изменить код sklearn cosine_similarity для достижения цели, но этот код основан на нормализации обоих массивов до того, как вычисления продолжатся, и я не могу этого сделать - arr1эффективно изменяется на протяжении всего вычисления, в зависимости от строки в arr2, которая в настоящее время используется для вычисления сходств.

Мне приходится многократно запускать это вычисление на несколько больших массивах, поэтому любые советы по оптимизации будут высоко оценены. Или, если это вычисление соответствует какой-то уже оптимизированной встроенной функции, с которой я не знаком, это было бы еще лучше. Спасибо!

Ответы [ 2 ]

1 голос
/ 15 октября 2019

Следующее реализует вашу модифицированную формулу, используя в основном матричное умножение.

def modified_similarity(a,b):
    bc = np.maximum(b,0)/np.linalg.norm(b,axis=1,keepdims=True)
    return a@bc.T/np.sqrt(np.square(a)@np.sign(bc).T)
0 голосов
/ 15 октября 2019

Я считаю, что следующий код и ваша функция modified_cosine_sim эквивалентны.

def faster_cosine_sim(arr1, arr2):
    return cosine_similarity(arr1 * np.where(arr2 > 0, 1, 0), arr2)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...