Группировка результатов разреженной попарной матрицы - PullRequest
0 голосов
/ 26 июня 2019

У меня есть разреженная попарная матрица (<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 для проверки того, какие записи были выше порога.

1 Ответ

1 голос
/ 27 июня 2019

IIUC вы ищете что-то вроде

import pandas as pd

data = [[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]]

names = ['Smith, David', 'Davis, Jenny', 'David Smith',
         'Jennings, Brian', 'Black, John']

df = pd.DataFrame(data, columns=names, index=names)

df = df[df>0.8].unstack()

print(df[df.notnull()].reset_index())
        level_0          level_1    0
0  Smith, David  Jennings, Brian  1.0
1  Davis, Jenny      David Smith  0.9
2  Davis, Jenny  Jennings, Brian  0.9

Отсюда вы сможете играть в направлении желаемого результата.

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