Aprendizado Não Supervisionado
2026-08-30
Duas limitações em ambos: sem forma paramétrica, os dados são o modelo; e ambos sofrem a maldição da dimensionalidade — volta no bloco final desta aula, com os \(30\) atributos do Breast Cancer Wisconsin.
A Aula 2 já mostrou que \(d_K(\mathbf{x})\) seria reaproveitada como métrica de densidade local para construir caminhos num grafo — é esse reaproveitamento que esta aula cumpre.
Nota
A paisagem \(p(\mathbf{x})\) responde “comum ou raro?” ponto a ponto — mas não diz com quais outros pontos um ponto forma um grupo.
Pergunta nova, ainda sem resposta: dado um conjunto de pacientes, quais são parecidos o bastante entre si para merecer o mesmo rótulo?
Saber que um ponto está numa região densa não diz, sozinho, com quais outros pontos ele forma um grupo.
Duas regiões densas separadas por um vale raso: dois grupos. Dois pontos na mesma região densa e contígua, mesmo geometricamente distantes: um grupo só.
“Comum ou raro” é propriedade de um ponto isolado; “parecido com quem” é propriedade de conjuntos de pontos. Essa segunda pergunta é clustering — o objeto desta aula.
Transformar uma paisagem de densidade numa partição de grupos se desdobra em quatro perguntas, uma por bloco:
1. Densidade sozinha não define grupo — o que deveria significar “cluster”?
2. Como construir isso computacionalmente, sem escolher quantos grupos existem a priori?
3. Isso é um problema de grafos — qual estrutura captura toda a hierarquia de clusters de uma vez?
4. Como decidir quais clusters encontrados são reais, e quais são flutuação amostral?
Duas luas entrelaçadas (sintético, controlado). Mesma ferramenta da Aula 2 — KDE — aplicada aqui: qual é a paisagem de densidade?
A paisagem de densidade acima parece ter, a olho nu, duas cristas separadas por um vale. Isso já resolve sozinho o problema de encontrar os grupos, ou falta alguma coisa?
Dica: pense se “ter uma paisagem de densidade” é a mesma coisa que “ter uma lista de quais pontos pertencem a qual grupo” — e o que teria que acontecer, algoritmicamente, para ir de um para o outro.
Resposta — densidade x grupo
Voltando à pergunta: densidade ponto a ponto (Aula 2) é matéria-prima, não o produto final — falta o passo de transformar essa paisagem numa partição de grupos, exatamente o que o resto da aula constrói.
Pense em \(p(\mathbf{x})\) como uma paisagem: montanhas = regiões densas, vales = regiões raras.
Um cluster é uma montanha inteira — não importa o formato do contorno, só que seja um bloco conectado de terreno alto, separado dos outros por um vale.
Algoritmo: não “que centro fixo está mais perto?”, mas “caminhando por terreno alto, até onde eu chego sem descer a um vale?”
Uma lua inteira, mesmo curva, é uma trilha alta conectada de ponta a ponta — mesmo que as duas pontas estejam geometricamente longe em linha reta.
Duas luas: HDBSCAN (o algoritmo desta aula) \(=100\%\) de acurácia contra o rótulo verdadeiro.
Dois anéis concêntricos (forma ainda mais hostil à ideia de “bola em torno de um centro” — o anel externo envolve o interno por todos os lados): HDBSCAN também \(=100\%\).
Nenhum dos dois resultados depende de saber, de antemão, a forma certa do cluster.
(i) Formalizar “montanha” como conjunto de nível de densidade (Bloco 3).
(ii) Transformar isso num grafo, com uma distância que “sabe” onde é vale e onde é montanha (Bloco 4).
(iii) Extrair desse grafo uma única estrutura com toda a hierarquia de clusters possível, de uma vez (Bloco 5).
Duas montanhas separadas por um vale raso (densidade baixa, mas não zero) — “andar por terreno alto” as trata como um cluster só, ou dois?
Dica: pense no que muda se o vale for rebaixado ainda mais, até chegar a densidade zero, comparado ao vale raso original.
Resposta — cluster só ou dois clusters?
Voltando à pergunta: a resposta depende de \(\lambda\) — e é exatamente essa dependência que o Bloco 3 transforma em definição formal.
Corte transversal 1D: eixo \(\mathbf{x}\), densidade \(p(\mathbf{x})\) no eixo vertical — duas “montanhas” separadas por um “vale”.
\definecolor{curvecolor}{RGB}{93,109,126}
\definecolor{highlight}{RGB}{0,133,202}
\definecolor{threshold}{RGB}{224,60,49}
\begin{tikzpicture}
% eixos
\draw[->, thick, black!70] (-0.3,0) -- (9.6,0) node[right, font=\small] {$\mathbf{x}$};
\draw[->, thick, black!70] (0,-0.2) -- (0,4.4) node[above, font=\small] {$p(\mathbf{x})$};
% curva de densidade: duas montanhas, um vale
\draw[smooth, thick, color=curvecolor]
plot coordinates {
(0,0.3) (0.7,0.4) (1.3,0.9) (1.8,2.0) (2.2,3.4) (2.6,3.9) (3.0,3.4)
(3.4,2.0) (3.9,0.9) (4.5,0.6) (5.1,0.9) (5.6,2.0) (6.0,3.4) (6.4,3.9)
(6.8,3.4) (7.3,2.0) (7.8,0.9) (8.3,0.4) (9.0,0.3)
};
% linha de corte lambda
\draw[dashed, thick, color=threshold] (-0.1,2.6) -- (9.3,2.6);
\node[left, font=\small, color=threshold] at (-0.15,2.6) {$\lambda$};
% duas componentes de L_lambda (trechos da curva acima de lambda)
\draw[very thick, color=highlight]
plot[smooth] coordinates { (2.0,2.6) (2.2,3.4) (2.6,3.9) (3.0,3.4) (3.2,2.6) };
\draw[very thick, color=highlight]
plot[smooth] coordinates { (5.8,2.6) (6.0,3.4) (6.4,3.9) (6.8,3.4) (7.0,2.6) };
% vale
\draw[dotted, color=threshold] (4.5,0) -- (4.5,0.6);
\node[below, font=\scriptsize, color=threshold] at (4.5,-0.35) {vale};
% rotulos das componentes
\node[below, font=\scriptsize, color=highlight] at (2.6,-0.35) {componente 1};
\node[below, font=\scriptsize, color=highlight] at (6.4,-0.35) {componente 2};
\node[font=\small, color=highlight] at (4.7,5.1) {$L_\lambda=\{\mathbf{x}:p(\mathbf{x})\ge\lambda\}$};
\draw[->, color=highlight] (4.3,3.85) -- (3.0,3.55);
\draw[->, color=highlight] (5.5,3.85) -- (6.4,3.65);
\node[font=\small, color=curvecolor] at (2.6,4.15) {montanha};
\node[font=\small, color=curvecolor] at (6.4,4.15) {montanha};
\end{tikzpicture}Limiar \(\lambda\) (linha vermelha): \(L_\lambda\) = trecho do eixo onde a curva está acima da linha — aqui, 2 componentes, uma por montanha (o vale fica abaixo de \(\lambda\)).
Baixar \(\lambda\) até abaixo da altura do vale funde as duas componentes numa só — verificado a seguir com densidade real (KDE, duas luas).
Conjunto de nível de densidade, limiar \(\lambda\ge 0\): \[L_\lambda = \{\mathbf{x} : p(\mathbf{x}) \ge \lambda\}\]
Definição central da aula: um cluster, num nível \(\lambda\) fixo, é uma componente conexa de \(L_\lambda\) — não precisa ser convexa, só precisa ser percorrível inteira sem descer abaixo de \(\lambda\).
Combinatório (Bloco 2): sem modelo de densidade — parte o espaço por proximidade a um conjunto fixo de protótipos. Sempre gera regiões convexas (tesselação de Voronoi); não captura luas nem anéis.
Modelagem por mistura (Aula 4): assume densidade paramétrica com \(K\) componentes (ex.: \(K\) gaussianas) — cluster = “de qual componente este ponto veio?”, estimado por EM.
“Mode seeking” (esta aula): não assume forma nenhuma — estima as modas da densidade diretamente. Tradução livre (p. 507): “observações mais próximas de cada moda definem os clusters.”
Os três respondem à mesma pergunta (“quem vai com quem?”), com suposições bem diferentes sobre a forma dos dados — só o terceiro não assume nenhuma.
Combinatório e mistura só sabem traçar fronteiras retas/elípticas — cada lua fica cortada ao meio. Só o mode seeking (direita), sem suposição de forma, acompanha o contorno real de cada lua.
\(\lambda\) alto: só os picos mais extremos sobrevivem — poucas regiões pequenas, bem separadas.
\(\lambda\) caindo: cada região cresce; em algum ponto, duas regiões antes separadas se tocam e se fundem.
\(\lambda=0\): \(L_0\) é o suporte inteiro — uma componente só (supondo suporte conexo).
Hierarquia indexada por \(\lambda\): decrescer \(\lambda\) só funde componentes, nunca separa — mesma lógica do dendrograma (Bloco 5).
\(\lambda=0{,}20\): as duas luas são regiões separadas de \(L_\lambda\).
\(\lambda=0{,}04\): o vale entre as luas já foi absorvido — uma componente conexa só.
Problema aberto: qual \(\lambda\) escolher? Resposta no Bloco 6 — não escolher um único \(\lambda\), medir persistência ao longo de toda a faixa.
No limite \(\lambda \to \infty\), quantas componentes conexas tem \(L_\lambda\), em geral?
Dica: pense no que sobra de “terreno acima de \(\lambda\)” quando \(\lambda\) é maior que a densidade máxima de qualquer região dos dados.
Resposta — o limite \(\lambda \to \infty\)
Voltando à pergunta: o vale raso do Bloco 2 agora tem nome — depende inteiramente de onde \(\lambda\) corta. O Bloco 4 constrói a ferramenta computável para não depender de escolher \(\lambda\) à mão.
Aula 2: \(p(\mathbf{x})\approx K/(NV)\), \(V\) = volume da bola de raio \(d_K(\mathbf{x})\) que captura \(K\) vizinhos. \(V\) cresce com \(d_K\) — o raio está no denominador do estimador.
Não é coincidência: \(d_K(\mathbf{x})\) pequeno \(\Rightarrow\) bola pequena bastou \(\Rightarrow\) região densa; \(d_K(\mathbf{x})\) grande \(\Rightarrow\) precisou de raio grande \(\Rightarrow\) região rara.
Hoje: mesmo número, novo nome — core distance — \(\mathrm{core}_K(\mathbf{x}) = d_K(\mathbf{x})\) — e novo uso: peso de aresta num grafo.
Nota
1. \(\mathrm{core}_K(x)\) pequeno \(\Leftrightarrow\) região densa.
2. Distância bruta \(d(a,b)\) não diz nada sobre densidade da vizinhança de \(a\) ou \(b\).
3. Cluster = conectividade dentro de terreno alto — a distância do grafo precisa penalizar caminhos por regiões raras.
\(a\) numa região densa (muita gente parecida por perto); \(b\) sozinho, longe de todo vizinho — mas \(d(a,b)\) pequeno.
Conectar \(a,b\) pela distância bruta ignora que \(b\) está, na prática, isolado — \(b\) só “parece” perto de \(a\), sem trilha densa ligando os dois.
\[d_{\mathrm{mreach}}(a,b) = \max\bigl(\mathrm{core}_K(a), \mathrm{core}_K(b), d(a,b)\bigr)\]
Se \(b\) está isolado (\(\mathrm{core}_K(b)\) grande): \(d_{\mathrm{mreach}}(a,b) \ge \mathrm{core}_K(b)\) para qualquer \(a\) — \(b\) nunca parece mais perto de ninguém do que permite sua própria distância ao vale mais próximo.
Se \(a,b\) moram na mesma região densa: \(d_{\mathrm{mreach}}(a,b)\) continua pequeno — a distância bruta domina o máximo.
Nunca aproxima, só afasta: \(d_{\mathrm{mreach}}(a,b)\ge d(a,b)\) sempre — acalma isolados sem alterar nada dentro de uma região já densa.
# Núcleo pequeno (K=5) sobre os dois atributos reais que vão sustentar
# o Bloco 6 -- ilustra a "calma" da alcançabilidade mútua em 5 pacientes
# escolhidos deliberadamente: 4 numa vizinhança densa, 1 isolado.
_tree_2d = cKDTree(X_2d)
_core_2d = core_distance(X_2d, K=5)
_isolado = np.argmax(_core_2d) # paciente com o maior core distance
_denso = np.argsort(_core_2d)[:4] # 4 pacientes na região mais densa
_a, _b = _denso[0], _isolado
_d_raw = np.linalg.norm(X_2d[_a] - X_2d[_b])
_d_mreach = max(_core_2d[_a], _core_2d[_b], _d_raw)
print(f"core({_a})={_core_2d[_a]:.3f} core({_b})={_core_2d[_b]:.3f} "
f"d_bruta={_d_raw:.3f} d_mreach={_d_mreach:.3f}")core(418)=0.033 core(461)=1.288 d_bruta=5.388 d_mreach=5.388
Se \(\mathrm{core}_K(a) = \mathrm{core}_K(b) = 0\) (dois pontos coincidentes com pelo menos \(K\) outros pontos na mesma posição exata), o que \(d_{\mathrm{mreach}}(a,b)\) vale?
Dica: releia a fórmula — o que o \(\max\) faz quando dois dos três termos são zero?
Resposta — o caso extremo \(\mathrm{core}_K=0\)
Voltando à pergunta: quando ambos os núcleos são pequenos (região densa dos dois lados), a alcançabilidade mútua colapsa na distância bruta — exatamente o comportamento que o Bloco 5 vai usar para construir o grafo completo.
Escolha um limiar \(\varepsilon\). Monte o grafo: aresta \((u,v)\) sempre que \(d_{\mathrm{mreach}}(u,v)\le\varepsilon\).
Componentes conexas = clusters. Pontos sem aresta nenhuma (\(\mathrm{core}_K\) maior que \(\varepsilon\)) ficam isolados = ruído.
Nada novo: é a mesma lógica de “conectar por limiar” do DBSCAN — só que sobre \(d_{\mathrm{mreach}}\), não \(d\) bruta.
DBSCAN clássico \((\varepsilon,\text{minPts})\): \(p\) é núcleo se \(|N_\varepsilon(p)|\ge\text{minPts}\); conecta núcleos \(p,q\) direto se \(d(p,q)\le\varepsilon\); cluster = cadeia dessas conexões (definição recursiva).
1. \(p\) é núcleo se \(\ge\) minPts pontos (contando \(p\)) estão a \(\le\varepsilon\) dele.
2. Escolha um núcleo ainda não visitado, abra um cluster novo, ponha-o numa fila.
3. Tire \(q\) da fila; todo vizinho \(r\) a \(\le\varepsilon\) entra no cluster; se \(r\) também é núcleo e não visitado, marque-o e acrescente-o à fila — só núcleos propagam a busca (a cadeia).
4. Repita até a fila esvaziar; volte ao passo 2 para o próximo núcleo não visitado.
5. Quem nunca entrou em nenhum cluster vira ruído.
O passo 3 é a cadeia: a busca só continua a partir de um núcleo — um ponto de borda entra no cluster, mas não propaga. Por isso \(p\) e um \(z\) distante podem cair no mesmo cluster sem \(d(p,z)\le\varepsilon\), desde que exista uma cadeia de núcleos entre eles.
Detalhe que importa: \(N_\varepsilon(p)\) conta o próprio \(p\) (convenção do DBSCAN original/scikit-learn), mas \(\mathrm{core}_K(p)\) não conta \(p\). O \(K\) certo é \(K=\text{minPts}-1\), não \(\text{minPts}\) (verificado numericamente contra o DBSCAN do scikit-learn).
Com \(K=\text{minPts}-1\): “\(p\) núcleo” \(\iff\) \(\mathrm{core}_K(p)\le\varepsilon\) — a própria definição de core distance.
Logo: “\(p,q\) núcleos e \(d(p,q)\le\varepsilon\)” \(\iff\) \(\max(\mathrm{core}_K(p),\mathrm{core}_K(q),d(p,q))\le\varepsilon\) \(\iff\) \(d_{\mathrm{mreach}}(p,q)\le\varepsilon\) — mesma aresta, mesmo grafo, mesmos clusters (DBSCAN*, Campello, Moulavi & Sander 2013).
Grafo completo, pesos \(d_{\mathrm{mreach}}(i,j)\): \(N\) vértices, \(N(N-1)/2\) arestas — conectado, mas redundante (vários caminhos possíveis entre o mesmo par).
Árvore geradora (spanning tree): subgrafo que conecta todos os \(N\) vértices com só \(N-1\) arestas, sem ciclo — o mínimo de arestas que ainda mantém tudo ligado.
A Árvore Geradora Mínima (MST)
Entre todas as árvores geradoras possíveis, a MST é a que minimiza a soma dos pesos das suas \(N-1\) arestas.
Intuição: nunca inclui uma aresta cara quando existe uma rota mais barata entre os mesmos dois vértices por outro lugar da árvore — toda conexão redundante e cara é descartada.
Ideia geral (antes da regra específica de hoje): começa com \(N\) clusters, um por ponto; a cada passo funde os dois clusters mais próximos num só — \(N-1\) fusões até sobrar um cluster com todo mundo.
Cada fusão num nível de dissimilaridade maior que a anterior — a sequência de fusões é a hierarquia (o dendrograma).
Falta definir uma coisa: “distância entre dois clusters” (não entre dois pontos) — várias regras possíveis; a aula usa uma específica, a seguir.
A regra desta aula: distância entre clusters = distância do par mais próximo, um de cada lado. ESL (p. 523), tradução livre: “a dissimilaridade intergrupo [é] a do par mais próximo: \(d_{SL}(G,H)=\min_{i\in G,i'\in H} d_{ii'}\)” — o “vizinho mais próximo”.
Cortar as \(k-1\) arestas mais pesadas da MST = as \(k\) componentes de ligação simples com \(k\) clusters.
Não é intuitivo — mas também não é coincidência: é propriedade de caminhos em grafos.
Ligação simples junta \(p,q\) num nível \(\tau\) \(\iff\) existe cadeia \(p\to\dots\to q\) com cada passo \(\le\tau\) (componente conexa do grafo completo cortado em \(\tau\) — mesmo fecho transitivo do Bloco 4).
Custo de um caminho = maior aresta nele (“elo mais fraco”). \(p,q\) conectam em \(\tau\) assim que \(\tau\) atinge o custo mínimo entre todos os caminhos possíveis.
Por Que a MST Basta (Caminho de Gargalo Mínimo)
O caminho entre \(p\) e \(q\) dentro da MST (único) é sempre um caminho de custo mínimo no grafo completo — nenhuma outra rota tem elo mais fraco mais barato.
Por isso: cortar arestas \(>\tau\) da MST = cortar arestas \(>\tau\) do grafo completo — mesmas componentes, os clusters de ligação simples em \(\tau\).
O exemplo vai gerar duas partições dos mesmos pontos (MST-corte vs. ligação simples) — a alegação é que são idênticas. Para 7 pontos dá para conferir olhando; em geral, precisa de um número.
Índice de Rand: olha todo par de pontos e pergunta se as duas partições concordam sobre ele (mesmo cluster nas duas, ou clusters diferentes nas duas). Fração de pares em concordância.
Problema: até duas partições aleatórias concordam em vários pares só por acaso — isso infla o índice bruto.
ARI (Índice de Rand Ajustado)
Corrige o índice de Rand subtraindo a concordância esperada por acaso. \(\mathrm{ARI}=1\): partições idênticas (a menos de renomear rótulos). \(\mathrm{ARI}\approx 0\): concordância não melhor que o acaso. (Hubert & Arabie, 1985)
Na figura anterior: 7 pontos, 3 grupos visuais — A (\(0,1,2\)), B (\(3,4,5\)), ponto isolado \(6\). MST tem \(N-1=6\) arestas; as duas tracejadas em vermelho são as duas mais pesadas.
\(k=2\) (corta 1 aresta mais pesada): MST dá \(\{0..5\},\{6\}\) — ligação simples dá o mesmo (ARI \(=1{,}00\)).
\(k=3\) (corta 2 mais pesadas): MST dá \(\{0,1,2\},\{3,4,5\},\{6\}\) — ligação simples de novo idêntico (ARI \(=1{,}00\)).
Curioso: A e B se fundem antes de \(6\) (\(6{,}14 < 6{,}22\)) — “vizinho mais próximo” nem sempre é o mais intuitivo à primeira vista, mas é correto pela definição.
Uma única árvore de \(N-1\) arestas contém a hierarquia inteira — para qualquer \(k\), corte as \(k-1\) arestas mais pesadas, sem recálculo.
ESL (p. 524), tradução livre, sobre o defeito da ligação simples: “tendência a combinar […] observações ligadas por uma série de observações intermediárias próximas […] chamado de encadeamento”.
Encadeamento + “que \(k\)/\(\lambda\) escolher?” (Bloco 3) → o Bloco 6 ataca os dois.
Se um único ponto de ruído for inserido exatamente no meio do “vale” entre dois clusters genuinamente distintos, o que acontece com a MST e com o clustering por ligação simples resultante?
Dica: pense no “encadeamento” citado do ESL — o que uma única observação intermediária bem posicionada consegue fazer.
Resposta — um ponto de ruído no vale
min_cluster_size/persistência no Bloco 6.Voltando à pergunta: encadeamento não é resolvido só pela alcançabilidade mútua — o Bloco 6 ataca o problema de frente, exigindo que um cluster “sobreviva” por um tamanho mínimo, não só por uma cadeia fina de pontos.
(i) Um \(\lambda\) fixo não serve para clusters de densidades muito diferentes entre si.
(ii) Encadeamento pode ligar, por um fio fino, dois grupos que “deveriam” ser distintos.
HDBSCAN (Campello, Moulavi & Sander, 2013) ataca os dois com uma ideia nova: persistência.
Hierarquia completa = um filme: em cada quadro (\(\lambda\) de corte), alguns clusters existem, outros não.
Um cluster que sobrevive por muitos quadros seguidos é mais “real” do que um que aparece e desaparece rápido.
Do quadro 1 ao 3, o cluster A (\(\{0,1,2\}\)) e o B (\(\{3,4,5\}\)) sobrevivem inteiros por uma faixa longa — cada divisão nova cria um ramo (o quadro seguinte da árvore); onde dois ramos se fundem, o nó resultante é o cluster-pai dos dois.
Ramo (ou nó): um cluster candidato em algum nível da hierarquia — um pedaço do dendrograma que ainda não se dividiu. Quando um ramo se divide em dois, ele vira o cluster-pai dos dois ramos-filhos.
\(\lambda\) aqui é a mesma ideia do Bloco 3 (nível de corte), agora sobre a árvore de \(d_{\mathrm{mreach}}\) em vez da densidade \(p(\mathbf{x})\) direto: \(\lambda = 1/d_{\mathrm{mreach}}\), então \(\lambda\) alto = corte raso, ainda separado; \(\lambda\) baixo = corte fundo, já fundido.
1. Árvore condensada — percorra a hierarquia de baixo para cima; a cada divisão, se um dos dois ramos-filhos tem menos que min_cluster_size pontos, ele não vira ramo novo — os pontos dele somam como “perda” do cluster-pai. Só sobram como ramos as divisões em que os dois lados são grandes o bastante.
2. Persistência (excesso de massa) — para cada ramo, some, ponto a ponto, a faixa de \(\lambda\) em que aquele ponto pertenceu a esse ramo específico, antes de sair dele (virar ruído ou passar a um ramo-filho). Ramos com persistência alta sobreviveram por uma faixa longa de \(\lambda\) — evidência de estrutura real, não artefato de onde o corte caiu.
Esquemático (números ilustrativos — scikit-learn não expõe a árvore condensada, só o resultado final):
Raiz (cinza) afina conforme pontos “vazam” (linhas finas); em \(\lambda=2{,}0\) ela divide de verdade (os dois lados batem min_cluster_size) em ramo A e ramo B — a raiz vira cluster-pai dos dois ramos-filhos.
Área de cada ramo = persistência: A sobrevive bem mais tempo (\(2{,}0\)–\(5{,}0\)) que B (\(2{,}0\)–\(2{,}3\)) — quase \(10\times\) mais persistente.
\[\text{persistência}(C) = \sum_{p\,\in\,C} \bigl(\lambda_p - \lambda_{\text{nasc}}(C)\bigr)\] Para cada ponto \(p\) de \(C\): quanto \(\lambda\) ele durou dentro de \(C\) antes de sair (virar ruído ou ir a um ramo-filho).
Ramo A (nasce em \(\lambda=2{,}0\)): \(2\) pontos saem em \(\lambda=3{,}0\) (\(2\times1{,}0=2{,}0\)); \(2\) em \(\lambda=4{,}2\) (\(2\times2{,}2=4{,}4\)); os últimos \(2\) em \(\lambda=5{,}0\) (\(2\times3{,}0=6{,}0\)). \(\text{persistência(A)}=2{,}0+4{,}4+6{,}0=12{,}4\).
Ramo B (nasce em \(\lambda=2{,}0\), todos os \(5\) saem juntos em \(\lambda=2{,}3\)): \(\text{persistência(B)}=5\times0{,}3=1{,}5\).
Em cada divisão da árvore condensada, escolha entre “manter o cluster-pai inteiro” ou “dividir nos dois ramos-filhos”, pela opção de maior persistência total (programação dinâmica, de baixo para cima na árvore).
Na figura anterior: \(\text{persistência(A)}\approx12{,}4 \gg \text{persistência(B)}\approx1{,}5\) — a divisão vale a pena por causa de A. A sobrevive como cluster final; B, por ter durado tão pouco, não vira cluster — seus pontos ficam como ruído.
Resultado geral: clusters extraídos de alturas diferentes da árvore — não vem de um único corte horizontal em \(\lambda\).
Clusters encontrados (rótulo: nº de pacientes): {np.int64(-1): np.int64(168), np.int64(0): np.int64(54), np.int64(1): np.int64(347)}
Fração marcada como ruído (-1): 0.295
\(569\) pacientes, radius_worst + concave points_worst, min_cluster_size=15: 2 clusters + \(168\) pacientes como ruído (\(\approx 29{,}5\%\)).
Cluster 0 (\(54\) pacientes): 100% malignos — uma montanha densa e pura, encontrada sem nunca ver o rótulo.
Cluster 1 (\(347\) pacientes): \(315\) benignos + \(32\) malignos (\(\approx 90{,}8\%\) de pureza benigna).
Dos \(212\) pacientes malignos: \(54\) no cluster puro, \(32\) no cluster misto, \(126\) (\(\approx 59{,}4\%\)) em ruído.
Maligno varia mais em apresentação (múltiplos subtipos/estágios) — só uma fração forma montanha densa o bastante para sobreviver como cluster de alta persistência nesses 2 atributos.
ARI \(=0{,}644\) (excluindo ruído) — concordância forte. ARI \(=0{,}493\) (todos, ruído como rótulo próprio).
Não é \(1{,}0\): HDBSCAN não é classificador, não viu o rótulo. Encontrar estrutura alinhada ao diagnóstico, sem supervisão, é o resultado.
Se min_cluster_size fosse reduzido de 15 para 2 no exemplo do Breast Cancer Wisconsin, o que aconteceria com a fração de pacientes marcados como ruído, e por quê?
Dica: pense no que min_cluster_size está, na prática, impedindo de virar cluster.
min_cluster_size para 2 tende a diminuir a fração de ruído, porque ramos muito pequenos da árvore condensada (antes descartados como “perda” do cluster-pai) passam a contar como clusters válidos por si mesmos.min_cluster_size=2 reintroduz, na prática, uma versão do problema de encadeamento (chaining) da ligação simples pura — uma cadeia fina de 2-3 pontos já basta para ser aceita como cluster próprio.min_cluster_size não afeta a fração de ruído — ele só afeta quantos clusters distintos são extraídos, mantendo o total de pontos “ruidosos” constante.min_cluster_size continua sendo, mesmo no HDBSCAN, uma decisão de escala imposta pelo usuário — a persistência decide quais ramos sobrevivem, mas não decide, por si só, o tamanho mínimo que conta como ramo.Resposta — reduzindo min_cluster_size para 2
min_cluster_size continua sendo escolha de escala do usuário — persistência decide quais ramos sobrevivem, não o tamanho mínimo de ramo.Voltando à pergunta: o HDBSCAN troca “escolher \(\lambda\)” por “escolher min_cluster_size” — não elimina a decisão de escala, só a move para um parâmetro mais estável e mais fácil de interpretar (Bloco 7).
(1) \(\mathrm{core}_K(\mathbf{x})=d_K(\mathbf{x})\) (Aula 2): mede densidade local, sem forma paramétrica.
(2) \(d_{\mathrm{mreach}}\): transforma em distância de grafo que acalma pontos isolados.
(3) MST: comprime toda a hierarquia de ligação simples numa única árvore.
(4) Árvore condensada + persistência: extrai os clusters mais estáveis, sem corte global único.
Nenhuma suposição de convexidade — luas e anéis resolvidos de ponta a ponta.
Nenhuma escolha obrigatória de \(K\).
Pontos atípicos podem ser ruído — não forçados a um cluster.
1. min_cluster_size/min_samples ainda é escolha de escala — reduzir demais reintroduz encadeamento (Bloco 6).
2. Herda a maldição da dimensionalidade de \(d_K(\mathbf{x})\) — é literalmente o mesmo número.
min_cluster_size= 5 → 2 cluster(s), 59.2% dos pacientes como ruído
min_cluster_size= 10 → 0 cluster(s), 100.0% dos pacientes como ruído
min_cluster_size= 15 → 0 cluster(s), 100.0% dos pacientes como ruído
min_cluster_size= 20 → 0 cluster(s), 100.0% dos pacientes como ruído
min_cluster_size= 30 → 0 cluster(s), 100.0% dos pacientes como ruído
\(2\) atributos (Bloco 6): \(70{,}5\%\) dos pacientes em algum cluster.
\(30\) atributos, min_cluster_size=5: \(\approx 59{,}2\%\) já é ruído.
\(30\) atributos, min_cluster_size\ge 10: \(100\%\) ruído — nenhum cluster sobrevive.
Mesmo mecanismo da Aula 2: distâncias perdem poder discriminativo, \(d_K\) some, \(d_{\mathrm{mreach}}\) herda, árvore condensada não encontra ramo estável.
Um colega sugere “resolver” a queda de estrutura em 30 dimensões aumentando min_cluster_size até encontrar pelo menos um cluster de novo. Isso resolveria o problema de fundo?
Dica: pense se min_cluster_size grande está atacando a causa (distâncias perdendo poder discriminativo) ou só mudando o limiar de quantos pontos “contam”.
min_cluster_size pode, sim, eventualmente produzir algum cluster de novo — mas isso resolve o sintoma (nenhum cluster aparecia) sem resolver a causa (as distâncias em 30D perderam poder discriminativo).min_cluster_size bem alto em 30D, ele é necessariamente tão confiável estatisticamente quanto o cluster puro de \(54\) pacientes encontrado com \(2\) atributos no Bloco 6.min_cluster_size.Resposta — “resolver” aumentando min_cluster_size
min_cluster_size alto não é automaticamente tão confiável quanto o cluster puro do Bloco 6 — pode ser um artefato do limiar, não estrutura real.Voltando à pergunta: a maldição não tem solução mágica dentro do próprio algoritmo — reduzir dimensionalidade, ou usar conhecimento de domínio para escolher poucos atributos relevantes (como o Bloco 6 fez “na mão”), é o caminho, não um parâmetro a mais.
1. O que é “cluster”? Componente conexa de região de alta densidade — não bola em torno de centróide.
2. Como construir sem escolher \(K\)? \(d_{\mathrm{mreach}}\) + MST, sem parâmetro de forma, só uma escala local (\(K\) do núcleo).
3. Que grafo captura toda a hierarquia? A MST — cortar as \(k-1\) arestas mais pesadas reproduz ligação simples para qualquer \(k\).
4. Como decidir quais clusters são reais? Persistência por excesso de massa na árvore condensada.
HDBSCAN entrega partição rígida: cada ponto é de um cluster, ou é ruído — decisão binária.
Honesto quando clusters são bem separados; força escolha artificial quando dois clusters genuinamente se sobrepõem.
Ponte para a Aula 4
Modelos de Mistura Gaussiana + EM: mesma pergunta de agrupar, mas atribuição probabilística — cada ponto com uma probabilidade por cluster, não um rótulo único. Útil onde o HDBSCAN força escolha.
ESL (p. 507): “modelagem por mistura” era o terceiro paradigma citado desde a Abertura — a Aula 4 fecha o trio (combinatório, mistura, modo).
Um hospital precisa decidir se atribuição rígida (HDBSCAN) ou probabilística (GMM/EM, Aula 4) se ajusta melhor a uma triagem entre dois subtipos de tumor cujos biomarcadores parecem se sobrepor. O que deveria pesar mais nessa escolha?
Dica: pense se a “ambiguidade” observada nos dados é evidência de um vale de densidade genuíno entre os subtipos, ou de uma sobreposição real e contínua entre eles.
Resposta — partição rígida ou probabilística?
Voltando à pergunta: a escolha depende de crer (ou não) que existe um vale de densidade genuíno separando os subtipos — exatamente a pergunta que a Aula 4 equipa o aluno para responder com uma ferramenta nova.
UNICAMP — Instituto de Computação