Как найти наиболее похожие числовые массивы на один массив с помощью Numpy / Scipy? - PullRequest
0 голосов
/ 06 мая 2020

Допустим, у меня есть список из 5 слов:

[this, is, a, short, list]

Кроме того, я могу классифицировать некоторый текст, подсчитав количество вхождений слов из приведенного выше списка и представив эти подсчеты в виде вектора:

N = [1,0,2,5,10] # 1x this, 0x is, 2x a, 5x short, 10x list found in the given text

Таким же образом я классифицирую многие другие тексты (подсчитайте 5 слов в тексте и представьте их как счетчики - каждая строка представляет другой текст, который мы будем сравнивать с N):

M = [[1,0,2,0,5],
     [0,0,0,0,0],
     [2,0,0,0,20],
     [4,0,8,20,40],
     ...]

Теперь я хочу найти верхние 1 (2, 3 и c) строки из M, которые наиболее похожи на N. Или, говоря простыми словами, тексты, наиболее похожие на мой исходный текст.

Проблема в том, что простой проверки расстояний между N и каждой строкой от M недостаточно, поскольку, например, строка M4 [4,0,8,20,40] сильно отличается по расстоянию от N, но все же пропорциональна ( в 4 раза) и поэтому очень похожи. Например, текст в строке M4 может быть всего в 4 раза длиннее текста, представленного буквой N, поэтому, естественно, все значения будут в 4 раза больше.

Каков наилучший подход к решению этой проблемы (нахождение наиболее 1,2,3 эт c похожих текстов от М до текста в N)?

Ответы [ 2 ]

2 голосов
/ 06 мая 2020

Вообще говоря, наиболее широко распространенная методика набора слов (то есть массивов) на предмет подобия - это проверка меры косинусного сходства. Это отображает ваш мешок n (здесь 5) слов в n -мерное пространство, и каждый массив является точкой (которая, по сути, также является вектором точек) в этом пространстве. Наиболее похожими векторами (/ точками) будут те, которые имеют наименьший угол к вашему тексту N в этом пространстве (это автоматически позаботится о пропорциональных векторах, так как они будут близки по углу). Следовательно, вот код для него (при условии, что M и N - это numpy массивы аналогичной формы, представленной в вопросе):

import numpy as np
cos_sim = M[np.argmax(np.dot(N, M.T)/(np.linalg.norm(M)*np.linalg.norm(N)))]

, который дает выход [ 4 0 8 20 40] для ваших входов .

1 голос
/ 06 мая 2020

Вы можете нормализовать количество строк, чтобы удалить эффект длины, как вы обсуждали. Нормализация строк M может быть выполнена как M / M.sum(axis=1)[:, np.newaxis]. Остаточные значения затем можно рассчитать как сумму разницы квадратов между N и M на строку. Минимальная разница (без учета значений NaN или inf, полученных, если сумма строк равна 0), тогда наиболее похожа.

Вот пример:

import numpy as np

N = np.array([1,0,2,5,10])
M = np.array([[1,0,2,0,5],
              [0,0,0,0,0],
              [2,0,0,0,20],
              [4,0,8,20,40]])

# sqrt of sum of normalised square differences
similarity = np.sqrt(np.sum((M / M.sum(axis=1)[:, np.newaxis] - N / np.sum(N))**2, axis=1))
# remove any Nan values obtained by dividing by 0 by making them larger than one element
similarity[np.isnan(similarity)] = similarity[0]+1

result = M[similarity.argmin()]

result
>>> array([ 4,  0,  8, 20, 40])

Тогда вы могли бы используйте np.argsort(similarity)[:n], чтобы получить n наиболее похожих строк.

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