У меня есть разреженная попарная матрица (<class 'scipy.sparse.csr.csr_matrix'>
), которая представляет близость между pandas.Series
строк, используя TF-IDF и косинусное сходство.Если бы он был плотным, он выглядел бы как гораздо более крупная версия:
[[0,0,0.3,0,0.8],
[0.1,0,0,0,0.4],
[0,0.9,0.6,0,0],
[1,0.9,0,0,0.8],
[0,0.4,0.3,0,0]]
. Обе оси представлены Series
, как показано ниже:
['Smith, David', 'Davis, Jenny', 'David Smith', 'Jennings, Brian']
Моя цель состоит в том, чтобыТеперь сгруппируйте похожие строки (что-нибудь выше порога, например, 0,8) настолько эффективно, насколько это возможно.Результат может выглядеть примерно так (в любой структуре данных, не обязательно в хэше, это просто пример):
{
'Smith, David': ['Smith, David', 'David Smith'],
'Davis, Jenny': ['Davis, Jenny'],
'Jennings, Brian': ['Jennings, Brian']
}
Мой текущий подход использует матрицу координат <class 'class scipy.sparse.coo_matrix'>
и zip
дляперебираем ненулевые записи:
from sklearn.metrics.pairwise import cosine_similarity
cx = cosine_similarity(tf_idf_matrix, dense_output=False).tocoo()
vals = df['Names']
for row, col, data in zip(cx.row, cx.col, cx.data):
do_something(vals[row], vals[col], data)
Это работает хорошо, но довольно медленно, когда в Серии получается намного больше 100 000 записей, и я чувствую, что что-то упустил.Есть ли более эффективный подход?Возможно, что-то с привязкой осей к массиву и фильтрацией по моему порогу (0,8)?
Я чувствую, что это должно быть довольно распространенной задачей, но поиск в Google ни к чему меня не приведет.
Обновление:
Мне удалось значительно сократить накладные расходы, переключившись с использования sklearn.metrics.pairwise.cosine_similarity
на использование sparse_dot_topn.awesome_cossim_topn
.
Это позволило мне отфильтровать матрицу по моему порогу во время его построения, таким образом значительно уменьшив количество элементов для цикла и ограничив необходимость использования cx.data для проверки того, какие записи были выше порога.