Как генерировать би / триграммы, используя spacy/nltk

Вводимый текст всегда представляет собой список названий блюд, где есть от 1 до 3 прилагательных и существительное

входные

thai iced tea
spicy fried chicken
sweet chili pork
thai chicken curry

выходы:

thai tea, iced tea
spicy chicken, fried chicken
sweet pork, chili pork
thai chicken, chicken curry, thai curry

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

И я хотел бы добиться этого с spacy или nltk

3 ответа

Я использовал Spacy 2.0 с английской моделью. Ваш вклад:

s = ["thai iced tea",
"spicy fried chicken",
"sweet chili pork",
"thai chicken curry",]

Просторное решение:

import spacy
nlp = spacy.load('en') # import spacy, load model

def noun_notnoun(phrase):
    doc = nlp(phrase) # create spacy object
    token_not_noun = []
    notnoun_noun_list = []

    for item in doc:
        if item.pos_ != "NOUN": # separate nouns and not nouns
            token_not_noun.append(item.text)
        if item.pos_ == "NOUN":
            noun = item.text

    for notnoun in token_not_noun:
        notnoun_noun_list.append(notnoun + " " + noun)

    return notnoun_noun_list

Функция вызова:

for phrase in s:
    print(noun_notnoun(phrase))

Результаты:

['thai tea', 'iced tea']
['spicy chicken', 'fried chicken']
['sweet pork', 'chili pork']
['thai chicken', 'curry chicken']

Вы можете достичь этого за несколько шагов с NLTK:

  1. PoS помечает последовательности

  2. сгенерируйте нужные n-граммы (в ваших примерах нет триграмм, но есть скип-граммы, которые можно сгенерировать с помощью триграмм, а затем выбить средний токен)

  3. отменить все n-граммы, которые не соответствуют шаблону JJ NN.

Пример:

def jjnn_pairs(phrase):
    '''
    Iterate over pairs of JJ-NN.
    '''
    tagged = nltk.pos_tag(nltk.word_tokenize(phrase))
    for ngram in ngramise(tagged):
        tokens, tags = zip(*ngram)
        if tags == ('JJ', 'NN'):
            yield tokens

def ngramise(sequence):
    '''
    Iterate over bigrams and 1,2-skip-grams.
    '''
    for bigram in nltk.ngrams(sequence, 2):
        yield bigram
    for trigram in nltk.ngrams(sequence, 3):
        yield trigram[0], trigram[2]

Расширить шаблон ('JJ', 'NN') и желаемые н-граммы для ваших нужд.

Я думаю, что нет необходимости в разборе. Основная проблема этого подхода, однако, заключается в том, что большинство PoS-тэгеров, вероятно, будут помечать все не так, как вы хотите. Например, PoS-тег по умолчанию в моей установке NLTK помечал "chili" как NN, а не JJ, а "fried" получил VBD. Разбор не поможет вам с этим, однако!

Что-то вроде этого:

>>> from nltk import bigrams
>>> text = """thai iced tea
... spicy fried chicken
... sweet chili pork
... thai chicken curry"""
>>> lines = map(str.split, text.split('\n'))
>>> for line in lines:
...     ", ".join([" ".join(bi) for bi in bigrams(line)])
... 
'thai iced, iced tea'
'spicy fried, fried chicken'
'sweet chili, chili pork'
'thai chicken, chicken curry'

Альтернативно используя colibricore https://proycon.github.io/colibri-core/doc/;P

Другие вопросы по тегам