LABORATÓRIO · LEARNING VECTOR QUANTIZATION
Observe a competição moldar as fronteiras.
Pontos rotulados ensinam quatro protótipos. O vencedor aproxima-se quando acerta e afasta-se quando erra; no LVQ2.1, dois protótipos corrigem juntos uma fronteira.
vencedor correto → atrairvencedor incorreto → repelirjanela LVQ2.1 → ajuste duploFronteiras do LVQ1
As cores de fundo mostram a classe do protótipo mais próximo.
amostras Aamostras Bprotótiposfronteira
Última etapa matemática
Distâncias, decisão, condição da janela e atualização.
Treine uma amostra para visualizar as contas.
Erro × resposta
O erro diminui quando mais amostras recebem a classe correta.
erroacurácia
Protótipos aprendidos
A tabela mostra os poucos vetores usados para classificar todo o plano.
CÓDIGO COMPLETO E EXECUTÁVEL
Treine, avalie e use LVQ1 ou LVQ2.1
Além das regras de movimento, o exemplo agora contém dataset, laço de épocas, redução da taxa, classificação, avaliação e uma chamada final.
iniciar()treinar()classificar()avaliar()
// Um protótipo é [x1, x2, classe].
var treino = [
[-3, 3, 0], [-2, 2, 0], [-3, -2, 0], [-1, -3, 0],
[ 3, 3, 1], [ 2, 1, 1], [ 3, -2, 1], [ 1, -3, 1]
];
var teste = [
[-2.5, 1.5, 0], [-2, -2.5, 0],
[ 2.5, 1.5, 1], [ 2, -2.5, 1]
];
var prototipos = [
[-2, 2, 0],
[-1, -2, 0],
[ 2, 2, 1],
[ 1, -2, 1]
];
// Calcula a distância euclidiana entre dois vetores 2D.
function distancia(x, prototipo) {
var dx1 = x[0] - prototipo[0];
var dx2 = x[1] - prototipo[1];
return Math.sqrt(dx1 * dx1 + dx2 * dx2);
}
// Move um protótipo para perto (+1) ou para longe (-1) da amostra.
function mover(prototipo, x, taxa, direcao) {
prototipo[0] = prototipo[0] + direcao * taxa * (x[0] - prototipo[0]);
prototipo[1] = prototipo[1] + direcao * taxa * (x[1] - prototipo[1]);
}
// Encontra os índices dos dois protótipos mais próximos.
function doisMaisProximos(x) {
var primeiro = -1;
var segundo = -1;
for (var i = 0; i < prototipos.length; i++) {
if (primeiro === -1 || distancia(x, prototipos[i]) < distancia(x, prototipos[primeiro])) {
segundo = primeiro;
primeiro = i;
} else if (segundo === -1 || distancia(x, prototipos[i]) < distancia(x, prototipos[segundo])) {
segundo = i;
}
}
return [primeiro, segundo];
}
// LVQ1 altera somente o protótipo vencedor.
function treinarLVQ1(x, classeCorreta, taxa) {
var proximos = doisMaisProximos(x);
var vencedor = prototipos[proximos[0]];
if (vencedor[2] === classeCorreta) {
mover(vencedor, x, taxa, +1); // atrair
} else {
mover(vencedor, x, taxa, -1); // repelir
}
}
// Testa se as duas distâncias são parecidas o suficiente.
function estaNaJanela(d1, d2, largura) {
var limite = (1 - largura) / (1 + largura);
var razao1 = d1 / d2;
var razao2 = d2 / d1;
return Math.min(razao1, razao2) > limite;
}
// LVQ2.1 ajusta um protótipo correto e um incorreto perto da fronteira.
function treinarLVQ21(x, classeCorreta, taxa, largura) {
var proximos = doisMaisProximos(x);
var p1 = prototipos[proximos[0]];
var p2 = prototipos[proximos[1]];
var classesDiferentes = p1[2] !== p2[2];
var umCorreto = (p1[2] === classeCorreta) !== (p2[2] === classeCorreta);
if (classesDiferentes && umCorreto && estaNaJanela(distancia(x, p1), distancia(x, p2), largura)) {
if (p1[2] === classeCorreta) {
mover(p1, x, taxa, +1);
mover(p2, x, taxa, -1);
} else {
mover(p1, x, taxa, -1);
mover(p2, x, taxa, +1);
}
}
}
// A classe do protótipo mais próximo é a previsão do LVQ.
function classificar(x) {
var proximos = doisMaisProximos(x);
return prototipos[proximos[0]][2];
}
// Apresenta todas as amostras durante várias épocas.
function treinar(dados, algoritmo, epocas, taxaInicial, largura) {
for (var epoca = 0; epoca < epocas; epoca++) {
var taxa = taxaInicial * (1 - epoca / epocas); // diminui gradualmente
for (var i = 0; i < dados.length; i++) {
var x = [dados[i][0], dados[i][1]];
var classe = dados[i][2];
if (algoritmo === 'LVQ2.1') {
// O LVQ1 faz o ajuste geral; o LVQ2.1 refina a fronteira.
treinarLVQ1(x, classe, taxa);
treinarLVQ21(x, classe, taxa, largura);
} else {
treinarLVQ1(x, classe, taxa);
}
}
}
}
function avaliar(dados) {
var acertos = 0;
for (var i = 0; i < dados.length; i++) {
if (classificar(dados[i]) === dados[i][2]) acertos++;
}
return acertos / dados.length;
}
// ----------------------- USO DO MODELO -----------------------
treinar(treino, 'LVQ2.1', 80, 0.15, 0.30);
console.log('Protótipos aprendidos:', prototipos);
console.log('Acurácia de teste:', avaliar(teste));
console.log('Previsão para [2.2, 0.5]:', classificar([2.2, 0.5]));