idade
Pode assumir valores numa escala. A árvore ordena os valores e testa limiares entre vizinhos.
idade ≤ 38,5?APRENDIZAGEM SUPERVISIONADA · ÁRVORE DE DECISÃO
A árvore procura divisões que deixam as classes mais puras. Nesta página, números contínuos, contagens discretas e categorias em texto são tratados diretamente por um algoritmo implementado do zero.
01 · DADOS TABULARES MISTOS
Não é necessário transformar toda categoria textual em um número arbitrário. O algoritmo identifica o tipo da característica e gera candidatos de divisão adequados.
Pode assumir valores numa escala. A árvore ordena os valores e testa limiares entre vizinhos.
idade ≤ 38,5?É uma contagem inteira, mas continua sendo ordenável. Os candidatos também são limiares.
visitas ≤ 2,5?O texto é comparado diretamente. Nesta implementação didática, cada categoria é testada contra as demais.
plano = "Premium"?| idade | visitas | plano | região | compra |
|---|---|---|---|---|
| 22 | 1 | Básico | Norte | Não |
| 29 | 2 | Premium | Norte | Sim |
| 44 | 4 | Intermediário | Sul | Sim |
02 · IMPUREZA DE GINI
Gini vale 0 quando todas as amostras do grupo pertencem à mesma classe. Quanto mais misturado estiver o grupo, maior será sua impureza.
Gini(S) = 1 − Σ pₖ²Para 6 “Sim” e 6 “Não”:
1 − (6/12)² − (6/12)² = 0,50
Gini_div = (nₑ/n)Gini(E) + (n𝒹/n)Gini(D)Os filhos são ponderados pela quantidade de exemplos que recebem.
ganho = Gini_pai − Gini_divO algoritmo escolhe o candidato com o maior ganho.
03 · LABORATÓRIO INTERATIVO
As quatro características formam X; a coluna “compra” é o alvo y. Depois de qualquer alteração, treine novamente para recalcular todos os candidatos.
Use ponto ou vírgula nos números. Plano e região aceitam texto sem qualquer codificação numérica.
| idade contínua | visitas discreta | plano categoria | região categoria | compra alvo y |
|---|
Nós azuis são perguntas; nós verdes e vermelhos são previsões. Ramos ainda não abertos aparecem tracejados.
Veja de onde vêm os números usados para escolher a pergunta.
A linha destacada possui o maior ganho de Gini e será usada pela árvore.
| Característica | Pergunta | Filho “sim” | Filho “não” | Gini ponderado | Ganho |
|---|
Cada ponto representa a árvore após abrir mais uma divisão. A linha vermelha é o erro de classificação; a verde é a acurácia.
Acompanhe as perguntas percorridas da raiz até a folha.
04 · CÓDIGO COMPLETO E EXECUTÁVEL
Copie o programa inteiro. Ele recebe dados mistos sem codificação numérica manual, calcula candidatos e Gini, constrói a árvore, avalia o teste e classifica um novo cliente.
// ============================================================
// ÁRVORE DE DECISÃO: [idade, visitas, plano, comprou]
// Colunas 0 e 1 são numéricas; a coluna 2 contém texto.
// ============================================================
var treino = [
[22, 1, 'Básico', 'Não'], [25, 2, 'Básico', 'Não'],
[31, 4, 'Premium', 'Sim'], [35, 5, 'Premium', 'Sim'],
[42, 2, 'Básico', 'Não'], [45, 6, 'Premium', 'Sim'],
[52, 5, 'Premium', 'Sim'], [55, 1, 'Básico', 'Não']
];
var teste = [
[28, 1, 'Básico', 'Não'], [38, 5, 'Premium', 'Sim'],
[48, 2, 'Básico', 'Não'], [50, 6, 'Premium', 'Sim']
];
var profundidadeMaxima = 3;
function classeMajoritaria(linhas) {
var quantidadeSim = 0;
for (var i = 0; i < linhas.length; i++) {
if (linhas[i][3] === 'Sim') quantidadeSim++;
}
if (quantidadeSim >= linhas.length - quantidadeSim) return 'Sim';
return 'Não';
}
function calcularGini(linhas) {
if (linhas.length === 0) return 0;
var quantidadeSim = 0;
for (var i = 0; i < linhas.length; i++) {
if (linhas[i][3] === 'Sim') quantidadeSim++;
}
var pSim = quantidadeSim / linhas.length;
var pNao = 1 - pSim;
return 1 - pSim * pSim - pNao * pNao;
}
// Candidato = [coluna, tipo, valor].
function criarCandidatos(linhas) {
var candidatos = [];
for (var coluna = 0; coluna < 3; coluna++) {
for (var i = 0; i < linhas.length; i++) {
var repetido = false;
for (var j = 0; j < candidatos.length; j++) {
if (candidatos[j][0] === coluna && candidatos[j][2] === linhas[i][coluna]) repetido = true;
}
if (!repetido) {
var tipo = coluna < 2 ? 'numero' : 'texto';
candidatos.push([coluna, tipo, linhas[i][coluna]]);
}
}
}
return candidatos;
}
function separar(linhas, candidato) {
var esquerda = [];
var direita = [];
for (var i = 0; i < linhas.length; i++) {
var atende;
if (candidato[1] === 'numero') atende = linhas[i][candidato[0]] <= candidato[2];
else atende = linhas[i][candidato[0]] === candidato[2];
if (atende) esquerda.push(linhas[i]);
else direita.push(linhas[i]);
}
return [esquerda, direita];
}
// Melhor divisão = [coluna, tipo, valor, esquerda, direita, ganho].
function melhorDivisao(linhas) {
var candidatos = criarCandidatos(linhas);
var giniPai = calcularGini(linhas);
var melhor = null;
for (var i = 0; i < candidatos.length; i++) {
var grupos = separar(linhas, candidatos[i]);
if (grupos[0].length === 0 || grupos[1].length === 0) continue;
var giniFilhos = (grupos[0].length * calcularGini(grupos[0])
+ grupos[1].length * calcularGini(grupos[1])) / linhas.length;
var ganho = giniPai - giniFilhos;
if (melhor === null || ganho > melhor[5]) {
melhor = [candidatos[i][0], candidatos[i][1], candidatos[i][2],
grupos[0], grupos[1], ganho];
}
}
return melhor;
}
// Folha = ['folha', classe]. Nó = ['no', coluna, tipo, valor, esquerda, direita].
function construirNo(linhas, profundidade) {
if (calcularGini(linhas) === 0 || profundidade === profundidadeMaxima) {
return ['folha', classeMajoritaria(linhas)];
}
var melhor = melhorDivisao(linhas);
if (melhor === null || melhor[5] <= 0) return ['folha', classeMajoritaria(linhas)];
return ['no', melhor[0], melhor[1], melhor[2],
construirNo(melhor[3], profundidade + 1),
construirNo(melhor[4], profundidade + 1)];
}
function classificar(no, entrada) {
if (no[0] === 'folha') return no[1];
var atende;
if (no[2] === 'numero') atende = entrada[no[1]] <= no[3];
else atende = entrada[no[1]] === no[3];
if (atende) return classificar(no[4], entrada);
return classificar(no[5], entrada);
}
function avaliar(arvore, dados) {
var acertos = 0;
for (var i = 0; i < dados.length; i++) {
if (classificar(arvore, dados[i]) === dados[i][3]) acertos++;
}
return acertos / dados.length;
}
// ----------------------- USO DO MODELO -----------------------
var arvore = construirNo(treino, 0);
console.log('Árvore:', JSON.stringify(arvore));
console.log('Acurácia de teste:', avaliar(arvore, teste));
console.log('Novo cliente:', classificar(arvore, [40, 5, 'Premium']));