Skip to content
24intermediate

Model Evaluation Metrics

Metrics for classification, regression and clustering, including the multiclass and probability-based metrics.

What you will learn

  • Use deepbox/ndarray for tensor.
  • Use deepbox/metrics for accuracy, precision, recall, f1Score, jaccardScore, matthewsCorrcoef, confusionMatrix, rocAucScore, logLoss, r2Score, mse, rmse, mae, mape, meanAbsolutePercentageError, silhouetteScore.
  • Metrics for classification, regression and clustering, including the multiclass and probability-based metrics.

Source

index.ts
/** * Example 24: Model Evaluation Metrics * * Metrics for classification, regression and clustering. Every metric * returns a plain number (or an array of numbers when asked for per-class * values), so results can be printed or compared directly. */ import {  // Classification metrics  accuracy,  confusionMatrix,  f1Score,  jaccardScore,  logLoss,  mae,  mape,  matthewsCorrcoef,  meanAbsolutePercentageError,  mse,  precision,  // Regression metrics  r2Score,  recall,  rmse,  rocAucScore,  // Clustering metrics  silhouetteScore,} from "deepbox/metrics";import { tensor } from "deepbox/ndarray"; console.log("=== Model Evaluation Metrics ===\n"); // Binary classification metricsconsole.log("1. Binary Classification Metrics:");console.log("-".repeat(50)); const yTrueClass = tensor([1, 0, 1, 1, 0, 1, 0, 0, 1, 1]);const yPredClass = tensor([1, 0, 1, 0, 0, 1, 0, 1, 1, 1]); console.log("True labels:", yTrueClass.toString());console.log("Predictions:", `${yPredClass.toString()}\n`); const acc = accuracy(yTrueClass, yPredClass);const prec = precision(yTrueClass, yPredClass);const rec = recall(yTrueClass, yPredClass);const f1 = f1Score(yTrueClass, yPredClass); console.log(`Accuracy:  ${(acc * 100).toFixed(2)}%`);console.log(`Precision: ${(prec * 100).toFixed(2)}%`);console.log(`Recall:    ${(rec * 100).toFixed(2)}%`);console.log(`F1-Score:  ${(f1 * 100).toFixed(2)}%`);console.log(`Jaccard:   ${(jaccardScore(yTrueClass, yPredClass) * 100).toFixed(2)}%`);console.log(`Matthews correlation: ${matthewsCorrcoef(yTrueClass, yPredClass).toFixed(4)}\n`); const cm = confusionMatrix(yTrueClass, yPredClass);console.log("Confusion Matrix:");console.log(cm.toString());console.log("Rows are true classes, columns are predicted classes: [[TN, FP], [FN, TP]]\n"); // Probability-based metrics need scores, not labels.console.log("2. Probability-Based Metrics (binary):");console.log("-".repeat(50)); const yProba = tensor([0.9, 0.2, 0.8, 0.4, 0.1, 0.7, 0.3, 0.6, 0.85, 0.95]);console.log(`ROC AUC:  ${rocAucScore(yTrueClass, yProba).toFixed(4)}`);console.log(`Log loss: ${logLoss(yTrueClass, yProba).toFixed(4)}\n`); // Multiclass metrics: choose how per-class scores are combined with `average`.console.log("3. Multiclass Metrics:");console.log("-".repeat(50)); const yTrueMulti = tensor([0, 1, 2, 2, 1, 0, 2, 1, 0, 2]);const yPredMulti = tensor([0, 2, 2, 2, 1, 0, 1, 1, 0, 2]); for (const average of ["macro", "micro", "weighted"] as const) {  const p = precision(yTrueMulti, yPredMulti, { average });  const r = recall(yTrueMulti, yPredMulti, { average });  const f = f1Score(yTrueMulti, yPredMulti, { average });  console.log(    `${average.padEnd(9)} precision=${p.toFixed(4)} recall=${r.toFixed(4)} f1=${f.toFixed(4)}`  );} // average: null returns one value per class, in label order.const perClass = f1Score(yTrueMulti, yPredMulti, { average: null });console.log(`Per-class F1: ${perClass.map((v) => v.toFixed(4)).join(", ")}`); // Multiclass ROC AUC takes an [n, classes] matrix of probabilities that sum to 1 per row.const yProbaMulti = tensor([  [0.8, 0.1, 0.1],  [0.2, 0.3, 0.5],  [0.1, 0.2, 0.7],  [0.1, 0.1, 0.8],  [0.2, 0.6, 0.2],  [0.7, 0.2, 0.1],  [0.1, 0.5, 0.4],  [0.3, 0.5, 0.2],  [0.6, 0.3, 0.1],  [0.2, 0.2, 0.6],]);console.log(`Multiclass ROC AUC (macro): ${rocAucScore(yTrueMulti, yProbaMulti).toFixed(4)}`);console.log(`Multiclass log loss: ${logLoss(yTrueMulti, yProbaMulti).toFixed(4)}\n`); // Regression metricsconsole.log("4. Regression Metrics:");console.log("-".repeat(50)); const yTrueReg = tensor([3.0, 0.5, 2.0, 7.0, 4.2]);const yPredReg = tensor([2.5, 0.6, 2.1, 7.8, 4.0]); console.log("True values:", yTrueReg.toString());console.log("Predictions:", `${yPredReg.toString()}\n`); const r2 = r2Score(yTrueReg, yPredReg);const mseVal = mse(yTrueReg, yPredReg);const rmseVal = rmse(yTrueReg, yPredReg);const maeVal = mae(yTrueReg, yPredReg); console.log(`R² Score: ${r2.toFixed(4)}`);console.log(`MSE:      ${mseVal.toFixed(4)}`);console.log(`RMSE:     ${rmseVal.toFixed(4)}`);console.log(`MAE:      ${maeVal.toFixed(4)}`); // mape already returns a percentage. scikit-learn's version returns a fraction,// which is what meanAbsolutePercentageError returns.console.log(`MAPE:     ${mape(yTrueReg, yPredReg).toFixed(2)}% (mape returns a percentage)`);console.log(  `meanAbsolutePercentageError: ${meanAbsolutePercentageError(yTrueReg, yPredReg).toFixed(4)} (a fraction)\n`); // Clustering metricsconsole.log("5. Clustering Metrics:");console.log("-".repeat(50)); const XCluster = tensor([  [1, 2],  [1.5, 1.8],  [5, 8],  [8, 8],  [1, 0.6],  [9, 11],]);const labels = tensor([0, 0, 1, 1, 0, 1]); const silhouette = silhouetteScore(XCluster, labels);console.log(`Silhouette Score: ${silhouette.toFixed(4)}`);console.log("Range: [-1, 1], higher is better");console.log("Measures how close points are to their own cluster compared with the next one\n"); console.log("Metric selection guide:");console.log(  "  Classification: F1 for imbalanced data, ROC AUC and log loss when you have probabilities");console.log("  Regression: R² for variance explained, MAE for an error in the target's units");console.log("  Clustering: silhouette for cluster separation");

Output

Console output
Console output only.