Part of speech (PoS) taggins is a fundamental technique in most natural language recognition projects, in which we try to determine the role each word plays on a sentence. For example, the sentence "Toto, I have a feeling that we are not in Kansas anymore." could be tagged as:
Word | Tag |
---|---|
Toto | Proper noun |
, | Punctuation |
I | Pronoun |
have | Verb |
a | Determiner |
feeling | Noun |
that | Preposition |
we | Pronoun |
are | Verb |
not | Adverb |
in | Preposition |
Kansas | Noun |
anymore | Adverb |
. | Punctuation |
However, on this notebook, we will be performing PoS tagging over portuguese sentences, as english PoS tagging has already been covered in many other projects. Therefore, this discussion will be carried out in portuguese from this point onwards.
If you want to learn about PoS tagging in english, you can checkout this article by Mehul Gupta who does a job that is honestly better than mine on explaining the topic in detail. You can also easily find many implementations of PoS tagging on GitHub.
Hidden Markov Model
Nesses exemplos, usaremos a implementação do algoritmo Hidden Markov Model (Modelo Oculto de Markov) oferecido pela biblioteca nltk
. Esse modelo tem diversas aplicações além de PoS tagging em áreas como termodinâmica, estatística, ecnomia, teoria da informação, entre outras.
Teremos um processo estocástico, mais especificamente um processo Markoviano, ou seja, temos uma sequência de variáveis aleatórias que podem assumir um conjunto de estados
Enquanto as probabilidades de emissão indicam a probabilidade de um obervável
No nosso caso, os estados assumíveis serão classes de palavras existentes na língua portugesa que aqui serão representados com:
Classe de palavra | Tag |
---|---|
Artigo | ART |
Adjetivo | ADJ |
Nome | N |
Nome próprio | NPROP |
Numeral | NUM |
Pronome adjetivo | PROADJ |
Pronome substantivo | PROSUB |
Pronome pessoal | PROPESS |
Pronome conectivo subordinado | PRO-KS |
Pronome conectivo subordinado relativo | PRO-KS-REL |
Advérbio | ADV |
Advérbio conectivo subordinativo | ADV-KS |
Advérbio relativo subordinativo | ADV-KS-REL |
Conjunção coordenativa | KC |
Conjunção subordinativa | KS |
Preposição | PREP |
Interjeição | IN |
Verbo | V |
Verbo auxiliar | VAUX |
Particípio | PCP |
Palavra denotativa | PDEN |
Pontuação. | PU |
Moeda corrente | CUR |
as tags ainda podem ser acompanhadas de informações adicionais denotadas por:
Informação | Modificador (TAG|MOD) |
---|---|
Estrangeirismo | EST |
Apostos | AP |
Dados | DAD |
Números de telefone | TEL |
Datas | DAT |
Horas | HOR |
Contrações e ênclises | + |
Mesóclise | ! |
A sequência
Nome | Verbo | Advérbio | |
---|---|---|---|
Nome | 0.6 | 0.1 | 0.3 |
Verbo | 0.5 | 0.1 | 0.4 |
Advérbio | 0.5 | 0.4 | 0.1 |
caso o nosso vocabulário possua apenas as palavras armando, faz e rapidamente, uma possível tabela de probabilidades de emissão seria:
Nome | Verbo | Advérbio | |
---|---|---|---|
Armando | 0.5 | 0.5 | 0.0 |
Faz | 0.1 | 0.9 | 0.0 |
Rapidamente | 0.0 | 0.0 | 1.0 |
O Hidden Markov Model monta uma máquina de estados e trabalha com iterações baseadas nas duas probabilidades mencionadas para convergir e determinar uma classificação adequada para as palavras de uma sentença. Essas probabilidades são calculadas a partir de uma análise dos dados de treino fornecidos. Veremos agora o exemplo utilizando a implementação da nltk
do algoritmo.
Utilizaremos o corpus disponível nesse link cuja documentação pode ser obtida aqui.
Veja alguns exemplos de classificaões realizados pelo modelo treinado:
Código
print_tag('fugiu')
print_tag('escritório')
print_tag('rapidamente')
print_tag('R$')
print_tag('armando')
print_tag('seu')
print_tag('feliz')
Saída:
fugiu: v
escritório: n
rapidamente: adv
R$: cur
armando: nprop
seu: proadj
feliz: adj
Código:
tag_sentence('mesmo estando atrasado , parou para cumprimentá-lo')
Saída:
[('mesmo', 'pden'),
('estando', 'v'),
('atrasado', 'pcp'),
(',', 'pu'),
('parou', 'v'),
('para', 'prep'),
('cumprimentá-lo', 'n')]
Código:
tag_sentence('o galo ganhou mais uma vez , ai credo')
Saída:
[('o', 'art'),
('galo', 'n'),
('ganhou', 'v'),
('mais', 'adv'),
('uma', 'art'),
('vez', 'n'),
(',', 'pu'),
('ai', 'in'),
('credo', 'n')]
Código:
tag_sentence('que a força esteja com você')
Saída:
[('que', 'ks'),
('a', 'art'),
('força', 'n'),
('esteja', 'v'),
('com', 'prep'),
('você', 'propess')]
Utilizando o conjunto de dados de teste incluso no corpus para testar a qualidade do modelo, podemos verificar, que houveram 119.585 classificações corretas enquanto 58.788 delas foram incorretas, isso representa uma taxa de acerto de aproximadamente 67%, o que é uma taxa razoável especialmente considerando que ela poderia provavelmente ser melhorada com ajustes nos parâmetros de treino.
Nessa tabela observamos os resultados obtidos no teste. As linhas representam a predição enquanto as colunas representam a resposta correta para a palavra. Podemos perceber que o erro mais comum é a classificação incorreta de palavras como nomes, isso provavelmente é devido ao fato dos nomes serem uma classe de palavras mais geral que as outras, portanto, pela característica do aprendizado de máquina, quando o modelo não sabe qual classe atribuir a uma palavra, ele tende a optar por uma classificação menos específica.
No gráfico abaixo podemos ver como essa característica está refletida na taxa de acertos dos nomes que é muito próxima de 1, em mais de 90% dos casos o modelo classifica nomes corretamente.
Outro ponto interessante a se notar, é que as classes de palavras mais comuns como artigos, nomes, pronomes e verbos têm as maiores acuracias, cerca de 70% em todos os casos, o que significa que nos casos mais comuns, a classificação é eficaz. Moedas também apresentaram uma boa precisão, provavelmente devido ao fato de que representações de moedas tendem a ser mais específicas, já que são um grupo muito restrito e frequentemente incluem caracteres que não estão contidos no alfabeto da língua portugesa.