Example 06
intermediate
06
Datasets
ML
Metrics
Preprocessing

Complete Machine Learning Pipeline

End-to-end ML pipeline demonstrating classification with the Iris dataset and regression with the Housing-Mini dataset. Includes data preprocessing, model comparison, cross-validation, and visualization. This example uses deepbox/datasets, deepbox/ml, deepbox/metrics, deepbox/preprocess, deepbox/plot and focuses on loadIris, loadHousingMini; LogisticRegression, LinearRegression, Ridge, Lasso; accuracy, precision, recall, f1Score, r2Score, mse; trainTestSplit, StandardScaler, KFold; Figure, scatter, plot.

Deepbox Modules Used

deepbox/datasetsdeepbox/mldeepbox/metricsdeepbox/preprocessdeepbox/plot

What You Will Learn

  • Use deepbox/datasets for loadIris, loadHousingMini.
  • Use deepbox/ml for LogisticRegression, LinearRegression, Ridge, Lasso.
  • Use deepbox/metrics for accuracy, precision, recall, f1Score, r2Score, mse.
  • Use deepbox/preprocess for trainTestSplit, StandardScaler, KFold.
  • End-to-end ML pipeline demonstrating classification with the Iris dataset and regression with the Housing-Mini dataset. Includes data preprocessing, model comparison, cross-validation, and visualization.

Source Files

index.ts
1import { mkdirSync, writeFileSync } from "node:fs";2import { loadHousingMini, loadIris } from "deepbox/datasets";3import {4  accuracy,5  confusionMatrix,6  f1Score,7  mae,8  mse,9  precision,10  r2Score,11  recall,12  rmse,13} from "deepbox/metrics";14import { cross_validate, Lasso, LinearRegression, LogisticRegression, Ridge } from "deepbox/ml";15import { tensor } from "deepbox/ndarray";16import { Figure } from "deepbox/plot";17import { StandardScaler, trainTestSplit } from "deepbox/preprocess";1819console.log("=".repeat(60));20console.log("Example 06: Complete Machine Learning Pipeline");21console.log("=".repeat(60));2223mkdirSync("docs/examples/06-ml-pipeline/output", { recursive: true });2425console.log("\n📦 Part 1: Classification with Iris Dataset");26console.log("-".repeat(60));2728const iris = loadIris();29console.log(`Dataset loaded: ${iris.data.shape[0]} samples, ${iris.data.shape[1]} features`);30console.log(`Classes: ${iris.targetNames?.join(", ") || "N/A"}`);31console.log(`Features: ${iris.featureNames?.join(", ") || "N/A"}`);3233const binaryIrisTarget = [];34for (let i = 0; i < iris.target.size; i++) {35  const val = Number(iris.target.data[iris.target.offset + i]);36  binaryIrisTarget.push(val === 0 ? 0 : 1);37}38const binaryTarget = tensor(binaryIrisTarget);3940console.log("\n🔄 Data Preprocessing");41console.log("-".repeat(60));4243const [XTrainIris, XTestIris, yTrainIris, yTestIris] = trainTestSplit(iris.data, binaryTarget, {44  testSize: 0.3,45  randomState: 42,46});4748console.log(`Training set: ${XTrainIris.shape[0]} samples`);49console.log(`Test set: ${XTestIris.shape[0]} samples`);5051const scalerIris = new StandardScaler();52scalerIris.fit(XTrainIris);53const XTrainScaled = scalerIris.transform(XTrainIris);54const XTestScaled = scalerIris.transform(XTestIris);5556console.log("✓ Features scaled using StandardScaler");5758console.log("\n🤖 Training Logistic Regression");59console.log("-".repeat(60));6061const logReg = new LogisticRegression({ maxIter: 1000, learningRate: 0.1 });62logReg.fit(XTrainScaled, yTrainIris);6364const yPredIris = logReg.predict(XTestScaled);6566console.log("\n📊 Classification Metrics");67console.log("-".repeat(60));68const acc = accuracy(yTestIris, yPredIris);69const prec = precision(yTestIris, yPredIris);70const rec = recall(yTestIris, yPredIris);71const f1 = f1Score(yTestIris, yPredIris);7273console.log(`Accuracy: ${(Number(acc) * 100).toFixed(2)}%`);74console.log(`Precision: ${(Number(prec) * 100).toFixed(2)}%`);75console.log(`Recall: ${(Number(rec) * 100).toFixed(2)}%`);76console.log(`F1-Score: ${(Number(f1) * 100).toFixed(2)}%`);7778const confMatrix = confusionMatrix(yTestIris, yPredIris);79console.log("\nConfusion Matrix:");80console.log(confMatrix.toString());8182console.log("\n📦 Part 2: Regression with Housing-Mini Dataset");83console.log("-".repeat(60));8485const housing = loadHousingMini();86console.log(`Dataset loaded: ${housing.data.shape[0]} samples, ${housing.data.shape[1]} features`);8788const [XTrainHousing, XTestHousing, yTrainHousing, yTestHousing] = trainTestSplit(89  housing.data,90  housing.target,91  {92    testSize: 0.25,93    randomState: 42,94  }95);9697console.log(`Training set: ${XTrainHousing.shape[0]} samples`);98console.log(`Test set: ${XTestHousing.shape[0]} samples`);99100const scalerHousing = new StandardScaler();101scalerHousing.fit(XTrainHousing);102const XTrainHousingScaled = scalerHousing.transform(XTrainHousing);103const XTestHousingScaled = scalerHousing.transform(XTestHousing);104105console.log("\n🔬 Comparing Regression Models");106console.log("-".repeat(60));107108const models = [109  { name: "Linear Regression", model: new LinearRegression() },110  { name: "Ridge Regression (α=1.0)", model: new Ridge({ alpha: 1.0 }) },111  { name: "Ridge Regression (α=10.0)", model: new Ridge({ alpha: 10.0 }) },112  { name: "Lasso Regression (α=0.1)", model: new Lasso({ alpha: 0.1 }) },113];114115const results: Array<{116  name: string;117  r2: number;118  mse: number;119  mae: number;120  rmse: number;121}> = [];122123for (const { name, model } of models) {124  model.fit(XTrainHousingScaled, yTrainHousing);125  const yPred = model.predict(XTestHousingScaled);126127  const r2 = r2Score(yTestHousing, yPred);128  const mseVal = mse(yTestHousing, yPred);129  const maeVal = mae(yTestHousing, yPred);130  const rmseVal = rmse(yTestHousing, yPred);131132  results.push({ name, r2, mse: mseVal, mae: maeVal, rmse: rmseVal });133134  console.log(`\n${name}:`);135  console.log(`  R² Score: ${r2.toFixed(4)}`);136  console.log(`  MSE: ${mseVal.toFixed(4)}`);137  console.log(`  MAE: ${maeVal.toFixed(4)}`);138  console.log(`  RMSE: ${rmseVal.toFixed(4)}`);139}140141console.log("\n🔄 Cross-Validation");142console.log("-".repeat(60));143const cvResult = cross_validate(new Ridge({ alpha: 1.0 }), XTrainHousingScaled, yTrainHousing, {144  cv: 5,145  scoring: {146    r2: (estimator, XFold, yFold) => r2Score(yFold, (estimator as Ridge).predict(XFold)),147    rmse: (estimator, XFold, yFold) => rmse(yFold, (estimator as Ridge).predict(XFold)),148  },149});150151const cvR2Scores = cvResult.testScores.r2 ?? [];152const cvRmseScores = cvResult.testScores.rmse ?? [];153const meanCvR2 =154  cvR2Scores.reduce((total, score) => total + score, 0) / Math.max(cvR2Scores.length, 1);155const meanCvRmse =156  cvRmseScores.reduce((total, score) => total + score, 0) / Math.max(cvRmseScores.length, 1);157158console.log("5-fold cross-validation for Ridge Regression (α=1.0):");159for (let i = 0; i < cvR2Scores.length; i++) {160  const r2 = cvR2Scores[i];161  const rmseScore = cvRmseScores[i];162  console.log(163    `  Fold ${i + 1}: R²=${r2?.toFixed(4) ?? "n/a"}, RMSE=${rmseScore?.toFixed(4) ?? "n/a"}`164  );165}166console.log(`\nMean CV R²: ${meanCvR2.toFixed(4)}`);167console.log(`Mean CV RMSE: ${meanCvRmse.toFixed(4)}`);168169console.log("\n📈 Visualizing Predictions");170console.log("-".repeat(60));171172const bestModel = new Ridge({ alpha: 1.0 });173bestModel.fit(XTrainHousingScaled, yTrainHousing);174const finalPredictions = bestModel.predict(XTestHousingScaled);175176const yTestArray: number[] = [];177const yPredArray: number[] = [];178179for (let i = 0; i < yTestHousing.size; i++) {180  yTestArray.push(Number(yTestHousing.data[yTestHousing.offset + i]));181  yPredArray.push(Number(finalPredictions.data[finalPredictions.offset + i]));182}183184const fig = new Figure();185const ax = fig.addAxes();186ax.scatter(tensor(yTestArray), tensor(yPredArray), {187  color: "#1f77b4",188  size: 6,189});190ax.plot(tensor([0, 1, 2]), tensor([0, 1, 2]), {191  color: "#ff0000",192  linewidth: 2,193});194ax.setTitle("Predictions vs Actual");195ax.setXLabel("Actual Values");196ax.setYLabel("Predicted Values");197const svg = fig.renderSVG();198writeFileSync("docs/examples/06-ml-pipeline/output/predictions-vs-actual.svg", svg.svg);199console.log("✓ Saved: output/predictions-vs-actual.svg");200201console.log("\n💡 Key Takeaways");202console.log("-".repeat(60));203console.log("• Logistic Regression achieved high accuracy on binary classification");204console.log("• Ridge Regression with α=1.0 performed best on housing dataset");205console.log("• Cross-validation now reports real fold-by-fold R² and RMSE scores");206console.log("• Feature scaling is crucial for model performance");207console.log("• Regularization helps prevent overfitting");208209console.log("\n✅ ML Pipeline Complete!");210console.log("=".repeat(60));211

Console Output

$ npx tsx 06-ml-pipeline/index.ts
1 SVG visualization in `output/`:
`predictions-vs-actual.svg` — Scatter plot of predictions vs actual values