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/plotWhat 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));211Console Output
$ npx tsx 06-ml-pipeline/index.ts
1 SVG visualization in `output/`:
`predictions-vs-actual.svg` — Scatter plot of predictions vs actual values