Несколько методов вычисления схожести предложений при обработке естественного языка

задняя часть Python рептилия NLP

В процессе обработки естественного языка мы часто сталкиваемся со сценариями, когда нам нужно найти похожие предложения или найти приблизительные выражения предложений. В это время нам нужно сгруппировать похожие предложения вместе, что предполагает сходство предложений. В этом разделе мы будем узнать, как использовать Python для вычисления сходства предложений.

основной метод

Расчет схожести предложений Мы классифицировали следующие методы:

  • Изменить расчет расстояния

  • Расчет коэффициента Жаккара

  • Расчет TF

  • Расчет TFIDF

  • Расчет Word2Vec

Давайте посмотрим на каждый принцип и посмотрите на эти типы алгоритма Python.

Изменить расчет расстояния

Расстояние редактирования, называемое на английском языке Edit Distance, также известное как расстояние Левенштейна, относится к минимальному количеству операций редактирования, необходимых для преобразования двух строк из одной в другую.Чем больше расстояние между ними, тем больше они различаются. Разрешенные операции редактирования включают замену одного символа другим, вставку символа и удаление символа.

Например, у нас есть две строки: строка и настройка.Если мы хотим преобразовать строку в настройку, нам нужно сделать два шага:

  • Первый шаг — добавить символ e между s и t.

  • Второй шаг — заменить r на t.

Таким образом, их разница в расстоянии редактирования равна 2, что соответствует минимальному количеству шагов, которые необходимо изменить (добавить, заменить, удалить) для преобразования двух.

Итак, как это сделать в Python, мы можем напрямую использовать библиотеку расстояний:

import distance

def edit_distance(s1, s2):
    return distance.levenshtein(s1, s2)

s1 = 'string'
s2 = 'setting'
print(edit_distance(s1, s2))

Здесь мы напрямую используем метод levenshtein() библиотеки расстояний и передаем две строки, чтобы получить расстояние редактирования двух строк.

Результаты приведены ниже:

2

Библиотеку расстояний здесь можно установить напрямую с помощью pip3:

pip3 install distance

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

import distance

def edit_distance(s1, s2):
    return distance.levenshtein(s1, s2)

strings = [
    '你在干什么',
    '你在干啥子',
    '你在做什么',
    '你好啊',
    '我喜欢吃香蕉'
]

target = '你在干啥'
results = list(filter(lambda x: edit_distance(x, target) <= 2, strings))
print(results)

Здесь мы определяем несколько строк, затем определяем целевую строку, а затем устанавливаем пороговое значение с расстоянием редактирования 2. Конечным результатом является результат с расстоянием редактирования 2 или меньше. Текущие результаты следующие:

['你在干什么', '你在干啥子']

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

Расчет коэффициента Жаккара

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

На самом деле, его метод расчета очень прост.Это значение, полученное путем деления пересечения двух выборок на объединение.Когда две выборки полностью совпадают, результат равен 1, а когда две выборки совершенно разные, результат 0.

Алгоритм очень простой, то есть пересечение делится на объединение, для его реализации воспользуемся кодом Python:

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np

def jaccard_similarity(s1, s2):
    def add_space(s):
        return ' '.join(list(s))

    # 将字中间加入空格
    s1, s2 = add_space(s1), add_space(s2)
    # 转化为TF矩阵
    cv = CountVectorizer(tokenizer=lambda s: s.split())
    corpus = [s1, s2]
    vectors = cv.fit_transform(corpus).toarray()
    # 求交集
    numerator = np.sum(np.min(vectors, axis=0))
    # 求并集
    denominator = np.sum(np.max(vectors, axis=0))
    # 计算杰卡德系数
    return 1.0 * numerator / denominator

s1 = '你在干嘛呢'
s2 = '你在干什么呢'
print(jaccard_similarity(s1, s2))

Здесь мы используем CountVectorizer из библиотеки Sklearn для вычисления матрицы TF предложения, затем используем Numpy для вычисления пересечения и объединения двух, а затем вычисляем коэффициент Жаккара.

Здесь стоит изучить использование CountVectorizer. С помощью его метода fit_transform () мы можем преобразовать строку в матрицу частот слов. Например, есть два предложения «что ты делаешь» и «что ты делаешь». Прежде всего, CountVectorizer учитывает. Выясните, какие слова не повторяются, вы получите список слов, результат:

['么', '什', '你', '呢', '嘛', '在', '干']

Это на самом деле может быть получено через следующий код, который должен получить содержание словаря:

cv.get_feature_names()

Затем после преобразования через переменные векторы становится:

[[0 0 1 1 1 1 1]
 [1 1 1 1 0 1 1]]

Это соответствует частотной статистике слов соответствующего словаря двух предложений. Здесь два предложения, поэтому результатом является двумерный массив длины 2. Например, первое предложение «Что ты делаешь» не содержит « какое слово, то результат, соответствующий первому слову «какое», равен 0, то есть число равно 0, и так далее.

Позже мы использовали метод np.min() и передали ось как 0, что фактически получило минимальное значение каждого столбца, который фактически взял пересечение.Метод np.max() получил максимальное значение каждого столбца. value на самом деле является объединением.

Сумма этих двух значений представляет собой размер пересечения и размер объединения, после чего можно рассчитать частное. Результаты следующие:

0.5714285714285714

Чем больше значение, тем ближе две строки, в противном случае верно обратное, поэтому мы также можем использовать этот метод и фильтровать, устанавливая порог подобия.

Расчет TF

Третье решение состоит в том, чтобы напрямую вычислить сходство двух векторов в матрице TF, Фактически, это решить значение косинуса угла между двумя векторами, которое представляет собой скалярное произведение, деленное на длину модуля двух. Формула выглядит следующим образом:

cosθ=a·b/|a|*|b|

Мы получили матрицу TF выше.Теперь нам нужно только решить значение косинуса угла между двумя векторами.Код выглядит следующим образом:

from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
from scipy.linalg import norm

def tf_similarity(s1, s2):
    def add_space(s):
        return ' '.join(list(s))

    # 将字中间加入空格
    s1, s2 = add_space(s1), add_space(s2)
    # 转化为TF矩阵
    cv = CountVectorizer(tokenizer=lambda s: s.split())
    corpus = [s1, s2]
    vectors = cv.fit_transform(corpus).toarray()
    # 计算TF系数
    return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1]))

s1 = '你在干嘛呢'
s2 = '你在干什么呢'
print(tf_similarity(s1, s2))

Здесь мы используем метод np.dot() для получения скалярного произведения вектора, а затем используем метод norm() для получения длины вектора по модулю.После расчета получаются коэффициенты TF двух результатов.Результаты следующие:

0.7302967433402214

Расчет TFIDF

Помимо расчета коэффициента TF, мы также можем рассчитать коэффициент TFIDF. TFIDF фактически добавляет информацию IDF на основе частоты слов TF. IDF называется обратной частотой документа. /www.ruanyifeng.com/blog/2013/03/ tf-idf.html объяснение TFIDF также очень подробное.

Ниже мы по-прежнему используем модуль TfidfVectorizer в Sklearn для реализации кода следующим образом:

from sklearn.feature_extraction.text import TfidfVectorizer
import numpy as np
from scipy.linalg import norm

def tfidf_similarity(s1, s2):
    def add_space(s):
        return ' '.join(list(s))

    # 将字中间加入空格
    s1, s2 = add_space(s1), add_space(s2)
    # 转化为TF矩阵
    cv = TfidfVectorizer(tokenizer=lambda s: s.split())
    corpus = [s1, s2]
    vectors = cv.fit_transform(corpus).toarray()
    # 计算TF系数
    return np.dot(vectors[0], vectors[1]) / (norm(vectors[0]) * norm(vectors[1]))

s1 = '你在干嘛呢'
s2 = '你在干什么呢'
print(tfidf_similarity(s1, s2))

Переменная vectors здесь фактически соответствует значению TFIDF, а именно:

[[0.         0.         0.4090901  0.4090901  0.57496187 0.4090901 0.4090901 ]
 [0.49844628 0.49844628 0.35464863 0.35464863 0.  0.35464863 0.35464863]]

Результаты приведены ниже:

0.5803329846765686

Таким образом, мы также можем рассчитать коэффициент подобия TFIDF.

Расчет Word2Vec

Word2Vec, как следует из названия, на самом деле представляет собой процесс преобразования каждого слова в вектор. Если вы не понимаете, вы можете обратиться к: https://blog.csdn.net/itplus/article/details/37969519.

Здесь мы можем напрямую загрузить обученную модель Word2Vec.Адрес ссылки на модель: https://pan.baidu.com/s/1TZ8GII0CEX32ydjsfMc0zw, которая представляет собой 64-мерную модель Word2Vec, обученную с использованием новостей, энциклопедии Baidu и новых данных. .Сумма очень большая, и общий эффект неплохой.Мы можем напрямую скачать и использовать.Здесь мы используем данные news_12g_baidubaike_20g_novel_90g_embedding_64.bin, а затем реализуем Sentence2Vec.Код выглядит следующим образом:

import gensim
import jieba
import numpy as np
from scipy.linalg import norm

model_file = './word2vec/news_12g_baidubaike_20g_novel_90g_embedding_64.bin'
model = gensim.models.KeyedVectors.load_word2vec_format(model_file, binary=True)

def vector_similarity(s1, s2):
    def sentence_vector(s):
        words = jieba.lcut(s)
        v = np.zeros(64)
        for word in words:
            v += model[word]
        v /= len(words)
        return v

    v1, v2 = sentence_vector(s1), sentence_vector(s2)
    return np.dot(v1, v2) / (norm(v1) * norm(v2))

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

Пример вызова выглядит следующим образом:

s1 = '你在干嘛'
s2 = '你正做什么'
vector_similarity(s1, s2)

Результат выглядит следующим образом:

0.6701133967824016

В это время, если мы вернемся к исходному примеру, чтобы увидеть эффект:

strings = [
    '你在干什么',
    '你在干啥子',
    '你在做什么',
    '你好啊',
    '我喜欢吃香蕉'
]

target = '你在干啥'

for string in strings:
    print(string, vector_similarity(string, target))

Тем не менее предыдущий пример, давайте посмотрим, какие их результаты сопоставления. Результаты выполнения следующие:

你在干什么 0.8785495016487204
你在干啥子 0.9789649689827049
你在做什么 0.8781992402695274
你好啊 0.5174225914249863
我喜欢吃香蕉 0.582990841450621

Видно, что аналогичное сходство предложений может быть более 0,8, и разные предложения менее 0,6. Это отвлечение очень велико. Можно сказать, что мы можем сочетать некоторую семантическую информацию, чтобы сделать некоторые суждения. Это много.

Так что в целом способ расчета Word2Vec очень хорош.

Кроме того, в академическом мире есть несколько возможных лучших результатов исследований.Вы можете посмотреть некоторые ответы на Zhihu: https://www.zhihu.com/question/29978268/answer/54399062.

Выше приведен базовый метод и реализация Python для расчета сходства предложений.Кодовый адрес этого раздела: https://github.com/AIDeepLearning/SentenceDistance.

Привет~ Всем рекомендую книгу! Книга о сканере Python, которая была переиздана 4 раза за два месяца! Это «Практика разработки поисковых роботов на Python3» Цуй Цинцай, блогера Jingmi! ! ! В то же время в конце статьи есть розыгрыш книги, которую нельзя пропустить! ! !

Введение в книгу

книга«Борьба за разработку поискового робота Python3»Всестороннее введение в знания об использовании Python3 для разработки поисковых роботов. Книга сначала знакомит с различными типами процессов настройки среды и подробными базовыми знаниями о поисковых роботах. В ней также обсуждаются библиотеки запросов, такие как urllib и запросы, и библиотеки синтаксического анализа, такие как Beautiful Soup. , XPath и pyquery, а также текстовые и методы хранения различных баз данных.Кроме того, эта книга знакомит с процессом анализа Ajax для сканирования данных, Selenium и Splash для динамического сканирования веб-сайтов по нескольким реальным и свежим кейсам, а затем делится некоторые практические навыки сканирования, такие как использование метода обхода прокси-сервера и обслуживание динамического пула прокси-серверов, использование прокси-сервера коммутируемого доступа ADSL, метод взлома различных кодов проверки (графика, экстремальный тест, сенсорный, сетка и т. д.), метод имитации сканирования веб-сайта входа в систему и обслуживания пула файлов cookie и т. д.

Кроме того, содержание этой книги выходит далеко за рамки этого: автор также обсуждает методы использования Charles, mitmdump, Appium и других инструментов для выполнения анализа перехвата пакетов приложений, обхода интерфейса параметров шифрования и обхода WeChat Moments в сочетании с характеристики мобильного интернета. Кроме того, эта книга также знакомит с фреймворком pyspider, использованием фреймворка Scrapy и подробным знанием распределенного сканера.Кроме того, для работы по оптимизации и развертыванию эта книга также включает оптимизацию эффективности фильтра Bloom, развертывание сканера Docker и Scrapyd, распределенная структура управления поисковым роботом Gerapy share.

Всего в книге 604 страницы, а весит она целых два фунта~ Цена 99 юаней!

об авторе

Когда вы читаете книгу, давайте посмотрим, кто написал ее первым, давайте узнаем~

Цуй Цинцай, блогер Jingmi (https://cuiqingcai.com), блог краулера Python был прочитан более миллиона человек, магистр Университета Бэйхан, преподаватель Tianshan Intelligence, NetEase Cloud Classroom, Microsoft Xiaobing Big Data Engineer, он имеет опыт работы во многих крупных проектах распределенных поисковых роботов и готов поделиться технологиями.Статьи просты для понимания ^_^

Поставляется с мыльным листом ~(@^_^@)~

Чтобы узнать подробности, нажмите ➡️nuggets.capable/post/684490…