Части речи (также известные как POS, классы слов или синтаксические категории) полезны, потому что они многое говорят о слове и его соседях. Знание того, является ли слово существительным или глаголом, говорит нам о вероятных соседних словах (существительным предшествуют определители и прилагательные, а глаголам — существительные), что делает тегирование частей речи ключевым аспектом синтаксического анализа. Части речи являются полезными функциями для маркировки именованных объектов, таких как люди или организации, при извлечении информации или для разрешения совместных ссылок. Части речи также играют важную роль в генерации последовательности.

Части речи можно разделить на 2 большие категории: закрытый тип урока и открытый тип урока. Закрытые классы — это те, которые имеют относительно фиксированные элементы, такие как предлог. Открытые классы - это те, которые могут часто иметь новые термины, такие как существительное. Это одна из основных причин использования любой модели для прогнозирования POS вместо прогнозирования только на основе правил.

Тегирование — это задача устранения неоднозначности; слова неоднозначны — имеют более одной возможной части речи — и цель состоит в том, чтобы найти правильный тег для ситуации. Например, книга может быть глаголом (забронировать этот рейс) или существительным (дай мне эту книгу). Целью POS-тегов является устранение этих неоднозначностей путем выбора правильного тега для контекста.

Одним из широко используемых алгоритмов для этого является Скрытая модель Маркова (HMM). HMM — это модель последовательности, задачей которой является прогнозирование меток для каждой единицы в предложении. Таким образом, отображение последовательности наблюдений на последовательность меток. Он в основном выбирает наиболее вероятностную последовательность меток (тегов) для данной последовательности слов. Мы подробно рассмотрим работу HMM и ее реализацию в python.

Цепь Маркова полезна, когда нам нужно вычислить вероятность наблюдаемого события. Но во многих случаях события скрыты. Например. Обычно мы не видим теги частей речи в предложении. Однако мы видим слова и можем сделать вывод о тегах. Вот почему мы будем использовать здесь скрытую марковскую модель. Большое предположение, сделанное как цепью Маркова, так и скрытой моделью Маркова, заключается в том, что будущее состояние зависит только от текущего состояния, а не от какого-либо из прошлых состояний. HMM позволяет нам предсказывать как наблюдаемые, так и скрытые состояния.

Позвольте мне сначала определить терминологию.

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

Марковское предположение: P(qi|q1…qi−1) = P(qi|qi−1)

Выходная независимость: P(oi|q1…qi,…,qT,o1,…,oi,…,oT) =P(oi|qi)

Предварительная обработка и извлечение данных:

Этап подготовки данных включает в себя получение данных из любого источника и их разделение на обучение и тестирование. Я использовал nltk brown corpus и сохранил 40 000 предложений в качестве набора для обучения и 17 340 предложений в качестве тестового набора. Я сохранил переменную trainVocab, которая будет моим словарным запасом для слов. Я могу выполнять дополнительную предварительную обработку, такую ​​как лемматизация и стемминг. Также во время тестирования я могу заменить все слова, которых нет в моем лексиконе, на Нэн.

nltk.download('brown')
training_corpus = nltk.corpus.brown
Z =training_corpus.tagged_sents()
Xlemmatization & stemming=()
Y=()
for i in range(len(Z)):
    x,y=list(zip(*Z[i]))
    X=X+(x,)
    Y=Y+(y,)
    #print(Y,'\n\n\n')
x_train=X[:40000]
y_train=Y[:40000]
x_test=X[40000:]
y_test=Y[40000:]
trainVocab = frozenset(chain(*[s for s in x_train]))

Алгоритм для HMM следующий:

  1. Определим модель. Модель импортирована из библиотеки граната
from pomegranate import State,HiddenMarkovModel,DiscreteDistribution
model = HiddenMarkovModel(name=”HMM”)

2. Мы создадим множество, содержащее N состояний (тегов).

#Q=uniquetags
def unique_tagsFn(Y):
    mysetY=set()
    for i in Y:
        for j in i:
            mysetY.add(j)
    return mysetY
uniquetags=unique_tagsFn(Y)

3. Нам понадобятся две вспомогательные функции для подсчета количества слов в униграмме и количества слов в биграмме. По сути, он будет вести подсчет тегов, встречающихся по отдельности и в непрерывной паре.

def unigram_counts(sequences):
    your_unigram_counts=defaultdict(int)
    for i in range(len(sequences)):
        for j in sequences[i]:
            your_unigram_counts[j] +=1
    return your_unigram_counts
tag_unigrams = unigram_counts(y_train)

def bigram_counts(sequences):
    your_bigram_counts=defaultdict(int)
    for i in range(len(sequences)):
        for k in range(len(sequences[i])-1):
            your_bigram_counts[(sequences[i][k],sequences[i][k+1])] +=1
    return your_bigram_counts
tag_bigrams = bigram_counts(y_train)

4. Мы создадим матрицу вероятности эмиссии B. По сути, она говорит о вероятности генерации определенного слова при выборе определенного тега. Для расчета этого нам нужно иметь количество слов для определенного тега. Итак, мы создаем вложенный словарь, первым ключом которого является тег.

#B=emissions_distribution
emission_counts=defaultdict(lambda : defaultdict(int))
for j,tagList in enumerate(y_train):
    for a,b in zip(y_train[j],x_train[j]):
        emission_counts[a][b]=counts[a][b]+1
states = dict()
for tag in uniquetags:
    for word in emission_counts[tag]:
        emissions_distribution[word] = emission_counts[tag][word] / tag_unigrams[tag]
    tag_emissions = DiscreteDistribution(emissions_distribution)
    tag_state = State(tag_emissions, name=tag)
    states[tag]=tag_state
model.add_states([elt for elt in states.values()])

5. Мы создадим матрицу вероятности перехода состояния A. Мы добавим еще два состояния, т.е. start_state и end_state.

#For transition probabilities from start_state
#A=prob
start_state_count=defaultdict(int)
for i in range(len(y_train)):
    start_state_count[sequences[i][0]] +=1
tag_starts_sum=sum(start_state_count.values())
for tag in uniquetags:    
    prob= start_state_count[tag] / tag_starts_sum
    model.add_transition(mode.start, states[tag], prob)

#Similarly transition probabilities to end_state
end_state_count=defaultdict(int)
for i in range(len(y_train)):
    end_state_count[sequences[i][-1]] +=1
for tag in uniquetags:    
    prob = end_state_count[tag] / tag_unigrams[tag]
    model.add_transition(states[tag], model.end , prob)

#Now we need to consider transition between two states say from t1 to t2
for t1, t2 in tag_bigrams.keys():
    # Compute the transition probability P(t2|t1)=C(t1,t2) / C(t1)
    prob = tag_bigrams[(t1,t2)] / tag_unigrams[t1]
    model.add_transition(states[t1], states[t2] , prob)

6. Наконец, нам нужно запечь модель, и она готова для прогнозов.

model.bake()

7. Чтобы получить выходные теги из этой модели, мы просто вызываем метод Витерби с данными.

_, state_path = model.viterbi(x_test)
output_sequence=[state[1].name for state in state_path[1:-1]]

Ссылка: https://web.stanford.edu/~jurafsky/slp3/edbook_oct162019.pdf