Поиск слов в тексте, независимо от перегиба: Python - PullRequest
1 голос
/ 06 ноября 2019

Я пытаюсь найти в заданном тексте указанный список слов. Код довольно прост.

# put the words you want to match into a list
word_list = ["eat", "car", "house", "pick up", "child"]

# get input text from the user 
user_prompt = input("Please enter some text: ")

# loop over each word in word_list and check if it is a substring of user_prompt
for word in word_list:
    if word in user_prompt:
        print("{} is in the user string".format(word))

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

Есть ли способ поиска текста, чтобы найти слова из списка слов независимо от перегиба? Спасибо!

Ответы [ 2 ]

1 голос
/ 06 ноября 2019

Как сказал jonathan.scholbach, вы хотите лемматизировать слова в вашем тексте. Лемма слова - это форма слова, которую вы найдете в словаре.

Существует простой способ сделать это с помощью spacy , который будет выглядеть так:

import spacy

nlp=spacy.load('en_core_web_sm')
sent = "  I picked up my children in the car and they ate some pears.."
word_list = ["eat", "car", "house", "pick up", "child"]
doc = nlp(sent)
doc_lemma = " "
for token in doc:
    #for words without a defined lemma like pronouns, spacy returns -PRON-
    #let's capture those cases and use the form in the text: 
    if token.lemma_[0] == '-':
      doc_lemma = doc_lemma + token.text.lower() + " "
    else:
        #Put the lemmas in a string, so words like "pick up" will be found as well
        doc_lemma = doc_lemma + token.lemma_ + " "

#word_list now lookks like that:
# i pick up my child in the car and they eat some pear ..
for word in word_list:
    if word in doc_lemma:
        print(word)
#output:
#    eat
#    car
#    pick up
#    child

Редактировать: Как упоминалось в комментариях, это решение сопоставляет соединения только в том случае, если они находятся непосредственно рядом друг с другом: pick up сопоставляется в I picked up the apple, но не в Did you pick her up?

Рабочая среда для глаголов + частиц, подобных pick up, может выглядеть следующим образом:

#find root (the verb) and a corresponding particle
root= None
particle = None
for token in doc:
    if token.dep_=="ROOT":
        root= token.lemma_
if token.dep_ == "prt":
    particle= token.lemma_
#if both particle and root exist in the sentence, add them together to our final string,
#so verb + particle like "pick up" is matched, even when not next to each other.
if root is not None and particle is not None:
    doc_lemma = doc_lemma + root + " " + particle 

Этот обходной путь, вероятно, имеет другие недостатки, например, когда задействованы подпункты.

1 голос
/ 06 ноября 2019

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

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

Для английского языка есть пакет Python LemmInflect , который утверждает, что имеет 96,1% точности английских глаголов.

Используя это, мы можем сделать что-то вроде:

import lemminflect


def find_lemmas(word_set: set, test_string: str) -> list:
    word_set = set(word_set)
    found_lemmas = []

    for word in test_string.split(" "):
        lemma_dict = lemminflect.getAllLemmas(word)
        if lemma_dict:
            # values of getAllLemmas are tuples, we need a flat set
            lemmas = {y for x in lemma_dict.values() for y in x}
            found_lemma = list(lemmas & word_set)
            if found_lemma:
                found_lemmas.append(found_lemma[0])

    return found_lemmas

, что даст нам:

>>> word_set = {"eat", "car", "house", "pick up", "child"}
>>> test_string = """After he ate the cake he left the 
    house and went to his car. Then he wondered whether picking up the 
    children now would really be the best idea."""
>>> find_lemmas(word_set=word_set, test_string=test_string)
['eat', 'house', 'child']

Мы можем видеть, что "pick up" не был признан. Это потому, что мы разбираем слово test_string слово за словом, что разрушает структуру любого составного слова. Таким образом, получение этих составных лемм потребовало бы гораздо более сложной логики.

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

"She bent down to pick a penny. Then she looked up and realised she had lost a pound. "

В этом случае мы найдем форму "pick", а также форму "up", но это не будетформа "pick up".

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