ensemble / ensemble.js
nanye's picture
support for random forest & extra trees, mlp basis for boosting, multiple class, and improve UI
6ed536f
Raw History Blame Contribute Delete
1.53 kB
/* Display helpers for scikit-learn predictions, including multiclass SAMME. */
(function(root){
function gridValue(model,p,values){
const n=model.size,x=Math.max(0,Math.min(n-1,Math.round(p.x*(n-1)))),y=Math.max(0,Math.min(n-1,Math.round(p.y*(n-1))));
return values[y*n+x];
}
function predict(model,p){return gridValue(model,p,model.grid);}
function weightsFor(points,models){
if(!points.length)return [];
const logs=points.map((p,i)=>models.reduce((s,m)=>s+(p.label!==m.predictions[i]?m.alpha:0),0));
const max=Math.max(...logs),weights=logs.map(v=>Math.exp(v-max)),total=weights.reduce((a,b)=>a+b,0);
return weights.map(w=>w/total);
}
function combine(models,prediction,probabilities){
const classes=models[0]?.classes||[-1,1];
const scores=new Map(classes.map(c=>[c,0]));
for(const m of models){
if(m.forest){
const values=probabilities(m);
m.classes.forEach((c,i)=>scores.set(c,scores.get(c)+values[i]));
}else{
const c=prediction(m);scores.set(c,scores.get(c)+m.alpha);
}
}
return classes.reduce((best,c)=>scores.get(c)>scores.get(best)?c:best,classes[0]);
}
function vote(models,p){return combine(models,m=>predict(m.tree,p),m=>gridValue(m.tree,p,m.tree.probabilities));}
function trainingVote(models,i){return combine(models,m=>m.predictions[i],m=>m.trainingProbabilities[i]);}
const api={predict,weightsFor,vote,trainingVote};
if(typeof module!=='undefined')module.exports=api;else root.Ensemble=api;
})(globalThis);