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
- Contar as palavrasa matriz de contagens, CountVectorizer, contagem ou presença
- Comparar dois sacossimilaridade de cosseno: o ângulo, não a distância
- 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?
| atributos | vetores | cosseno |
| 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 segunda | 0,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
- Um documento vira as contagens das suas palavras, uma coluna por palavra do vocabulário; a ordem das palavras é jogada fora.
- O
fit fixa o vocabulário; palavras nunca vistas são descartadas. Ajuste só nos documentos de treino.
binary=True guarda só a presença, o que importa em documentos longos.
- Compare documentos pelo cosseno: comprimento não é assunto.
- 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.