Machine Learning · Insper · E2.1

Bag-of-Words

Abordagem fundamental

Como um documento vira uma linha de contagens e quão parecidas são duas linhas

A ideia

uma coluna

para cada palavra do vocabulário

uma linha

para cada documento

uma célula

quantas vezes aquela palavra aparece naquele documento

Nada é aprendido além do vocabulário: não há modelo nem treino.

O caminho desta parte

  1. Contar as palavrasa matriz de contagens, CountVectorizer, contagem ou presença
  2. Comparar dois sacossimilaridade de cosseno: o ângulo, não a distância
  3. O que o saco perdea ordem das palavras; os bigramas recuperam parte dela
Cada etapa responde a uma pergunta: como um documento vira uma linha de números? → quão parecidos são dois documentos? → o que o saco joga fora?
Etapa 1 · como um documento vira uma linha de números?

Três documentos, cortados em tokens


"O gato comeu o peixe."               ['gato', 'comeu', 'peixe']
"O cachorro comeu a ração do gato."   ['cachorro', 'comeu', 'ração', 'do', 'gato']
"Gato dorme, gato sonha."             ['gato', 'dorme', 'gato', 'sonha']
  
Preveja. Quantas colunas a matriz vai ter? E que número vai na célula (d3, gato)?

O CountVectorizer monta a matriz


bow = CountVectorizer()
X = bow.fit_transform(docs)
print(pd.DataFrame(X.toarray(), columns=bow.get_feature_names_out(), index=['d1', 'd2', 'd3']))
print(type(X).__name__, X.shape, 'non-zeros:', X.nnz)
  

    cachorro  comeu  do  dorme  gato  peixe  ração  sonha
d1         0      1   0      0     1      1      0      0
d2         1      1   1      0     1      0      1      0
d3         0      0   0      1     2      0      0      1
csr_matrix (3, 8) non-zeros: 11
  
\[ \text{doc}_i \;\longrightarrow\; x_i \in \mathbb{R}^{|V|}, \qquad x_{ij} = \text{vezes que a palavra } j \text{ aparece no documento } i \]
8 colunas, o vocabulário \(V\) em ordem alfabética; (d3, gato) vale 2. "Bag" (saco) é literal: despeje as palavras num saco e sacuda; só as contagens sobrevivem.

O fit aprende o vocabulário, o transform só o aplica

O vetorizador acima foi ajustado nos três documentos. Agora, três documentos novos:

  • "O gato comeu o gato."
  • "O cachorro latiu."
  • "Um felino adormeceu."
Preveja. O que acontece com "latiu"? Que vetor "Um felino adormeceu." vira?

Palavras nunca vistas não têm coluna


[[0 1 0 0 2 0 0 0]
 [1 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0]]
  
  • "latiu" é descartada sem aviso.
  • "um felino adormeceu" é feita só de palavras nunca vistas: vira o vetor nulo.
Um vetorizador é uma etapa ajustada, como um escalonador: ajuste-o só nos documentos de treino. Palavras que só existem no teste não podem definir as colunas.

Contagem ou presença: binary=True


[[0 1 0 0 1 1 0 0]
 [1 1 1 0 1 0 1 0]
 [0 0 0 1 1 0 0 1]]
  

O 2 de d3 sob gato virou 1.

textos curtos

títulos, tweets, consultas: uma palavra raramente se repete, então as duas versões são quase idênticas

documentos longos

as contagens deixam uma única palavra muito repetida dominar o vetor

Etapa 2 · quão parecidos são dois documentos?

Comparando dois sacos: o cosseno

\[ \cos(x_a, x_b) = \frac{x_a \cdot x_b}{\lVert x_a \rVert\, \lVert x_b \rVert} \]

Para contagens: de 0 (nenhuma palavra em comum) a 1 (as mesmas palavras nas mesmas proporções).

Preveja. d1 compartilha comeu e gato com d2 e só gato com d3 (que a tem duas vezes). Qual par é mais parecido?

Contar e comparar, passo a passo

Os três documentos: cada um dos 12 tokens soma um na sua célula e depois cada par é comparado pelo cosseno. Preveja. Qual par é o mais parecido e por quanto?

Por que o ângulo e não a distância?

Cole d1 duas vezes e compare o resultado com d1:


"O gato comeu o peixe."                          [0 1 0 0 1 1 0 0]
"O gato comeu o peixe. O gato comeu o peixe."    [0 2 0 0 2 2 0 0]
  
Preveja. Qual é a distância euclidiana entre eles? E o cosseno?

distância euclidiana

1,732
\(\sqrt{3}\): cresce com a diferença de comprimento

cosseno

1,000
só olha a direção

O comprimento de um documento não é o assunto dele

É por isso que a busca de vizinhos e o agrupamento de textos usam metric='cosine' ou dividem antes cada linha pelo seu comprimento (o que o vetorizador do TF-IDF, frequência do termo × frequência inversa nos documentos, faz por padrão).
Etapa 3 · o que o saco joga fora?

A ordem das palavras se perde

  • "O cachorro mordeu o homem."
  • "O homem mordeu o cachorro."
Preveja. Qual é o cosseno entre essas duas frases?
atributosvetorescosseno
palavras sozinhas (3 colunas)[1, 1, 1] e [1, 1, 1]1,00
+ bigramas (7 colunas)"cachorro mordeu", "mordeu homem" só na primeira; "homem mordeu", "mordeu cachorro" só na segunda0,60

Os bigramas recuperam a ordem local, com um preço

  • Com palavras sozinhas, as duas frases são o mesmo vetor: quem mordeu quem desapareceu.
  • ngram_range=(1, 2) acrescenta pares de tokens vizinhos e o cosseno cai para 0,60.
  • O preço: mais colunas, quase todas raras.
O bigrama junta tokens que ficam vizinhos depois da tokenização: o "o" foi descartado, então "mordeu o homem" deu "mordeu homem".

Simulador: monte o saco você mesmo

Preveja. Carregue o preset ordem: as duas primeiras frases vão receber vetores diferentes? Depois marque incluir bigramas.

Resumo

  1. Um documento vira as contagens das suas palavras, uma coluna por palavra do vocabulário; a ordem das palavras é jogada fora.
  2. O fit fixa o vocabulário; palavras nunca vistas são descartadas. Ajuste só nos documentos de treino.
  3. binary=True guarda só a presença, o que importa em documentos longos.
  4. Compare documentos pelo cosseno: comprimento não é assunto.
  5. A ordem se perde: "o cachorro mordeu o homem" = "o homem mordeu o cachorro". Os bigramas recuperam a ordem local, com muito mais colunas.
Lab fundamental · cerca de 25 min, em duplas

Bag-of-words em posts reais, passos 1 a 5

  • Quatro newsgroups (computação gráfica, beisebol, eletrônica, cristianismo), cerca de 2.100 posts; só scikit-learn.
  • Uma pergunta: os posts mais parecidos falam do mesmo assunto? A concordância de vizinhos responde (0,251 por acaso).
  • Passos: carregar os posts · a matriz de contagens · do que cada newsgroup fala · encolhendo o vocabulário · contagens, presença, stop words.
  • Em todo passo, responda o Preveja antes de rodar. Simulação: uma lista de stop words aprendida dos dados (passo 5).
  • Baixe o notebook do lab e abra no Jupyter ou no Colab.

Ritmo: passos 1 e 2 em 5 min; passos 3 e 4 em 8 min; passo 5 e a simulação em 12 min.