Machine Learning, Sklearn

Сравнение текста с помощью статистической меры TF-IDF

Время прочтения: 4 мин.

Немного теории

TF-IDF — применяется для анализа значимости слова в документе,который является частью большой коллекции документов либо корпуса. Мы сталкиваемся с задачами, где необходимо проанализировать или найти нужной информации в тексте. Для решения практически всегда используем статистическую меру – TF-IDF.

TF (или частота слова) – это отношение количества употреблений какого-либо слова к совокупному количеству слов документа. Следовательно, анализируется значимость слова ti в одном отдельном документе.

IDF — это обратная частотность документов, с которой какое-либо слово упоминается в документах коллекции. Для любого уникального слова в пределах точной коллекции документов присутствует одно значение IDF.

Мы видим, что TF-IDF считается произведением двух выражений:

Больший вес в рамках одного документа в TF-IDF имеют слова с высокой частотой и с невысокой частотой использования в иных документах.

Практика

Применим вышеизложенный материал на практике. Задача состояла в сравнении двух текстов между собой. Нам необходимо было осуществить поиск похожих сообщений пользователей.

Для решения задачи потребуются следующие библиотеки:

from sklearn.feature_extraction.text import TfidfVectorizer,CountVectorizer — из этой большой библиотеки sklearn нам необходимо 2 модуля для расчета частоты слов (TfidfVectorizer) и количества слов (CountVectorizer)

from scipy.spatial import distance — предназначенная для выполнения научных и инженерных расчётов, из нее мы будем брать модуль distance для расчета косинусного расстояния.

import pandas as pd – служит для обработки и анализа данных

import regex as re – данная библиотека позволяет использовать регулярные выражения

import docx – библиотека для чтения docx файлов

Далее необходимо создать пару функций:

Из .docx файла получить уже очищенные предложения от мусора (цифры, знаки препинания и так далее)

def convert(doc):
    text=[]
    for i in doc:
        mas=[]
        mas=i.split('.')
        for j in mas:
            if j!='':
                j=re.sub(r'[^\pL\p{Space}]', '', j.strip().lower()).replace('  ',' ')
                text.append(j)
    return text

Для сбора уникальных предложений в двух сравниваемых текстах:

def add_sugg(doc1,doc2):
    all_mas=[]
    for i in doc1:
        if i in all_mas:
            continue
        else:
            all_mas.append(i)
    for j in doc2:
        if j in all_mas:
            continue
        else:
            all_mas.append(j)
    return all_mas

-	Расчет косинусного расстояния.
def dist(x,y):
return distance.cosine(x,y)

После описания функций можно их использовать и читать текст с документа. Для дальнейшей работы необходимо собрать все уникальные предложения. Далее разложить их на слова в каждом из них, и каждому дать свой номер, это и будет наш токинайзер. Эти числа и будем применять на исходные файлы docx. и сравнивать вектора между собой.

doc1 = [p.text for p in docx.Document('1.docx').paragraphs]
doc2 = [p.text for p in docx.Document('2.docx').paragraphs]
text1=convert(doc1)
text2=convert(doc2)
all_mas=add_sugg(text1,text2)

Так же я создал docx документ, куда внес собственные стоп слова, это пригодится для дальнейшей обработки текста — удаления ненужной информации.

stop_word = [p.text.lower() for p in docx.Document('стоп слова.docx').paragraphs]

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

tfidfvectorizer = TfidfVectorizer(analyzer='word',stop_words=s_word)

Следующим шагом будет обучение модели уже по отчищенным словам.

tfidf_wm = tfidfvectorizer.fit(all_mas)

И заключающий шаг преобразования — это применение модели на исходные тексты, для это необходимо применить модель к тесту.

text1_idf = tfidf_wm.transform(text1)
text2_idf = tfidf_wm.transform(text2)

Для удобства работы будем использовать pandas. В него запишем все полученные вектора

df_tfidfvect1 = pd.DataFrame(data = text1_idf.toarray(),columns = tfidf_tokens)
df_tfidfvect2 = pd.DataFrame(data = text2_idf.toarray(),columns = tfidf_tokens)

Посмотрим что получилось.

На выходе мы получили вектор их всех уникальных слов. В разбивке на частоту в каждом предложении.

Для удобства сделаем массив всех строк и запишем в новую колонку

df_tfidfvect1['combine'] = df_tfidfvect1.values.tolist()
df_tfidfvect2['combine'] = df_tfidfvect2.values.tolist()

Сделаем cross join что бы сравнить каждый вектор с каждым.

df_tfidfvect1['key'] = 0
df_tfidfvect2['key'] = 0
df_all = pd.merge(df_tfidfvect1, df_tfidfvect2, on='key')

Для наглядности создадим Dataframe, чтобы не плодить множество колонок.

df=pd.DataFrame()
df['x']=df_all['combine_x']
df['y']=df_all['combine_y']
df['dist']=df.apply(lambda x: dist(x['x'],x['y']),axis=1)

И отобразим только те вектора, у которых уникальность предложений менее 50%.

df.where(df['dist']<=0.5).dropna()

Таким несложным образом можно реализовать простую идею сравнения любых текстов. В дальнейшем использование данного шаблона позволит реализовать различные идеи. Например, привести слова в нормальную форму, кластеризовать комментарии, найти отклонения в теме форума, и так далее.

Советуем почитать