Сравнение нечетких строк
То, что я пытаюсь завершить, - это программа, которая читается в файле и будет сравнивать каждое предложение в соответствии с исходным предложением. Предложение, которое идеально соответствует оригиналу, получит оценку 1, а предложение, которое является общей противоположностью, получит 0. Все остальные нечеткие предложения получат оценку от 1 до 0.
Я не уверен, какую операцию использовать, чтобы позволить мне завершить это в Python 3.
Я включил образец текста, в котором текст 1 является оригиналом, а остальные предыдущие строки - это сравнения.
Текст: Пример
Текст 1: Это была темная и бурная ночь. Я сидел один на красном стуле. Я не был полностью одинок, поскольку у меня было три кошки.
Текст 20: Это была мрачная и бурная ночь. Я сидел один на малом кресле. Я не был полностью одинок, так как у меня было три кошачьих
// Должен забить верхнюю точку, но не 1
Текст 21: Это была темная и бурная ночь. Я был одинок, сидя на малиновой кафедре. Я не был полностью одинок, так как у меня было три кошачьих
// Должен набрать меньше, чем текст 20
Текст 22: Я был одинок, сидя на малиновой кафедре. Я был не совсем одинок, так как у меня было три кошачьих. Это была мрачная и бурная ночь.
// Должен оценивать меньше, чем текст 21, но НЕ 0
Текст 24: Это была темная и бурная ночь. Я был не один. Я не сидел на красном стуле. У меня было три кошки.
// Должен забить 0!
Ответы
Ответ 1
Существует пакет под названием fuzzywuzzy
. Установить через pip:
pip install fuzzywuzzy
Простое использование:
>>> from fuzzywuzzy import fuzz
>>> fuzz.ratio("this is a test", "this is a test!")
96
Пакет построен поверх difflib
. Почему бы просто не использовать это, спросите вы? Помимо того, что он немного проще, он имеет множество различных методов сопоставления (например, нечувствительность к токену, частичное совпадение строк), которые делают его более эффективным на практике. Особенно полезны функции process.extract
: найдите наилучшие совпадающие строки и отношения из набора. Из их readme:
Частичное соотношение
>>> fuzz.partial_ratio("this is a test", "this is a test!")
100
Коэффициент сортировки токенов
>>> fuzz.ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
90
>>> fuzz.token_sort_ratio("fuzzy wuzzy was a bear", "wuzzy fuzzy was a bear")
100
Соотношение токенов
>>> fuzz.token_sort_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
84
>>> fuzz.token_set_ratio("fuzzy was a bear", "fuzzy fuzzy was a bear")
100
Процесс
>>> choices = ["Atlanta Falcons", "New York Jets", "New York Giants", "Dallas Cowboys"]
>>> process.extract("new york jets", choices, limit=2)
[('New York Jets', 100), ('New York Giants', 78)]
>>> process.extractOne("cowboys", choices)
("Dallas Cowboys", 90)
Ответ 2
В стандартной библиотеке есть модуль (называемый difflib
), который может сравнивать строки и возвращать оценку на основе их сходства. Класс SequenceMatcher
должен делать то, что вам нужно.
EDIT: Маленький пример из приглашения python:
>>> from difflib import SequenceMatcher as SM
>>> s1 = ' It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats.'
>>> s2 = ' It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines.'
>>> SM(None, s1, s2).ratio()
0.9112903225806451
НТН!
Ответ 3
fuzzyset
намного быстрее, чем fuzzywuzzy
(difflib
) для индексирования и поиска.
from fuzzyset import FuzzySet
corpus = """It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines
It was a murky and tempestuous night. I was all alone sitting on a crimson cathedra. I was not completely alone as I had three felines
I was all alone sitting on a crimson cathedra. I was not completely alone as I had three felines. It was a murky and tempestuous night.
It was a dark and stormy night. I was not alone. I was not sitting on a red chair. I had three cats."""
corpus = [line.lstrip() for line in corpus.split("\n")]
fs = FuzzySet(corpus)
query = "It was a dark and stormy night. I was all alone sitting on a red chair. I was not completely alone as I had three cats."
fs.get(query)
# [(0.873015873015873, 'It was a murky and stormy night. I was all alone sitting on a crimson chair. I was not completely alone as I had three felines')]
Предупреждение. Будьте осторожны, чтобы не смешивать unicode
и bytes
в вашем fuzzyset.
Ответ 4
Задача называется Идентификация парафраз, которая является активной областью исследований в области обработки естественного языка. Я связал несколько статей, многие из которых вы можете найти с открытым исходным кодом на GitHub для.
Обратите внимание, что весь ответ на вопрос предполагает, что между двумя предложениями существует некоторое сходство строк и поверхностей, в то время как в действительности два предложения с небольшим сходством строк могут быть семантически похожими.
Если вы заинтересованы в подобном сходстве, вы можете использовать Skip-Thoughts.
Установите программное обеспечение в соответствии с руководствами GitHub и перейдите к разделу обнаружения парафраза в файле readme:
import skipthoughts
model = skipthoughts.load_model()
vectors = skipthoughts.encode(model, X_sentences)
Это преобразует ваши предложения (X_sentences) в векторы. Позже вы можете найти сходство двух векторов:
similarity = 1 - scipy.spatial.distance.cosine(vectors[0], vectors[1])
где мы принимаем вектор [0] и вектор 1 - соответствующий вектор для X_sentences [0], X_sentences 1, который вы хотели бы найти в своих оценках.
Существуют другие модели для преобразования предложения в вектор, который вы можете найти здесь.
Как только вы конвертируете свои предложения в векторы, сходство - это просто вопрос нахождения сходства Косина между этими векторами.