LDA, NMF e BERTopic, do clássico ao moderno
alocação latente de Dirichlet: uma história probabilística de como as palavras são escritas
fatoração de matrizes não negativas da matriz TF-IDF (frequência do termo × frequência inversa nos documentos)
sentence embeddings + UMAP + HDBSCAN + uma variante do TF-IDF
Dois corpora: 11 frases escritas à mão e 2.155 posts reais de quatro fóruns (o fórum fica escondido dos modelos, para conferi-los).
"Esportes" dá probabilidade alta a team, game, goal e quase nenhuma a oven. Um documento é uma mistura: 80% esportes, 20% espaço.
LDA e também a NMF, com pesos não negativos
Cada documento pertence a um tópico ou a nenhum; as palavras do tópico são calculadas depois, para descrever o grupo.
BERTopic
| doc | team | game | goal | rocket | launch | moon | bread | bake |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 |
| 3 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 |
| 6 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
| 9 | 1 | 1 | 0 | 1 | 1 | 0 | 0 | 0 |
| 10 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 |
11 frases, 53 palavras mantidas, um vocabulário de 33 (sem as stop words do inglês).
Três temas: esportes, espaço e culinária; as duas últimas frases os misturam.
Latent Dirichlet Allocation (Blei, Ng & Jordan, 2003):
Não é uma afirmação de que as pessoas escrevem assim. A ordem das palavras não entra: contagens de bag-of-words bastam.
Um documento 80% esportes, 20% espaço:
\(p(\textit{team}) = 0{,}8 \times 0{,}40 + 0{,}2 \times 0{,}05 = 0{,}33\)
\(p(\textit{rocket}) = 0{,}8 \times 0{,}05 + 0{,}2 \times 0{,}40 = 0{,}12\)
Seguindo a história, 4 das 12 posições sortearam o tópico espaço; são exatamente aquelas onde aparecem moon, orbit, rocket, orbit.
| \(\alpha\) | maior fatia |
|---|---|
| 0,1 | 0,89 |
| 1 | 0,62 |
| 10 | 0,42 |
No scikit-learn: doc_topic_prior e topic_word_prior, ambos \(1/k\) por padrão: poucos tópicos por documento, poucas palavras por tópico.
Preveja. Com \(\alpha = 0{,}1\), os documentos sorteados saem de uma cor só ou das três?
Quatro fóruns do 20 Newsgroups (computação gráfica, hóquei, espaço, religião); 5.725 palavras de 3+ letras em pelo menos 5 posts e no máximo em metade deles.
| jpeg don pts like think play period gif |
| god space people think just jesus time like |
| team game hockey season games nhl play year |
| image edu data graphics space available software program |
os tópicos: um peso para cada palavra
quanto de cada tópico um documento contém
Lee & Seung (1999): o mesmo formato da PCA (análise de componentes principais), mais a restrição de toda entrada ser \(\ge 0\). Aqui \(X\) é a TF-IDF.
Tópicos: launch rocket satellite orbit · bread oven bake fresh · team game goal won
Divisão limpa, onde a LDA falhou 19 vezes em 20.
init='nndsvda' parte de uma SVD (decomposição em valores singulares), não de um ponto aleatório: um dos motivos da estabilidade.
| frase | espaço | culinária | esportes |
|---|---|---|---|
| 0 (esportes) | 0,00 | 0,00 | 0,71 |
| 3 (espaço) | 0,62 | 0,00 | 0,00 |
| 9 team watched the rocket launch… | 0,29 | 0,00 | 0,45 |
| 10 astronauts ate fresh bread… | 0,10 | 0,41 | 0,00 |
Preveja. A partir de pesos aleatórios, aperte passo: as linhas da NMF terminam como temas inteiros ou como contrastes, como as da SVD? O erro dela chega ao da SVD?
| graphics thanks files image program file know windows |
| god jesus people believe christ faith bible christians |
| game team hockey players play games season nhl |
| space nasa launch shuttle moon orbit lunar earth |
Uma rodada em um corpus: o lab encontra um corpus em que a ordem se inverte.
Não há rótulos para validar: a nota precisa vir dos próprios documentos.
o quanto a LDA se surpreende com posts separados; menor é melhor; só para modelos probabilísticos
a informação mútua pontual normalizada: as palavras do topo aparecem juntas nos documentos?
À mão: dos 2.155 posts, 304 têm god, 159 jesus e 101 as duas; se fossem independentes, seriam 1,04%; observado 4,69%: NPMI = 0,492.
Com \(k = 4\): coerência da LDA 0,224 e diversidade 0,85; da NMF, 0,369 e 1,00.
A perplexidade só sobe: lida ao pé da letra, recomenda \(k = 2\); e ela não acompanha o que as pessoas acham interpretável.
Com as 20 primeiras palavras de cada post: NMF 0,12, LDA 0,03.
Nos posts de 20 palavras, um k-means simples nos embeddings chega a ARI 0,582, cinco vezes o da NMF.
Cada post → 384 números com o all-MiniLM-L6-v2 (pequeno, em inglês, rápido numa CPU).
min_dist=0.0 junta bem os pontos parecidos, que é o que um agrupador por densidade quer.random_state.min_cluster_size=10 e da densidadeHóquei (516) e religião (554) viram um grupo grande cada; computação gráfica e espaço se quebram em muitos pequenos (formatos de arquivo, placas de vídeo, a Lua…).
min_cluster_size, um valor por vezPreveja. Suba min_cluster_size de 2 a 40: o número de tópicos cai aos poucos?
Junte os documentos de um grupo num pseudodocumento; depois, um TF-IDF por classe (c-TF-IDF):
\[ \text{c-TF-IDF}(t, c) = \frac{n_{t,c}}{\sum_{t'} n_{t',c}} \times \log\!\Big(1 + \frac{A}{f_t}\Big) \]À mão, três grupos das frases escritas à mão: 16, 13 e 14 palavras, \(A = 14\).
\(\tfrac{3}{16} \times \log(1 + 14/3) = 0{,}325\)
\(\tfrac{2}{16} \times \log 8 = 0{,}260\)
O transformador do próprio BERTopic dá exatamente a mesma matriz.
| grupo | posts | palavras do topo |
|---|---|---|
| −1 | 431 | space jpeg launch image (os outliers) |
| 1 | 567 | god jesus people church |
| 0 | 520 | team game hockey play |
| 15 | 66 | image graphics package processing |
| 9 | 55 | card mode vesa vga |
| 23 | 52 | moon lunar prize money |
A classe BERTopic encadeia os mesmos quatro passos: mesma partição (ARI 1,0), mesmas palavras do topo, só renumeradas por tamanho.
| tópico 2, nomeado por… | palavras do topo |
|---|---|
| vetorizador padrão | image and for of to it or the graphics with |
| sem stop words | image graphics package processing software data analysis … |
| KeyBERTInspired | graphical graphics rtrace plots tools interactive plotting … |
update_topics as troca e as atribuições de post a tópico ficam idênticas.Os mesmos 2.155 posts, 24 tópicos para os três, duas sementes cada. Preveja antes: de quem são os tópicos mais puros?
| modelo | semente | tópicos | outliers | coerência | diversidade | homogeneidade |
|---|---|---|---|---|---|---|
| LDA | 42 | 24 | 0% | 0,265 | 0,72 | 0,526 |
| NMF | 42 | 24 | 0% | 0,391 | 0,92 | 0,646 |
| BERTopic | 42 | 24 | 20% | 0,251 | 0,88 | 0,927 |
| LDA | 43 | 24 | 0% | 0,276 | 0,70 | 0,574 |
| NMF | 43 | 24 | 0% | 0,407 | 0,91 | 0,644 |
| BERTopic | 43 | 16 | 10% | 0,295 | 0,82 | 0,662 |
| LDA | NMF | BERTopic | |
|---|---|---|---|
| um tópico é | uma distribuição sobre palavras | uma linha não negativa de \(H\) | um grupo, nomeado pelo c-TF-IDF |
| número de tópicos | fixado de antemão | fixado de antemão | encontrado pelo HDBSCAN |
| documentos curtos | fraca | fraca | forte |
| outliers | nenhum | nenhum | explícitos (−1) |
| dependência da semente | forte | menor (início por SVD) | sim, até o número de tópicos |
| custo | barato, CPU | o mais barato, CPU | modelo de embeddings; uma GPU ajuda |
Sem uma lista, os tópicos são nomeados por the, of, to. Uma lista na língua errada não ajuda: o tópico 6 aqui é van, het, een, de posts em holandês.
O reduce_outliers reatribui os 431. Homogeneidade em todos os posts: 0,822 (c-TF-IDF) ou 0,882 (embeddings), abaixo de 0,927.
min_cluster_size de 10 para 15: alguns tópicos a menos ou muitos?| min_cluster_size | tópicos | outliers |
|---|---|---|
| 5 | 96 | 28% |
| 10 | 24 | 20% |
| 15 | 5 | 0% |
| 25 | 3 | 0% |
Varra alguns valores e leia os tópicos; para juntar tópicos sem reagrupar, reduce_topics.
Some aos embeddings um ruído de cerca de um milionésimo (o tamanho das diferenças entre CPU e GPU), mantendo todas as sementes:
| ruído, semente 0 | 24 tópicos, ARI com o original 0,908 |
| ruído, semente 1 | 24 tópicos, ARI 0,910 |
| ruído, semente 2 | 3 tópicos, ARI 0,514 |
min_cluster_size.!pip install bertopic antes.