Alura > Cursos de Data Science > Cursos de Machine Learning > Conteúdos de Machine Learning > Primeiras aulas do curso NLP: buscando entidades em documentos

NLP: buscando entidades em documentos

Identificando entidades básicas - Apresentação

Olá! Me chamo João Miranda e serei o seu instrutor ao longo deste curso.

Audiodescrição: João é um homem de pele clara, com cabelo curto e barba também curta. Veste uma camisa preta, sem estampas. Ao fundo, há uma parede iluminada em tons de verde e azul.

Já consideraram a possibilidade de utilizar modelos de NLP ("Processamento de Linguagem Natural") para identificar entidades como pessoas, organizações e outros elementos em textos de maneira automatizada?

O que aprenderemos?

Neste curso, construiremos uma aplicação prática que será capaz de identificar entidades nomeadas em textos jurídicos. Ao longo do projeto, realizaremos diversas etapas de tratamento de dados textuais, rotularemos as informações no formato IOB ("Inside-Outside-Beginning") e treinaremos um modelo de NLP com a capacidade de reconhecer palavras e expressões específicas em documentos.

Utilizaremos modelos tradicionais da biblioteca SpaCy. Portanto, não aprenderemos a realizar esse tipo de tarefa com modelos LLN ("Large Language Models"). Ao final do curso, teremos essa aplicação que está sendo mostrada na tela.

Endereço acessado pelo instrutor:

localhost:8501

Interface de usuário de um software de reconhecimento de entidades nomeadas (NER) com fundo preto e texto em branco. Na parte superior, o título 'Reconhecimento de entidades nomeadas (NER)' é seguido por duas opções de seleção: 'Texto' e 'Arquivo'. Abaixo há um campo para inserção de texto. Na parte inferior, a seção intitulada 'Reconhecimento de entidades nomeadas' com um subtítulo 'Select entity labels' e 'Entity labels' está presente, mas sem rótulos visíveis.

Nessa aplicação, haverá um título "Reconhecimento de Entidades Nomeadas". Abaixo, podemos escolher a opção de um texto ("Texto") que podemos inserir manualmente ou um arquivo do computador ("Arquivo").

Neste arquivo, é possível clicar no botão "Browse Files" à direita para selecionar o arquivo desejado. Ao realizar um duplo clique no arquivo desejado, a aplicação será capaz de reconhecer automaticamente todas as entidades presentes no texto. Durante o desenvolvimento do projeto, as entidades selecionadas poderão ser filtradas, permitindo decidir quais serão destacadas dentro do conteúdo textual.

Essa aplicação é bastante completa e muito útil para agilizar procedimentos jurídicos, pois acelera o processo de análise desses documentos. Esse mesmo processo pode ser aplicado em diversas áreas, não apenas em documentos jurídicos.

Pré-requisitos

Para acompanhar o conteúdo, é necessário que você tenha conhecimento na linguagem de programação Python e também conceitos de Machine Learning.

Vamos começar?

Identificando entidades básicas - Leitura dos textos

Uma empresa de advocacia está buscando soluções tecnológicas para otimizar o processamento de documentos jurídicos e melhorar a gestão dos processos em andamento.

Contextualizando

Atualmente, o escritório lida com uma grande quantidade de contratos, petições, jurisprudências e outros documentos legais, mas não existe uma forma eficiente de extrair essas informações críticas de forma automática, como, por exemplo:

  1. Partes de pessoas envolvidas;
  2. Datas relevantes;
  3. Dispositivos legais citados.

Nosso papel neste projeto consiste em desenvolver um modelo de NLP especializado na tarefa de reconhecimento de entidades nomeadas, também conhecida como NER ("Named Entity Recognition").

Esse modelo será capaz de identificar e classificar automaticamente informações relevantes em textos jurídicos, como partes envolvidas, datas e dispositivos legais.

Com isso, as pessoas advogadas e das equipes terão acesso mais rápido a dados cruciais, o que contribuirá para otimizar o tempo dedicado à análise, reduzir o risco de erros humanos e melhorar a gestão dos processos de forma mais eficiente e assertiva.

Carregando o arquivo

Para construir um modelo que identifique as entidades nomeadas específicas para o nosso problema, utilizaremos o Google Colab. O primeiro passo será carregar os textos jurídicos, que utilizaremos em nosso modelo. Para isso, no menu lateral esquerdo, selecionaremos a opção "Arquivos" (ícone de arquivo) e clicaremos em "Fazer Upload para o armazenamento da sessão" na parte superior esquerda.

Em seguida, selecionaremos o arquivo texts.zip, que estará disponível na atividade "Preparando Ambiente".

É importante fazer o download do arquivo texts.zip antes de continuar, para garantir que ele esteja disponível para o projeto.

Após selecionar o arquivo, clicamos duas vezes nele, e o Colab fará o upload para a aba de arquivos.

Leitura dos textos

Podemos então ler este arquivo, que é um arquivo compactado contendo vários arquivos .txt. Para isso, usaremos a biblioteca zipfile. Na primeira célula, escreveremos:

import zipfile

Pressionaremos "Ctrl + Enter" para executar a célula. Durante esse tempo, o arquivo será carregado à esquerda no Colab:

Acessamos o caminho do arquivo clicando nos três pontos ao lado do nome do arquivo e selecionando a opção "Copiar Caminho". Na próxima célula, utilizaremos a biblioteca zipfile para fazer a leitura desse arquivo compactado.

Digitamos with zipfile e utilizamos a função .ZipFile(), passando o caminho do arquivo entre aspas simples: with zipfile.ZipFile('/content/texts.zip'). Em seguida, adicionamos uma vírgula e colocamos como segundo parâmetro a letra 'r' indicando que realizaremos a leitura desse arquivo ("read").

Fora dos parênteses, adicionamos um apelido para o arquivo com as zip:. Na linha seguinte da mesma célula, após realizar a leitura, listamos os arquivos presentes dentro do arquivo compactado utilizando print(zip.namelist()).

with zipfile.ZipFile('/content/texts.zip', 'r') as zip:
    print(zip.namelist())

Ao executar "Ctrl + Enter", obteremos uma lista com os nomes de todos os arquivos.

['ADI2TJDFT.txt', 'adi3767.txt', 'Ag10000170733596001.txt', 'Ag10105170208398001.txt', 'AgAIRR11889820145030011.txt', 'AgCr10582160008758001.txt', 'AgRgSTJ1.txt', 'AgRgSTJ2.txt', 'AgRgTSE1.txt', 'AgRgTSE3.txt', 'AIAgRAgI6193ARAGUARIMG.txt', 'airr801422012.txt', 'AIRR3999520145020086.txt', 'AIRR15708820115050222.txt', 'AP00000794920137060006.txt', 'AP00001415620157010201.txt', 'AP00001441420167030203.txt', 'AP771420167080008PA.txt', 'CP32320177080008PA.txt', 'DespSEPLAGDF.txt', 'ED1STM.txt', 'ED1TJAC.txt', 'EDAgRgTSE2.txt', 'EDEDARR208420135040232.txt', 'EDRR1TST.txt', 'EEDRR9715120105020002.txt', 'ERR731004520105130003.txt', 'HC110260SP.txt', 'HC151914AgRES.txt', 'HC340624SP.txt', 'HC418951PR.txt', 'HC70000845920187000000.txt', 'lei11340.txt', 'Lei11788.txt', 'LoaDF2018.txt', 'Pet128TSE5.txt', 'Port77DF.txt', 'Rcl3495STJ.txt', 'REE5908TSE4.txt', 'REsp1583083RS.txt', 'RR474820145230056.txt', 'RR942006420095040028.txt', 'RR2574407120025020372.txt', 'TCU4687.txt', 'TSTRR16037920105200001.txt', 'AC1TCU.txt', 'AC1TJAC.txt', 'AC1TJMG.txt', 'AC2.txt', 'ACORDAOTCU25052016.txt']

Para exibir cada nome de arquivo em uma linha separada, facilitando a leitura, modificamos o código dentro do print() pasa *zip.namelist(), sep = '\n'. O asterisco descompactará a lista e extrairá cada um dos elementos, colocando cada nome de arquivo em uma linha diferente com sep = '\n':

with zipfile.ZipFile('/content/texts.zip', 'r') as zip:
    print(*zip.namelist(), sep = '\n')

Executamos com "Ctrl + Enter".

ADI2TJDFT.txt

adi3767.txt

Ag10000170733596001.txt

Ag10105170208398001.txt

AgAIRR11889820145030011.txt

AgCr10582160008758001.txt

AgRgSTJ1.txt

AgRgSTJ2.txt

AgRgTSE1.txt

AgRgTSE3.txt

AIAgRAgI6193ARAGUARIMG.txt

airr801422012.txt

AIRR3999520145020086.txt

AIRR15708820115050222.txt

AP00000794920137060006.txt

AP00001415620157010201.txt

AP00001441420167030203.txt

AP771420167080008PA.txt

CP32320177080008PA.txt

DespSEPLAGDF.txt

ED1STM.txt

ED1TJAC.txt

EDAgRgTSE2.txt

EDEDARR208420135040232.txt

EDRR1TST.txt

EEDRR9715120105020002.txt

ERR731004520105130003.txt

HC110260SP.txt

HC151914AgRES.txt

HC340624SP.txt

HC418951PR.txt

HC70000845920187000000.txt

lei11340.txt

Lei11788.txt

LoaDF2018.txt

Pet128TSE5.txt

Port77DF.txt

Rcl3495STJ.txt

REE5908TSE4.txt

REsp1583083RS.txt

RR474820145230056.txt

RR942006420095040028.txt

RR2574407120025020372.txt

TCU4687.txt

TSTRR16037920105200001.txt

AC1TCU.txt

AC1TJAC.txt

AC1TJMG.txt

AC2.txt

ACORDAOTCU25052016.txt

Para ler um arquivo de texto, como o ADI2TJDFT.txt, na próxima célula, utilizaremos o mesmo código da célula anterior para descompactar o arquivo zip. Em vez de utilizar o print(), podemos usar o with zip.open() passando o nome do arquivo que desejamos abrir entre aspas simples, 'ADI2TJDFT.txt'. Fora dos parênteses, apelidamos o arquivo de as arquivo.

Na linha seguinte, realizamos a leitura do arquivo e o decodificamos para o formato UTF-8. Isso é necessário porque o arquivo está em língua portuguesa e, portanto, pode conter acentos e outros elementos da língua que precisam ser interpretados corretamente para que a leitura seja feita. Para isso, digitamos texto = arquivo.read().decode('utf-8').

with zipfile.ZipFile('/content/texts.zip', 'r') as zip:
    with zip.open('ADI2TJDFT.txt') as arquivo:
        texto = arquivo.read().decode('utf-8')

Com isso, armazenaremos na variável texto toda a informação daquele arquivo. Ao executar essa célula, não aparecerá nada no output, mas a informação estará salva na variável texto.

Na próxima célula, podemos exibir o conteúdo do arquivo com:

print(texto)

Pressionando "Ctrl + Enter", conseguiremos realizar a leitura de um dos arquivos dentro do arquivo compactado.

O retorno abaixo foi parcialmente transcrito:

print(texto)
Órgão	:	Conselho Especial
Classe	:	ADI  Ação Direta de Inconstitucionalidade
N. Processo	:	2010002019357-4
Requerente(s)	:	PROCURADORA-GERAL DE JUSTIÇA DO DISTRITO FEDERAL E TERRITÓRIOS
Requerido(s)	:	PRESIDENTE DA CÂMARA LEGISLATIVA DO DISTRITO FEDERAL E OUTRO(S)
Relator 	:	Desembargador LÉCIO RESENDE
    EMENTA	
AÇÃO DIRETA DE INCONSTITUCIONALIDADE. LEIS DISTRITAIS N.º 747/1994 E 2018/1998. LEI COMPLEMENTAR DISTRITAL N.º 380/2001. INCONSTITUCIONALIDADE FORMAL. LEI ORGÂNICA DO DISTRITO FEDERAL. OCUPAÇÃO DE ÁREA PÚBLICA. COMPETÊNCIA PRIVATIVA DO GOVERNADOR DO DISTRITO FEDERAL. AÇÃO JULGADA PROCEDENTE EM RAZÃO DO VÍCIO FORMAL. Tanto o Decreto n.º 10.829/87, quanto a Portaria n.º 314/92, do Instituto Brasileiro do Patrimônio Cultural  IBPC, hoje Instituto do Patrimônio Histórico e Artístico Nacional  IPHAN, conferem ao Governador do Distrito Federal competência privativa para iniciar o processo legislativo, quando se tratar o tema de uso e ocupação do solo em todo o território do Distrito Federal.

    ACÓRDÃO	
Acordam os Desembargadores do Conselho Especial do Tribunal de Justiça do Distrito Federal e dos Territórios LÉCIO RESENDE  Relator, JOÃO MAIORISI  Vogal, ROMÃO C. OLIVEIRA  Vogal, DÁCIO VIEIRA  Vogal, SÉRGIO BITTENCOURT  Vogal, LECIR MANOEL DA LUZ  Vogal, CARMELITA BRASIL  Vogal, WALDIR LEÔNCIO LOPES JÚNIOR  Vogal, J.J. COSTA CARVALHO  Vogal, HUMBERTO ADJUTO ULHÔA  Vogal, NÍDIA CORRÊA LIMA  Vogal, ANA MARIA DUARTE AMARANTE BRITO  Vogal, CRUZ MACEDO  - Vogal, ROBERBAL CASEMIRO BELINATI  Vogal, SILVÂNIO BARBOSA DOS SANTOS  Vogal, OTÁVIO AUGUSTO  Vogal, sob a presidência do Desembargador OTÁVIO AUGUSTO, em proferir a seguinte decisão: JULGOU-SE PROCEDENTE A AÇÃO, POR MAIORIA, de acordo com a ata do julgamento e notas taquigráficas.
Brasília (DF), 17 de maio de 2011

Des. LÉCIO RESENDE
Relator

…

Se quisermos identificar as entidades dentro desse texto, como o número do processo, precisaríamos fazer a leitura e identificação manualmente, o que não seria tão eficiente.

Próximo passo

No próximo vídeo, aprenderemos como identificar essas entidades automaticamente dentro do nosso texto!

Identificando entidades básicas - Reconhecendo as entidades no texto

Demos o primeiro passo no projeto ao realizar a leitura de um documento jurídico armazenado em um arquivo compactado no formato zip. A partir desse documento, conseguimos reconhecer as entidades nomeadas presentes no texto jurídico, identificando as informações mais relevantes.

Ao ler o texto, fomos capazes de identificar as jurisprudências, as partes envolvidas, entre outros aspectos. Nosso objetivo é automatizar essa tarefa, de modo que não seja mais necessário realizar a leitura manual, utilizando um modelo que fará o entendimento e o reconhecimento dessas entidades de forma automática.

Automatizando a leitura

Para automatizar esse processo, utilizaremos a biblioteca SpaCy, que oferece modelos para o reconhecimento de entidades nomeadas em textos. O primeiro passo consiste em instalar essa biblioteca no Google Colab. Para isso, acessaremos a documentação do SpaCy na seção de instalação ("Install spaCy"), onde encontraremos o código necessário para instalar tanto a biblioteca quanto o modelo correspondente.

Na documentação, podemos selecionar as configurações específicas para o nosso projeto, como o sistema operacional ("Operating system"), que no caso do Google Colab é Linux. Assim, selecionaremos a opção Linux, deixaremos a plataforma de instalação "pip" e o hardware como "CPU".

Além disso, optaremos pelo pipeline treinado em português, já que nosso modelo precisa ser ajustado para a língua portuguesa. Podemos escolher entre um modelo de eficiência, que é mais rápido, mas menos preciso, ou um modelo de acurácia, que é mais preciso, mas mais lento. Optaremos pelo modelo de eficiência ("efficiency").

A documentação mostrará as informações para instalar tanto a biblioteca SpaCy quanto o modelo pt_core_news_sm, que é o modelo em português. Copiaremos as duas últimas linhas de código:

pip install -U spacy
python -m spacy download pt_core_news_sm

No Colab, começamos escrevendo !pip install -U spacy. A exclamação serve para acessarmos o prompt do Google Colab para realizar a instalação dentro da máquina:

!pip install -U spacy

Executamos com "Ctrl + Enter".

Enquanto a instalação ocorre, copiamos o código necessário para instalar o modelo e, em seguida, colamos na próxima célula com a exclamação:

!python -m spacy download pt_core_news_sm

Executamos com "Ctrl + Enter". Assim, será feito o download do modelo da lingua portuguesa da biblioteca SpaCy.

Retorno parcialmente transcrito:

Restart to reload dependencies

Após a instalação, será necessário reiniciar o ambiente para carregar as dependências. Para isso, comentamos o código de instalação da biblioteca e do modelo:

# !pip install -U spacy
# !python -m spacy download pt_core_news_sm

Logo após, selecionamos a opção de reiniciar a sessão e executar tudo no Colab, na parte superior, em "Ambiente de execução > Reiniciar sessão e executar tudo". Com isso, o ambiebte será reiniciado e todas as células serão executadas.

Será exibida uma janela intitulada "Reiniciar e executar tudo" com a pergunta "Você quer mesmo reiniciar o ambiente de execução? O estado dele e todas as variáveis locais será perido.". Clicamos no botão "Sim" na parte inferior direita.

Importando a biblioteca e o modelo

Após a reinicialização, importamos a biblioteca SpaCy e o modelo na célula seguinte com:

import spacy
import pt_core_news_sm

Na mesma célula, carregamos o modelo armazenando-o em uma variável chamada modelo_ner que receberá pt_core_news_sm.load():

import spacy
import pt_core_news_sm

modelo_ner = pt_core_news_sm.load()

O ner refere-se a Named Entity Recognition ("Reconhecimento de Entidades Nomeadas").

Executamos a célula e não há nenhum retorno relacionado a esse comando.

Podemos testar o modelo no documento jurídico que lemos. Para isso, criamos uma variável doc para armazenar o texto processado pelo modelo_ner().

doc = modelo_ner(texto)

Utilizamos um loop for para percorrer as entidades no documento. Na linha seguinte, digitamos for entidade in doc.ents:, pulamos mais uma linha e escrevemos print(f'{entidade.text} -> {entidade.label_}').

O entidade.text indica o texto da entidade, e após o ->, indicamos o tipo de entidade com entidade.label_. Com essa nomenclatura, extraímos a label dentro das entidades identificadas pelo modelo.

doc = modelo_ner(texto)

for entidade in doc.ents:
    print(f'{entidade.text} -> {entidade.label_}')

Executando essa célula, o modelo reconhece as entidades no texto, como Órgão sendo identificados com a label LOC e o Conselho Especial Classe sendo identificado com a label ORG. O DISTRITO FEDERAL E TERRITÓRIOS Requerido também é identificado como um LOC.

O retorno abaixo foi parcialmente transcrito:

Órgão -> LOC
Conselho Especial
Classe -> ORG
DISTRITO FEDERAL E TERRITÓRIOS
Requerido(s -> LOC
DA CÂMARA -> ORG
DISTRITO FEDERAL E OUTRO(S)
Relator -> LOC
LEIS DISTRITAIS -> MISC
COMPLEMENTAR DISTRITAL -> MISC
FORMAL -> ORG
LEI ORGÂNICA -> MISC
DISTRITO FEDERAL -> LOC
ÁREA PÚBLICA -> LOC
DO GOVERNADOR -> MISC
DISTRITO FEDERAL -> LOC
VÍCIO FORMAL -> ORG
Decreto n.º 10.829/87 -> MISC
Portaria n.º 314/92 -> ORG

…

Em cada uma das linhas, temos uma palavra do texto e, à direita, o tipo de entidade reconhecido. Embora ainda não saibamos o tipo exato de cada uma dessas entidades, já conseguimos extrair informações importantes dentro do nosso texto.

Utilizando a biblioteca Pandas

Para visualizar e filtrar melhor essas informações, podemos construir uma tabela com o Pandas. Importamos a biblioteca com o seguinte comando:

import pandas as pd

Executamos com "Ctrl + Enter".

Na próxima célula, criaremos um dataframe com as entidades e suas respectivas labels. Primeiro, definimos uma lista vazia com entidades = [], na qual armazenaremos cada uma das palavras (as entidades) reconhecidas. Para cada uma dessas palavras, também associamos sua label correspondente, armazenando essas informações em uma lista com labels = [].

Dessa forma, organizamos as entidades e suas labels lado a lado em uma tabela do Pandas.

Logo após, usamos o código for entidade in doc.ents:, mas, em vez de printarmos as informações, utilizamos entidades.append(entidade.text) para adicionar os textos das entidades na lista entidades. Na linha seguinte, digitamos labels.append(entidade.label_) para adicionar as labels correspondentes a cada entidade na lista labels.

entidades = []
labels = []

for entidade in doc.ents:
    entidades.append(entidade.text)
    labels.append(entidade.label_)

Ao executarmos a célula, criamos uma lista de entidades e de labels.

Para criar o dataframe, na próxima célula, digitamos pd.DataFrame({}) e passamos o título (nome da coluna) que será 'Entidade', associando à lista de entidades: 'Entidade': entidades. Aplicamos a mesma lógica para a label, criando a coluna 'Label' e associando à lista de labels: 'Label': labels.

pd.DataFrame({'Entidade': entidades, 'Label': labels})

Executando essa célula, obtemos uma tabela com as entidades e suas labels:

-EntidadeLabel
0ÓrgãoLOC
1Conselho Especial\nClasseORG
2DISTRITO FEDERAL E TERRITÓRIOS\nRequerido(s)LOC
3DA CÂMARAORG
4DISTRITO FEDERAL E OUTRO(S)\nRelatorLOC
.........
851PROCEDENTELOC
852Leis DistritaisMISC
853Lei ComplementarMISC
854omnesORG
855D E C I SMISC

Assim, teremos as entidades e suas respectivas labels organizadas em um dataframe.

É possível filtrar, por exemplo, apenas as labels LOC. Dessa forma, conseguimos extrair informações relevantes do texto utilizando o modelo do SpaCy.

Próximo passo

No entanto, ainda não temos clareza sobre o significado de cada label, e seria interessante visualizar essas labels destacadas no texto. Esse processo ajudará a verificar se todas as informações foram corretamente identificadas e também a compreender como o modelo as reconheceu. Abordaremos essa etapa no próximo vídeo!

Sobre o curso NLP: buscando entidades em documentos

O curso NLP: buscando entidades em documentos possui 150 minutos de vídeos, em um total de 53 atividades. Gostou? Conheça nossos outros cursos de Machine Learning em Data Science, ou leia nossos artigos de Data Science.

Matricule-se e comece a estudar com a gente hoje! Conheça outros tópicos abordados durante o curso:

Aprenda Machine Learning acessando integralmente esse e outros cursos, comece hoje!

Conheça os Planos para Empresas