Сходство Жаккара для текстов в фрейме данных pandas

Я хочу измерить сходство jaccard между текстами в pandas DataFrame. Точнее, у меня есть несколько групп сущностей, и есть текст для каждой сущности в течение определенного периода времени. Я хочу проанализировать сходство текста (здесь сходство Жаккара) с течением времени отдельно для каждого объекта.

Минимальный пример, иллюстрирующий мою точку зрения:


import pandas as pd

entries = [
    {'Entity_Id':'Firm1', 'date':'2001-02-05', 'text': 'This is a text'},
    {'Entity_Id':'Firm1', 'date':'2001-03-07', 'text': 'This is a text'},
    {'Entity_Id':'Firm1', 'date':'2003-01-04', 'text': 'No similarity'},
    {'Entity_Id':'Firm1', 'date':'2007-10-12', 'text': 'Some similarity'},
    {'Entity_Id':'Firm2', 'date':'2001-10-10', 'text': 'Another firm'},
    {'Entity_Id':'Firm2', 'date':'2005-12-03', 'text': 'Another year'},
    {'Entity_Id':'Firm3', 'date':'2002-05-05', 'text': 'Something different'}
    ]

df = pd.DataFrame(entries)

Текст даты Entity_Id

Firm1   2001-02-05   'This is a text' 
Firm1   2001-03-07   'This is a text'
Firm1   2003-01-04   'No similarity'
Firm1   2007-10-12   'Some similarity'
Firm2   2001-10-10   'Another firm'
Firm2   2005-12-03   'Another year'
Firm3   2002-05-05   'Something different'

Мой желаемый результат будет примерно таким:

Entity_Id текст даты Jaccard

Firm1   2001-02-05   'This is a text'       NaN
Firm1   2001-03-07   'This is a text'       1
Firm1   2003-01-04   'No similarity'        0
Firm1   2007-10-12   'Some similarity'      0.33
Firm2   2001-10-10   'Another firm'         NaN 
Firm2   2005-12-03   'Another year'         0.33  
Firm3   2002-05-05   'Something different'  NaN 

То есть мне нравится сравнивать все текстовые элементы в группе Фирм, независимо от временного интервала между текстами. Я хотел бы всегда сравнивать его с предыдущим текстом. Поэтому первая запись для каждой фирмы всегда пуста, так как нет текста для сравнения.

Мой подход состоит в том, чтобы сдвинуть тексты по идентификатору сущности на один временной интервал (доступна следующая дата). Затем определить первый отчет каждой Сущности и отметить этот. (Я ввожу исходный текст для NaN в text_shifted и удаляю его позже -> это нужно для токенизации всего столбца)

df = df.sort_values(['Entity_Id', 'date'], ascending=True)
df['text_shifted'] = df.groupby(['Entity_Id'])['text'].shift(1)
df['IsNaN'] = df['text_shifted'].isnull().astype(int)
df['text_shifted'] = df['text_shifted'].fillna(df['text'])

Далее я использую подобие жаккарда следующим образом:

def jaccard_similarity(query, document):
    intersection = set(query).intersection(set(document))
    union = set(query).union(set(document))
    return len(intersection)/len(union)

Однако сначала мне нужно токенизировать ввод. Но если я сделаю что-то вроде:

import nltk
df['text_tokens'] = df.text.apply(nltk.word_tokenize)
df['shift_tokens'] = df.text_shifted.apply(nltk.word_tokenize)

Требуются годы, чтобы токенизировать тексты в примере неупрощенного текста, где каждый текст содержит примерно 5000 слов, а у меня около 100 000 текстов.

Есть ли способ ускорить процесс? Могу ли я избежать токенизации или еще лучше использовать sklearn для вычисления сходства?

Если я использую косинусное сходство, как предлагается здесь: Косинусное сходство по строкам Я получаю результаты довольно быстро. Но я застрял в этом с жаккартом.


person alex_rieber    schedule 26.09.2017    source источник
comment
вы пробовали профилировать свою работу? По сути, похоже, что токенизация - это узкое место   -  person PlagTag    schedule 04.10.2017


Ответы (1)


Одним из способов ускорить процесс может быть параллельная обработка с использованием Pandas on Ray .

Вы можете попробовать NLTK-реализацию jaccard_distance для жаккарное сходство. Я не смог найти значительного улучшения времени обработки (для вычисления сходства), может работать лучше на более крупном наборе данных.

Пытался сравнить реализацию NLTK с вашей пользовательской функцией подобия jaccard (на 200 текстовых образцах средней длины 4 слова / токена)

NTLK jaccard_distance:

CPU times: user 3.3 s, sys: 30.3 ms, total: 3.34 s
Wall time: 3.38 s

Пользовательская реализация подобия jaccard:

CPU times: user 3.67 s, sys: 19.2 ms, total: 3.69 s
Wall time: 3.71 s
person Aniket    schedule 14.03.2018