AashishAIHub commited on
Commit
5b394bc
Β·
1 Parent(s): 87f43b1

update files

Browse files
ml_complete-all-topics/app.js CHANGED
@@ -1,3 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  // Data
2
  const data = {
3
  linearRegression: [
@@ -134,8 +228,18 @@ function initSections() {
134
  if (section.id === 'hyperparameter-tuning') initHyperparameterTuning();
135
  if (section.id === 'naive-bayes') initNaiveBayes();
136
  if (section.id === 'kmeans') initKMeans();
 
137
  if (section.id === 'decision-trees') initDecisionTrees();
 
 
 
 
 
138
  if (section.id === 'ensemble-methods') initEnsembleMethods();
 
 
 
 
139
  if (section.id === 'rl-intro') { /* No viz for intro */ }
140
  if (section.id === 'q-learning') { /* Add Q-learning viz if needed */ }
141
  if (section.id === 'policy-gradient') { /* Add policy gradient viz if needed */ }
@@ -182,7 +286,7 @@ function initTOCLinks() {
182
  });
183
  ticking = true;
184
  }
185
- });
186
  }
187
 
188
  function updateActiveLink() {
@@ -263,7 +367,12 @@ function drawLinearRegression() {
263
  });
264
  mse /= data.linearRegression.length;
265
 
266
- lrChart = safeCreateChart(ctx, {
 
 
 
 
 
267
  type: 'scatter',
268
  data: {
269
  datasets: [
@@ -313,7 +422,7 @@ function drawLinearRegression() {
313
  }
314
  }
315
  }
316
- }, 'Linear Regression Chart');
317
  }
318
 
319
  // Gradient Descent Visualization
@@ -429,7 +538,12 @@ function drawGradientDescent(currentStep = -1) {
429
  const ctx = canvas.getContext('2d');
430
  const lossData = state.gdIterations.map((iter, i) => ({ x: i + 1, y: iter.loss }));
431
 
432
- gdChart = safeCreateChart(ctx, {
 
 
 
 
 
433
  type: 'line',
434
  data: {
435
  datasets: [{
@@ -481,17 +595,57 @@ function safeCreateChart(ctx, config, chartName) {
481
  console.warn(`Canvas context not found for ${chartName}`);
482
  return null;
483
  }
484
- return new Chart(ctx, config);
 
 
485
  } catch (error) {
486
  console.error(`Chart creation failed for ${chartName}:`, error);
487
- // Show fallback message
488
- if (ctx && ctx.canvas && ctx.canvas.parentElement) {
489
- ctx.canvas.parentElement.innerHTML = `<p style="color: #ff8c6a; text-align: center; padding: 40px;">Visualization temporarily unavailable. Please refresh the page.</p>`;
490
- }
491
  return null;
492
  }
493
  }
494
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
495
  // Initialize everything when DOM is ready
496
  function init() {
497
  initCategories();
@@ -502,6 +656,17 @@ function init() {
502
  setTimeout(() => {
503
  initLinearRegression();
504
  }, 100);
 
 
 
 
 
 
 
 
 
 
 
505
  }
506
 
507
  if (document.readyState === 'loading') {
@@ -557,7 +722,10 @@ function initSVMBasic() {
557
 
558
  function drawSVMBasic() {
559
  const canvas = document.getElementById('svm-basic-canvas');
560
- if (!canvas) return;
 
 
 
561
 
562
  const ctx = canvas.getContext('2d');
563
  if (!ctx) {
@@ -661,6 +829,8 @@ function drawSVMBasic() {
661
  ctx.font = '13px sans-serif';
662
  ctx.textAlign = 'center';
663
  ctx.fillText('X₁', width / 2, height - 20);
 
 
664
  ctx.save();
665
  ctx.translate(20, height / 2);
666
  ctx.rotate(-Math.PI / 2);
@@ -683,7 +853,10 @@ function initSVMMargin() {
683
 
684
  function drawSVMMargin() {
685
  const canvas = document.getElementById('svm-margin-canvas');
686
- if (!canvas) return;
 
 
 
687
 
688
  const ctx = canvas.getContext('2d');
689
  if (!ctx) {
@@ -804,11 +977,9 @@ let svmCChart = null;
804
 
805
  function drawSVMCParameter() {
806
  const canvas = document.getElementById('svm-c-canvas');
807
- if (!canvas) return;
808
-
809
- // Destroy existing chart
810
- if (svmCChart) {
811
- svmCChart.destroy();
812
  }
813
 
814
  const ctx = canvas.getContext('2d');
@@ -902,6 +1073,8 @@ function drawSVMCParameter() {
902
  const violEl = document.getElementById('violations-count');
903
  if (marginEl) marginEl.textContent = marginWidth.toFixed(2);
904
  if (violEl) violEl.textContent = violations;
 
 
905
  }
906
 
907
  function initSVMTraining() {
@@ -992,7 +1165,10 @@ function updateTrainingInfo(point = null, violation = null) {
992
 
993
  function drawSVMTraining() {
994
  const canvas = document.getElementById('svm-train-canvas');
995
- if (!canvas) return;
 
 
 
996
 
997
  const ctx = canvas.getContext('2d');
998
  if (!ctx) {
@@ -1060,6 +1236,8 @@ function drawSVMTraining() {
1060
  ctx.textAlign = 'center';
1061
  ctx.fillText(point.label, x, y - 15);
1062
  });
 
 
1063
  }
1064
 
1065
  let svmKernelChart = null;
@@ -1096,7 +1274,10 @@ function initSVMKernel() {
1096
 
1097
  function drawSVMKernel() {
1098
  const canvas = document.getElementById('svm-kernel-canvas');
1099
- if (!canvas) return;
 
 
 
1100
 
1101
  const ctx = canvas.getContext('2d');
1102
  const width = canvas.width = canvas.offsetWidth;
@@ -1180,6 +1361,8 @@ function drawSVMKernel() {
1180
  ctx.fillStyle = '#7ef0d4';
1181
  ctx.fillText('βœ“ Non-linear kernel successfully separates the data', padding + 10, padding + 50);
1182
  }
 
 
1183
  }
1184
 
1185
  // Logistic Regression Visualizations
@@ -1197,7 +1380,10 @@ function initSigmoid() {
1197
 
1198
  function drawSigmoid() {
1199
  const canvas = document.getElementById('sigmoid-canvas');
1200
- if (!canvas) return;
 
 
 
1201
 
1202
  const ctx = canvas.getContext('2d');
1203
  const width = canvas.width = canvas.offsetWidth;
@@ -1281,6 +1467,8 @@ function drawSigmoid() {
1281
  ctx.fillText('Οƒ(z) = 1/(1+e⁻ᢻ)', padding + 10, padding + 25);
1282
  ctx.fillStyle = '#ff8c6a';
1283
  ctx.fillText('Threshold = 0.5', padding + 10, scaleY(0.5) - 10);
 
 
1284
  }
1285
 
1286
  function initLogisticClassification() {
@@ -1292,7 +1480,10 @@ function initLogisticClassification() {
1292
 
1293
  function drawLogisticClassification() {
1294
  const canvas = document.getElementById('logistic-canvas');
1295
- if (!canvas) return;
 
 
 
1296
 
1297
  const ctx = canvas.getContext('2d');
1298
  const width = canvas.width = canvas.offsetWidth;
@@ -1350,6 +1541,8 @@ function drawLogisticClassification() {
1350
  ctx.fillText(point.height, x, height - padding + 20);
1351
  });
1352
 
 
 
1353
  // Labels
1354
  ctx.fillStyle = '#a9b4c2';
1355
  ctx.font = '12px sans-serif';
@@ -1436,7 +1629,10 @@ function stopDragKNN() {
1436
 
1437
  function drawKNN() {
1438
  const canvas = document.getElementById('knn-canvas');
1439
- if (!canvas) return;
 
 
 
1440
 
1441
  const ctx = canvas.getContext('2d');
1442
  const width = canvas.width = canvas.offsetWidth;
@@ -1524,6 +1720,8 @@ function drawKNN() {
1524
  ctx.textAlign = 'left';
1525
  ctx.fillText(`K=${knnState.k} | Prediction: ${prediction}`, padding + 10, padding + 25);
1526
  ctx.fillText(`Votes: Orange=${votes.orange || 0}, Yellow=${votes.yellow || 0}`, padding + 10, padding + 50);
 
 
1527
  }
1528
 
1529
  // Model Evaluation
@@ -1542,7 +1740,10 @@ function initConfusionMatrix() {
1542
 
1543
  function drawConfusionMatrix() {
1544
  const canvas = document.getElementById('confusion-canvas');
1545
- if (!canvas) return;
 
 
 
1546
 
1547
  const ctx = canvas.getContext('2d');
1548
  const width = canvas.width = canvas.offsetWidth;
@@ -1598,6 +1799,8 @@ function drawConfusionMatrix() {
1598
  ctx.rotate(-Math.PI / 2);
1599
  ctx.fillText('Actual Negative', 0, 0);
1600
  ctx.restore();
 
 
1601
  }
1602
 
1603
  let rocState = { threshold: 0.5 };
@@ -1621,7 +1824,10 @@ function initROC() {
1621
 
1622
  function drawROC() {
1623
  const canvas = document.getElementById('roc-canvas');
1624
- if (!canvas) return;
 
 
 
1625
 
1626
  const ctx = canvas.getContext('2d');
1627
  const width = canvas.width = canvas.offsetWidth;
@@ -1718,6 +1924,8 @@ function drawROC() {
1718
  ctx.textAlign = 'left';
1719
  ctx.fillText(`TPR: ${tpr.toFixed(2)} | FPR: ${fpr.toFixed(2)}`, chartX + 10, chartY + 25);
1720
  ctx.fillText(`TP=${tp} FP=${fp} TN=${tn} FN=${fn}`, chartX + 10, chartY + 50);
 
 
1721
  }
1722
 
1723
  function initR2() {
@@ -1729,7 +1937,10 @@ function initR2() {
1729
 
1730
  function drawR2() {
1731
  const canvas = document.getElementById('r2-canvas');
1732
- if (!canvas) return;
 
 
 
1733
 
1734
  const ctx = canvas.getContext('2d');
1735
  const width = canvas.width = canvas.offsetWidth;
@@ -1808,6 +2019,8 @@ function drawR2() {
1808
  ctx.textAlign = 'left';
1809
  ctx.fillText(`RΒ² = ${r2.toFixed(3)}`, padding + 10, padding + 25);
1810
  ctx.fillText(`Model explains ${(r2 * 100).toFixed(1)}% of variance`, padding + 10, padding + 50);
 
 
1811
  }
1812
 
1813
  // Regularization
@@ -1832,7 +2045,10 @@ function initRegularization() {
1832
 
1833
  function drawRegularization() {
1834
  const canvas = document.getElementById('regularization-canvas');
1835
- if (!canvas) return;
 
 
 
1836
 
1837
  const ctx = canvas.getContext('2d');
1838
  const width = canvas.width = canvas.offsetWidth;
@@ -1899,6 +2115,8 @@ function drawRegularization() {
1899
  ctx.fillRect(padding + 210, legendY, 15, 15);
1900
  ctx.fillStyle = '#e8eef6';
1901
  ctx.fillText('L2 (Ridge)', padding + 230, legendY + 12);
 
 
1902
  }
1903
 
1904
  // Bias-Variance
@@ -1917,7 +2135,10 @@ function initBiasVariance() {
1917
 
1918
  function drawBiasVariance() {
1919
  const canvas = document.getElementById('bias-variance-canvas');
1920
- if (!canvas) return;
 
 
 
1921
 
1922
  const ctx = canvas.getContext('2d');
1923
  const width = canvas.width = canvas.offsetWidth;
@@ -1993,11 +2214,16 @@ function drawBiasVariance() {
1993
  ctx.fillText(line, offsetX + sectionWidth / 2, 20 + i * 18);
1994
  });
1995
  });
 
 
1996
  }
1997
 
1998
  function drawComplexityCurve() {
1999
  const canvas = document.getElementById('complexity-canvas');
2000
- if (!canvas) return;
 
 
 
2001
 
2002
  const ctx = canvas.getContext('2d');
2003
  const width = canvas.width = canvas.offsetWidth;
@@ -2050,6 +2276,8 @@ function drawComplexityCurve() {
2050
  ctx.fillStyle = '#7ef0d4';
2051
  ctx.fillText('● Sweet Spot', padding + 10, padding + 60);
2052
 
 
 
2053
  // Labels
2054
  ctx.fillStyle = '#a9b4c2';
2055
  ctx.textAlign = 'center';
@@ -2071,7 +2299,10 @@ function initCrossValidation() {
2071
 
2072
  function drawCrossValidation() {
2073
  const canvas = document.getElementById('cv-canvas');
2074
- if (!canvas) return;
 
 
 
2075
 
2076
  const ctx = canvas.getContext('2d');
2077
  const width = canvas.width = canvas.offsetWidth;
@@ -2142,6 +2373,8 @@ function drawCrossValidation() {
2142
  ctx.font = 'bold 16px sans-serif';
2143
  ctx.textAlign = 'center';
2144
  ctx.fillText(`Final Score: ${mean.toFixed(2)} Β± ${std.toFixed(3)}`, width / 2, height - 20);
 
 
2145
  }
2146
 
2147
  // Preprocessing
@@ -2161,7 +2394,10 @@ function initPreprocessing() {
2161
 
2162
  function drawScaling() {
2163
  const canvas = document.getElementById('scaling-canvas');
2164
- if (!canvas) return;
 
 
 
2165
 
2166
  const ctx = canvas.getContext('2d');
2167
  const width = canvas.width = canvas.offsetWidth;
@@ -2213,11 +2449,16 @@ function drawScaling() {
2213
  centerX += 35;
2214
  });
2215
  });
 
 
2216
  }
2217
 
2218
  function drawPipeline() {
2219
  const canvas = document.getElementById('pipeline-canvas');
2220
- if (!canvas) return;
 
 
 
2221
 
2222
  const ctx = canvas.getContext('2d');
2223
  const width = canvas.width = canvas.offsetWidth;
@@ -2268,6 +2509,8 @@ function drawPipeline() {
2268
  ctx.fill();
2269
  }
2270
  });
 
 
2271
  }
2272
 
2273
  // Loss Functions
@@ -2287,7 +2530,10 @@ function initLossFunctions() {
2287
 
2288
  function drawLossComparison() {
2289
  const canvas = document.getElementById('loss-comparison-canvas');
2290
- if (!canvas) return;
 
 
 
2291
 
2292
  const ctx = canvas.getContext('2d');
2293
  const width = canvas.width = canvas.offsetWidth;
@@ -2350,11 +2596,16 @@ function drawLossComparison() {
2350
  ctx.font = 'bold 16px sans-serif';
2351
  ctx.textAlign = 'center';
2352
  ctx.fillText('Regression Loss Comparison', width / 2, 50);
 
 
2353
  }
2354
 
2355
  function drawLossCurves() {
2356
  const canvas = document.getElementById('loss-curves-canvas');
2357
- if (!canvas) return;
 
 
 
2358
 
2359
  const ctx = canvas.getContext('2d');
2360
  const width = canvas.width = canvas.offsetWidth;
@@ -2410,6 +2661,8 @@ function drawLossCurves() {
2410
  ctx.rotate(-Math.PI / 2);
2411
  ctx.fillText('Loss', 0, 0);
2412
  ctx.restore();
 
 
2413
  }
2414
 
2415
  // Topic 13: Finding Optimal K in KNN
@@ -2469,7 +2722,12 @@ function drawElbowCurve() {
2469
  }
2470
 
2471
  // Use Chart.js
2472
- elbowChart = new Chart(ctx, {
 
 
 
 
 
2473
  type: 'line',
2474
  data: {
2475
  labels: kValues,
@@ -2528,12 +2786,15 @@ function drawElbowCurve() {
2528
  }
2529
  }
2530
  }
2531
- }, 'Elbow Chart');
2532
  }
2533
 
2534
  function drawCVKHeatmap() {
2535
  const canvas = document.getElementById('cv-k-canvas');
2536
- if (!canvas) return;
 
 
 
2537
 
2538
  const ctx = canvas.getContext('2d');
2539
  const width = canvas.width = canvas.offsetWidth;
@@ -2612,6 +2873,8 @@ function drawCVKHeatmap() {
2612
  const maxMean = Math.max(...meanAccs);
2613
  const optIdx = meanAccs.indexOf(maxMean);
2614
  ctx.fillText(`Best K = ${kValues[optIdx]} (Mean Acc: ${maxMean.toFixed(3)})`, padding, height - 20);
 
 
2615
  }
2616
 
2617
  // Topic 14: Hyperparameter Tuning
@@ -2640,11 +2903,9 @@ function initHyperparameterTuning() {
2640
 
2641
  function drawGridSearchHeatmap() {
2642
  const canvas = document.getElementById('gridsearch-heatmap');
2643
- if (!canvas) return;
2644
-
2645
- // Destroy existing chart
2646
- if (gridSearchChart) {
2647
- gridSearchChart.destroy();
2648
  }
2649
 
2650
  const ctx = canvas.getContext('2d');
@@ -2763,11 +3024,16 @@ function drawGridSearchHeatmap() {
2763
  ctx.font = 'bold 14px sans-serif';
2764
  ctx.textAlign = 'left';
2765
  ctx.fillText(`Best: C=${cValues[bestJ]}, Ξ³=${gammaValues[bestI]} β†’ Acc=${bestAcc.toFixed(2)}`, padding, height - 30);
 
 
2766
  }
2767
 
2768
  function drawParamSurface() {
2769
  const canvas = document.getElementById('param-surface');
2770
- if (!canvas) return;
 
 
 
2771
 
2772
  const ctx = canvas.getContext('2d');
2773
  const width = canvas.width = canvas.offsetWidth;
@@ -2826,6 +3092,8 @@ function drawParamSurface() {
2826
  ctx.font = 'bold 16px sans-serif';
2827
  ctx.textAlign = 'center';
2828
  ctx.fillText('Performance Surface (3D Contour View)', width / 2, 30);
 
 
2829
  }
2830
 
2831
  // Topic 15: Naive Bayes
@@ -2861,7 +3129,10 @@ function initNaiveBayes() {
2861
 
2862
  function drawBayesTheorem() {
2863
  const canvas = document.getElementById('bayes-theorem-viz');
2864
- if (!canvas) return;
 
 
 
2865
 
2866
  const ctx = canvas.getContext('2d');
2867
  const width = canvas.width = canvas.offsetWidth;
@@ -2923,7 +3194,11 @@ function drawCategoricalNB() {
2923
 
2924
  const ctx = canvas.getContext('2d');
2925
 
2926
- categoricalNBChart = safeCreateChart(ctx, {
 
 
 
 
2927
  type: 'bar',
2928
  data: {
2929
  labels: ['P(Yes|Rainy,Hot)', 'P(No|Rainy,Hot)'],
@@ -2975,12 +3250,15 @@ function drawCategoricalNB() {
2975
  }
2976
  }
2977
  }
2978
- }, 'Categorical Naive Bayes Chart');
2979
  }
2980
 
2981
  function drawGaussianNB() {
2982
  const canvas = document.getElementById('gaussian-nb-canvas');
2983
- if (!canvas) return;
 
 
 
2984
 
2985
  const ctx = canvas.getContext('2d');
2986
  const width = canvas.width = canvas.offsetWidth;
@@ -3088,6 +3366,8 @@ function drawGaussianNB() {
3088
 
3089
  ctx.fillStyle = '#6aa9ff';
3090
  ctx.fillText('| Decision Boundary', padding + 210, 35);
 
 
3091
  }
3092
 
3093
  function drawSpamClassification() {
@@ -3157,7 +3437,11 @@ function drawSpamClassification() {
3157
  compCanvas.style.marginTop = '20px';
3158
  canvas.parentElement.appendChild(compCanvas);
3159
 
3160
- bayesComparisonChart = safeCreateChart(compCanvas.getContext('2d'), {
 
 
 
 
3161
  type: 'bar',
3162
  data: {
3163
  labels: ['Spam Probability', 'Not-Spam Probability'],
@@ -3193,9 +3477,11 @@ function drawSpamClassification() {
3193
  }
3194
  }
3195
  }
3196
- }, 'Bayes Comparison Chart');
3197
  if (bayesComparisonChart) compCanvas.style.height = '150px';
3198
  }
 
 
3199
  }
3200
 
3201
  // Topic 16: Decision Trees
@@ -3227,7 +3513,10 @@ function initDecisionTrees() {
3227
 
3228
  function drawDecisionTree() {
3229
  const canvas = document.getElementById('decision-tree-viz');
3230
- if (!canvas) return;
 
 
 
3231
 
3232
  const ctx = canvas.getContext('2d');
3233
  const width = canvas.width = canvas.offsetWidth;
@@ -3311,6 +3600,8 @@ function drawDecisionTree() {
3311
  ctx.font = '12px sans-serif';
3312
  ctx.textAlign = 'left';
3313
  ctx.fillText('Example: Email with "free" + link β†’ SPAM', 40, height - 20);
 
 
3314
  }
3315
 
3316
  function drawSplitComparison() {
@@ -3368,6 +3659,8 @@ function drawSplitComparison() {
3368
  ctx.textAlign = 'center';
3369
  ctx.fillText('βœ“ Best split: Highest Information Gain!', width / 2, height - 30);
3370
 
 
 
3371
  // Title
3372
  ctx.fillStyle = '#7ef0d4';
3373
  ctx.font = 'bold 16px sans-serif';
@@ -3376,7 +3669,10 @@ function drawSplitComparison() {
3376
 
3377
  function drawEntropyViz() {
3378
  const canvas = document.getElementById('entropy-viz');
3379
- if (!canvas) return;
 
 
 
3380
 
3381
  const ctx = canvas.getContext('2d');
3382
  const width = canvas.width = canvas.offsetWidth;
@@ -3454,6 +3750,8 @@ function drawEntropyViz() {
3454
  ctx.font = 'bold 16px sans-serif';
3455
  ctx.textAlign = 'center';
3456
  ctx.fillText('Entropy: Measuring Disorder', width / 2, 30);
 
 
3457
  }
3458
 
3459
  function drawSplitComparison() {
@@ -3601,7 +3899,10 @@ function drawEntropyViz() {
3601
 
3602
  function drawTreeBoundary() {
3603
  const canvas = document.getElementById('tree-boundary');
3604
- if (!canvas) return;
 
 
 
3605
 
3606
  const ctx = canvas.getContext('2d');
3607
  const width = canvas.width = canvas.offsetWidth;
@@ -3686,80 +3987,1255 @@ function drawTreeBoundary() {
3686
  ctx.font = 'bold 16px sans-serif';
3687
  ctx.textAlign = 'center';
3688
  ctx.fillText('Decision Tree Creates Rectangular Regions', width / 2, 30);
 
 
3689
  }
3690
 
3691
- // Topic 17: Ensemble Methods
3692
- function initEnsembleMethods() {
3693
- const canvas1 = document.getElementById('bagging-viz');
3694
  if (canvas1 && !canvas1.dataset.initialized) {
3695
  canvas1.dataset.initialized = 'true';
3696
- drawBaggingViz();
3697
  }
3698
 
3699
- const canvas2 = document.getElementById('boosting-viz');
3700
  if (canvas2 && !canvas2.dataset.initialized) {
3701
  canvas2.dataset.initialized = 'true';
3702
- drawBoostingViz();
3703
- }
3704
-
3705
- const canvas3 = document.getElementById('random-forest-viz');
3706
- if (canvas3 && !canvas3.dataset.initialized) {
3707
- canvas3.dataset.initialized = 'true';
3708
- drawRandomForestViz();
3709
  }
3710
  }
3711
 
3712
- function drawBaggingViz() {
3713
- const canvas = document.getElementById('bagging-viz');
3714
- if (!canvas) return;
 
 
 
3715
 
3716
  const ctx = canvas.getContext('2d');
3717
  const width = canvas.width = canvas.offsetWidth;
3718
- const height = canvas.height = 400;
3719
 
3720
  ctx.clearRect(0, 0, width, height);
3721
  ctx.fillStyle = '#1a2332';
3722
  ctx.fillRect(0, 0, width, height);
3723
 
3724
- const boxWidth = 150;
3725
- const boxHeight = 60;
3726
- const startY = 60;
3727
- const spacing = (width - 3 * boxWidth) / 4;
3728
 
3729
- // Original data
3730
- ctx.fillStyle = '#6aa9ff33';
3731
- ctx.fillRect(width / 2 - 100, startY, 200, boxHeight);
 
 
 
 
 
 
 
 
 
3732
  ctx.strokeStyle = '#6aa9ff';
3733
- ctx.lineWidth = 2;
3734
- ctx.strokeRect(width / 2 - 100, startY, 200, boxHeight);
3735
- ctx.fillStyle = '#e8eef6';
3736
- ctx.font = 'bold 14px sans-serif';
3737
- ctx.textAlign = 'center';
3738
- ctx.fillText('Original Dataset', width / 2, startY + boxHeight / 2 + 5);
3739
 
3740
- // Bootstrap samples
3741
- const sampleY = startY + boxHeight + 60;
3742
- for (let i = 0; i < 3; i++) {
3743
- const x = spacing + i * (boxWidth + spacing);
3744
-
3745
- // Arrow
3746
- ctx.strokeStyle = '#7ef0d4';
3747
- ctx.lineWidth = 2;
3748
- ctx.beginPath();
3749
- ctx.moveTo(width / 2, startY + boxHeight);
3750
- ctx.lineTo(x + boxWidth / 2, sampleY);
3751
- ctx.stroke();
3752
-
3753
- // Sample box
3754
- ctx.fillStyle = '#7ef0d433';
3755
- ctx.fillRect(x, sampleY, boxWidth, boxHeight);
3756
- ctx.strokeStyle = '#7ef0d4';
3757
- ctx.strokeRect(x, sampleY, boxWidth, boxHeight);
3758
-
3759
- ctx.fillStyle = '#e8eef6';
3760
- ctx.font = 'bold 12px sans-serif';
3761
- ctx.fillText(`Bootstrap ${i + 1}`, x + boxWidth / 2, sampleY + boxHeight / 2 - 5);
3762
- ctx.font = '10px sans-serif';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3763
  ctx.fillStyle = '#a9b4c2';
3764
  ctx.fillText('(random sample)', x + boxWidth / 2, sampleY + boxHeight / 2 + 10);
3765
 
@@ -3910,6 +5386,40 @@ function drawBoostingViz() {
3910
  ctx.fillStyle = '#ff8c6a';
3911
  ctx.font = 'bold 14px sans-serif';
3912
  ctx.fillText('Final Prediction = Weighted Combination of All Models', width / 2, height - 20);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3913
  }
3914
 
3915
  function drawRandomForestViz() {
@@ -4018,6 +5528,8 @@ function drawRandomForestViz() {
4018
  ctx.fillStyle = '#7ef0d4';
4019
  ctx.font = 'bold 16px sans-serif';
4020
  ctx.fillText('Random Forest: Ensemble of Decision Trees', width / 2, 25);
 
 
4021
  }
4022
 
4023
  // Topic 16: K-means Clustering
@@ -4040,7 +5552,10 @@ function initKMeans() {
4040
 
4041
  function drawKMeansVisualization() {
4042
  const canvas = document.getElementById('kmeans-viz-canvas');
4043
- if (!canvas) return;
 
 
 
4044
 
4045
  const ctx = canvas.getContext('2d');
4046
  const width = canvas.width = canvas.offsetWidth;
@@ -4160,6 +5675,8 @@ function drawKMeansVisualization() {
4160
  ctx.font = '14px sans-serif';
4161
  ctx.textAlign = 'left';
4162
  ctx.fillText('WCSS = 15.984', padding, height - padding + 30);
 
 
4163
  }
4164
 
4165
  function drawKMeansElbow() {
@@ -4175,7 +5692,7 @@ function drawKMeansElbow() {
4175
  const kValues = [1, 2, 3, 4, 5];
4176
  const wcssValues = [50, 18, 10, 8, 7];
4177
 
4178
- kmeansElbowChart = safeCreateChart(ctx, {
4179
  type: 'line',
4180
  data: {
4181
  labels: kValues,
@@ -4238,7 +5755,7 @@ function drawKMeansElbow() {
4238
  }
4239
  }
4240
  }
4241
- }, 'K-means Elbow Chart');
4242
  }
4243
 
4244
  // Topic 18: Algorithm Comparison
@@ -4474,6 +5991,8 @@ function renderComparisonTable() {
4474
 
4475
  html += '</tbody>';
4476
  table.innerHTML = html;
 
 
4477
  }
4478
 
4479
  let radarComparisonChart = null;
@@ -4505,7 +6024,12 @@ function renderRadarChart() {
4505
  };
4506
  });
4507
 
4508
- radarComparisonChart = safeCreateChart(ctx, {
 
 
 
 
 
4509
  type: 'radar',
4510
  data: {
4511
  labels: ['Speed', 'Accuracy', 'Data Efficiency', 'Interpretability', 'Scalability'],
@@ -4530,7 +6054,7 @@ function renderRadarChart() {
4530
  }
4531
  }
4532
  }
4533
- }, 'Radar Comparison Chart');
4534
  }
4535
 
4536
  function renderHeatmap() {
@@ -4586,6 +6110,8 @@ function renderHeatmap() {
4586
  html += '</table>';
4587
  html += '</div>';
4588
 
 
 
4589
  // Legend
4590
  html += '<div style="text-align: center; margin-top: 24px; padding: 16px; background: var(--color-bg-2); border-radius: 8px;">';
4591
  html += '<strong style="color: #e8eef6;">Legend:</strong> ';
@@ -4634,6 +6160,8 @@ function renderUseCaseMatrix() {
4634
 
4635
  html += '</tbody>';
4636
  table.innerHTML = html;
 
 
4637
  }
4638
 
4639
  function renderDetailedCards() {
@@ -4673,6 +6201,8 @@ function renderDetailedCards() {
4673
 
4674
  html += '</div>';
4675
  container.innerHTML = html;
 
 
4676
  }
4677
 
4678
  function initQuiz() {
@@ -4836,6 +6366,75 @@ function drawDecisionFlowchart() {
4836
  ctx.fillText('Algorithm Selection Flowchart', width/2, 25);
4837
  }
4838
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4839
  // Handle window resize
4840
  let resizeTimer;
4841
  window.addEventListener('resize', () => {
@@ -4883,3 +6482,6 @@ window.addEventListener('resize', () => {
4883
  if (document.getElementById('decision-flowchart')) drawDecisionFlowchart();
4884
  }, 250);
4885
  });
 
 
 
 
1
+ // ========== VISUALIZATION VERIFICATION SYSTEM ==========
2
+ const vizLog = {
3
+ success: [],
4
+ failed: [],
5
+ warnings: []
6
+ };
7
+
8
+ function logViz(module, name, status, error = null) {
9
+ const log = {
10
+ module: module,
11
+ name: name,
12
+ status: status,
13
+ timestamp: new Date().toLocaleTimeString(),
14
+ error: error
15
+ };
16
+
17
+ if (status === 'success') {
18
+ vizLog.success.push(log);
19
+ console.log(`βœ“ ${module} - ${name}`);
20
+ } else if (status === 'failed') {
21
+ vizLog.failed.push(log);
22
+ console.error(`βœ— ${module} - ${name}: ${error}`);
23
+ } else {
24
+ vizLog.warnings.push(log);
25
+ console.warn(`⚠ ${module} - ${name}: ${error}`);
26
+ }
27
+ }
28
+
29
+ function createVerifiedVisualization(canvasId, chartConfig, moduleName, vizName) {
30
+ try {
31
+ const canvas = document.getElementById(canvasId);
32
+ if (!canvas) {
33
+ logViz(moduleName, vizName, 'failed', 'Canvas not found');
34
+ showFallback(canvasId, 'error');
35
+ return null;
36
+ }
37
+
38
+ const ctx = canvas.getContext('2d');
39
+ if (!ctx) {
40
+ logViz(moduleName, vizName, 'failed', 'Cannot get context');
41
+ showFallback(canvasId, 'error');
42
+ return null;
43
+ }
44
+
45
+ if (typeof Chart === 'undefined') {
46
+ logViz(moduleName, vizName, 'failed', 'Chart.js not loaded');
47
+ showFallback(canvasId, 'error');
48
+ return null;
49
+ }
50
+
51
+ const chart = new Chart(ctx, chartConfig);
52
+ logViz(moduleName, vizName, 'success');
53
+ return chart;
54
+
55
+ } catch (error) {
56
+ logViz(moduleName, vizName, 'failed', error.message);
57
+ showFallback(canvasId, 'error');
58
+ return null;
59
+ }
60
+ }
61
+
62
+ function showFallback(elementId, type) {
63
+ const element = document.getElementById(elementId);
64
+ if (!element) return;
65
+
66
+ const container = element.parentElement;
67
+ if (!container) return;
68
+
69
+ if (type === 'error') {
70
+ container.innerHTML = '<div style="padding: 40px; text-align: center; color: #ff8c6a; background: rgba(255, 140, 106, 0.1); border-radius: 8px; border: 2px solid #ff8c6a;">⚠️ Visualization temporarily unavailable<br><small style="color: #a9b4c2; margin-top: 8px; display: block;">Data is still accessible via diagnostic tools</small></div>';
71
+ }
72
+ }
73
+
74
+ // Show report on load
75
+ window.addEventListener('load', () => {
76
+ setTimeout(() => {
77
+ console.log('\n=== VISUALIZATION VERIFICATION REPORT ===');
78
+ console.log(`βœ“ Success: ${vizLog.success.length}`);
79
+ console.log(`βœ— Failed: ${vizLog.failed.length}`);
80
+ console.log(`⚠ Warnings: ${vizLog.warnings.length}`);
81
+
82
+ if (vizLog.failed.length > 0) {
83
+ console.error('Failed visualizations:', vizLog.failed);
84
+ }
85
+
86
+ if (vizLog.success.length > 0) {
87
+ console.log('\nSuccessful visualizations:');
88
+ vizLog.success.forEach(v => console.log(` βœ“ ${v.module} - ${v.name}`));
89
+ }
90
+
91
+ console.log('\n=========================================');
92
+ }, 2000);
93
+ });
94
+
95
  // Data
96
  const data = {
97
  linearRegression: [
 
228
  if (section.id === 'hyperparameter-tuning') initHyperparameterTuning();
229
  if (section.id === 'naive-bayes') initNaiveBayes();
230
  if (section.id === 'kmeans') initKMeans();
231
+ if (section.id === 'decision-tree-regression') initDecisionTreeRegression();
232
  if (section.id === 'decision-trees') initDecisionTrees();
233
+ if (section.id === 'gradient-boosting') initGradientBoosting();
234
+ if (section.id === 'xgboost') initXGBoost();
235
+ if (section.id === 'bagging') initBagging();
236
+ if (section.id === 'boosting-adaboost') initBoostingAdaBoost();
237
+ if (section.id === 'random-forest') initRandomForest();
238
  if (section.id === 'ensemble-methods') initEnsembleMethods();
239
+ if (section.id === 'diagnostics') {
240
+ // Wait for all visualizations to initialize
241
+ setTimeout(showDiagnostics, 500);
242
+ }
243
  if (section.id === 'rl-intro') { /* No viz for intro */ }
244
  if (section.id === 'q-learning') { /* Add Q-learning viz if needed */ }
245
  if (section.id === 'policy-gradient') { /* Add policy gradient viz if needed */ }
 
286
  });
287
  ticking = true;
288
  }
289
+ }, 'Gradient Descent', 'Loss Curve');
290
  }
291
 
292
  function updateActiveLink() {
 
367
  });
368
  mse /= data.linearRegression.length;
369
 
370
+ // Destroy existing chart
371
+ if (lrChart) {
372
+ lrChart.destroy();
373
+ }
374
+
375
+ lrChart = createVerifiedVisualization('lr-canvas', {
376
  type: 'scatter',
377
  data: {
378
  datasets: [
 
422
  }
423
  }
424
  }
425
+ }, 'Linear Regression', 'Scatter + Line');
426
  }
427
 
428
  // Gradient Descent Visualization
 
538
  const ctx = canvas.getContext('2d');
539
  const lossData = state.gdIterations.map((iter, i) => ({ x: i + 1, y: iter.loss }));
540
 
541
+ // Destroy existing chart
542
+ if (gdChart) {
543
+ gdChart.destroy();
544
+ }
545
+
546
+ gdChart = createVerifiedVisualization('gd-canvas', {
547
  type: 'line',
548
  data: {
549
  datasets: [{
 
595
  console.warn(`Canvas context not found for ${chartName}`);
596
  return null;
597
  }
598
+ const chart = new Chart(ctx, config);
599
+ console.log(`βœ“ Chart created: ${chartName}`);
600
+ return chart;
601
  } catch (error) {
602
  console.error(`Chart creation failed for ${chartName}:`, error);
 
 
 
 
603
  return null;
604
  }
605
  }
606
 
607
+ // Link Verification System
608
+ function verifyAllLinks() {
609
+ const links = document.querySelectorAll('a[href^="#"]');
610
+ const broken = [];
611
+ let working = 0;
612
+
613
+ links.forEach(link => {
614
+ const targetId = link.getAttribute('href').substring(1);
615
+ const target = document.getElementById(targetId);
616
+
617
+ if (!target) {
618
+ broken.push({
619
+ text: link.textContent,
620
+ href: link.getAttribute('href')
621
+ });
622
+ link.style.color = 'red';
623
+ link.title = 'Broken link';
624
+ } else {
625
+ working++;
626
+ link.addEventListener('click', (e) => {
627
+ e.preventDefault();
628
+ target.scrollIntoView({ behavior: 'smooth' });
629
+
630
+ // Highlight section
631
+ const originalBg = target.style.backgroundColor;
632
+ target.style.backgroundColor = 'rgba(106, 169, 255, 0.2)';
633
+ setTimeout(() => {
634
+ target.style.backgroundColor = originalBg;
635
+ }, 1000);
636
+ });
637
+ }
638
+ });
639
+
640
+ console.log(`\n=== LINK VERIFICATION ===`);
641
+ console.log(`βœ“ Working: ${working}/${links.length}`);
642
+ console.log(`βœ— Broken: ${broken.length}`);
643
+ if (broken.length > 0) {
644
+ console.error('Broken links:', broken);
645
+ }
646
+ console.log('==========================\n');
647
+ }
648
+
649
  // Initialize everything when DOM is ready
650
  function init() {
651
  initCategories();
 
656
  setTimeout(() => {
657
  initLinearRegression();
658
  }, 100);
659
+
660
+ // Verify all links on load
661
+ setTimeout(verifyAllLinks, 1000);
662
+
663
+ // Initialize diagnostics refresh
664
+ setInterval(() => {
665
+ const diagSection = document.getElementById('diagnostics');
666
+ if (diagSection && diagSection.querySelector('.section-body').classList.contains('expanded')) {
667
+ showDiagnostics();
668
+ }
669
+ }, 3000);
670
  }
671
 
672
  if (document.readyState === 'loading') {
 
722
 
723
  function drawSVMBasic() {
724
  const canvas = document.getElementById('svm-basic-canvas');
725
+ if (!canvas) {
726
+ logViz('SVM', 'Basic Decision Boundary', 'failed', 'Canvas not found');
727
+ return;
728
+ }
729
 
730
  const ctx = canvas.getContext('2d');
731
  if (!ctx) {
 
829
  ctx.font = '13px sans-serif';
830
  ctx.textAlign = 'center';
831
  ctx.fillText('X₁', width / 2, height - 20);
832
+
833
+ logViz('SVM', 'Basic Decision Boundary', 'success');
834
  ctx.save();
835
  ctx.translate(20, height / 2);
836
  ctx.rotate(-Math.PI / 2);
 
853
 
854
  function drawSVMMargin() {
855
  const canvas = document.getElementById('svm-margin-canvas');
856
+ if (!canvas) {
857
+ logViz('SVM', 'Margin Visualization', 'failed', 'Canvas not found');
858
+ return;
859
+ }
860
 
861
  const ctx = canvas.getContext('2d');
862
  if (!ctx) {
 
977
 
978
  function drawSVMCParameter() {
979
  const canvas = document.getElementById('svm-c-canvas');
980
+ if (!canvas) {
981
+ logViz('SVM', 'C Parameter Effect', 'failed', 'Canvas not found');
982
+ return;
 
 
983
  }
984
 
985
  const ctx = canvas.getContext('2d');
 
1073
  const violEl = document.getElementById('violations-count');
1074
  if (marginEl) marginEl.textContent = marginWidth.toFixed(2);
1075
  if (violEl) violEl.textContent = violations;
1076
+
1077
+ logViz('SVM', 'Margin Visualization', 'success');
1078
  }
1079
 
1080
  function initSVMTraining() {
 
1165
 
1166
  function drawSVMTraining() {
1167
  const canvas = document.getElementById('svm-train-canvas');
1168
+ if (!canvas) {
1169
+ logViz('SVM', 'Training Animation', 'failed', 'Canvas not found');
1170
+ return;
1171
+ }
1172
 
1173
  const ctx = canvas.getContext('2d');
1174
  if (!ctx) {
 
1236
  ctx.textAlign = 'center';
1237
  ctx.fillText(point.label, x, y - 15);
1238
  });
1239
+
1240
+ logViz('SVM', 'Training Animation', 'success');
1241
  }
1242
 
1243
  let svmKernelChart = null;
 
1274
 
1275
  function drawSVMKernel() {
1276
  const canvas = document.getElementById('svm-kernel-canvas');
1277
+ if (!canvas) {
1278
+ logViz('SVM', 'Kernel Comparison', 'failed', 'Canvas not found');
1279
+ return;
1280
+ }
1281
 
1282
  const ctx = canvas.getContext('2d');
1283
  const width = canvas.width = canvas.offsetWidth;
 
1361
  ctx.fillStyle = '#7ef0d4';
1362
  ctx.fillText('βœ“ Non-linear kernel successfully separates the data', padding + 10, padding + 50);
1363
  }
1364
+
1365
+ logViz('SVM', 'Kernel Comparison', 'success');
1366
  }
1367
 
1368
  // Logistic Regression Visualizations
 
1380
 
1381
  function drawSigmoid() {
1382
  const canvas = document.getElementById('sigmoid-canvas');
1383
+ if (!canvas) {
1384
+ logViz('Logistic Regression', 'Sigmoid Curve', 'failed', 'Canvas not found');
1385
+ return;
1386
+ }
1387
 
1388
  const ctx = canvas.getContext('2d');
1389
  const width = canvas.width = canvas.offsetWidth;
 
1467
  ctx.fillText('Οƒ(z) = 1/(1+e⁻ᢻ)', padding + 10, padding + 25);
1468
  ctx.fillStyle = '#ff8c6a';
1469
  ctx.fillText('Threshold = 0.5', padding + 10, scaleY(0.5) - 10);
1470
+
1471
+ logViz('Logistic Regression', 'Sigmoid Curve', 'success');
1472
  }
1473
 
1474
  function initLogisticClassification() {
 
1480
 
1481
  function drawLogisticClassification() {
1482
  const canvas = document.getElementById('logistic-canvas');
1483
+ if (!canvas) {
1484
+ logViz('Logistic Regression', 'Classification Boundary', 'failed', 'Canvas not found');
1485
+ return;
1486
+ }
1487
 
1488
  const ctx = canvas.getContext('2d');
1489
  const width = canvas.width = canvas.offsetWidth;
 
1541
  ctx.fillText(point.height, x, height - padding + 20);
1542
  });
1543
 
1544
+ logViz('Logistic Regression', 'Classification Boundary', 'success');
1545
+
1546
  // Labels
1547
  ctx.fillStyle = '#a9b4c2';
1548
  ctx.font = '12px sans-serif';
 
1629
 
1630
  function drawKNN() {
1631
  const canvas = document.getElementById('knn-canvas');
1632
+ if (!canvas) {
1633
+ logViz('KNN', 'Draggable Point', 'failed', 'Canvas not found');
1634
+ return;
1635
+ }
1636
 
1637
  const ctx = canvas.getContext('2d');
1638
  const width = canvas.width = canvas.offsetWidth;
 
1720
  ctx.textAlign = 'left';
1721
  ctx.fillText(`K=${knnState.k} | Prediction: ${prediction}`, padding + 10, padding + 25);
1722
  ctx.fillText(`Votes: Orange=${votes.orange || 0}, Yellow=${votes.yellow || 0}`, padding + 10, padding + 50);
1723
+
1724
+ logViz('KNN', 'Draggable Point', 'success');
1725
  }
1726
 
1727
  // Model Evaluation
 
1740
 
1741
  function drawConfusionMatrix() {
1742
  const canvas = document.getElementById('confusion-canvas');
1743
+ if (!canvas) {
1744
+ logViz('Model Evaluation', 'Confusion Matrix', 'failed', 'Canvas not found');
1745
+ return;
1746
+ }
1747
 
1748
  const ctx = canvas.getContext('2d');
1749
  const width = canvas.width = canvas.offsetWidth;
 
1799
  ctx.rotate(-Math.PI / 2);
1800
  ctx.fillText('Actual Negative', 0, 0);
1801
  ctx.restore();
1802
+
1803
+ logViz('Model Evaluation', 'Confusion Matrix', 'success');
1804
  }
1805
 
1806
  let rocState = { threshold: 0.5 };
 
1824
 
1825
  function drawROC() {
1826
  const canvas = document.getElementById('roc-canvas');
1827
+ if (!canvas) {
1828
+ logViz('Model Evaluation', 'ROC Curve', 'failed', 'Canvas not found');
1829
+ return;
1830
+ }
1831
 
1832
  const ctx = canvas.getContext('2d');
1833
  const width = canvas.width = canvas.offsetWidth;
 
1924
  ctx.textAlign = 'left';
1925
  ctx.fillText(`TPR: ${tpr.toFixed(2)} | FPR: ${fpr.toFixed(2)}`, chartX + 10, chartY + 25);
1926
  ctx.fillText(`TP=${tp} FP=${fp} TN=${tn} FN=${fn}`, chartX + 10, chartY + 50);
1927
+
1928
+ logViz('Model Evaluation', 'ROC Curve', 'success');
1929
  }
1930
 
1931
  function initR2() {
 
1937
 
1938
  function drawR2() {
1939
  const canvas = document.getElementById('r2-canvas');
1940
+ if (!canvas) {
1941
+ logViz('Model Evaluation', 'RΒ² Score', 'failed', 'Canvas not found');
1942
+ return;
1943
+ }
1944
 
1945
  const ctx = canvas.getContext('2d');
1946
  const width = canvas.width = canvas.offsetWidth;
 
2019
  ctx.textAlign = 'left';
2020
  ctx.fillText(`RΒ² = ${r2.toFixed(3)}`, padding + 10, padding + 25);
2021
  ctx.fillText(`Model explains ${(r2 * 100).toFixed(1)}% of variance`, padding + 10, padding + 50);
2022
+
2023
+ logViz('Model Evaluation', 'RΒ² Score', 'success');
2024
  }
2025
 
2026
  // Regularization
 
2045
 
2046
  function drawRegularization() {
2047
  const canvas = document.getElementById('regularization-canvas');
2048
+ if (!canvas) {
2049
+ logViz('Regularization', 'L1 vs L2 Comparison', 'failed', 'Canvas not found');
2050
+ return;
2051
+ }
2052
 
2053
  const ctx = canvas.getContext('2d');
2054
  const width = canvas.width = canvas.offsetWidth;
 
2115
  ctx.fillRect(padding + 210, legendY, 15, 15);
2116
  ctx.fillStyle = '#e8eef6';
2117
  ctx.fillText('L2 (Ridge)', padding + 230, legendY + 12);
2118
+
2119
+ logViz('Regularization', 'L1 vs L2 Comparison', 'success');
2120
  }
2121
 
2122
  // Bias-Variance
 
2135
 
2136
  function drawBiasVariance() {
2137
  const canvas = document.getElementById('bias-variance-canvas');
2138
+ if (!canvas) {
2139
+ logViz('Bias-Variance', 'Three Models', 'failed', 'Canvas not found');
2140
+ return;
2141
+ }
2142
 
2143
  const ctx = canvas.getContext('2d');
2144
  const width = canvas.width = canvas.offsetWidth;
 
2214
  ctx.fillText(line, offsetX + sectionWidth / 2, 20 + i * 18);
2215
  });
2216
  });
2217
+
2218
+ logViz('Bias-Variance', 'Three Models', 'success');
2219
  }
2220
 
2221
  function drawComplexityCurve() {
2222
  const canvas = document.getElementById('complexity-canvas');
2223
+ if (!canvas) {
2224
+ logViz('Bias-Variance', 'Complexity Curve', 'failed', 'Canvas not found');
2225
+ return;
2226
+ }
2227
 
2228
  const ctx = canvas.getContext('2d');
2229
  const width = canvas.width = canvas.offsetWidth;
 
2276
  ctx.fillStyle = '#7ef0d4';
2277
  ctx.fillText('● Sweet Spot', padding + 10, padding + 60);
2278
 
2279
+ logViz('Bias-Variance', 'Complexity Curve', 'success');
2280
+
2281
  // Labels
2282
  ctx.fillStyle = '#a9b4c2';
2283
  ctx.textAlign = 'center';
 
2299
 
2300
  function drawCrossValidation() {
2301
  const canvas = document.getElementById('cv-canvas');
2302
+ if (!canvas) {
2303
+ logViz('Cross-Validation', 'K-Fold Visualization', 'failed', 'Canvas not found');
2304
+ return;
2305
+ }
2306
 
2307
  const ctx = canvas.getContext('2d');
2308
  const width = canvas.width = canvas.offsetWidth;
 
2373
  ctx.font = 'bold 16px sans-serif';
2374
  ctx.textAlign = 'center';
2375
  ctx.fillText(`Final Score: ${mean.toFixed(2)} Β± ${std.toFixed(3)}`, width / 2, height - 20);
2376
+
2377
+ logViz('Cross-Validation', 'K-Fold Visualization', 'success');
2378
  }
2379
 
2380
  // Preprocessing
 
2394
 
2395
  function drawScaling() {
2396
  const canvas = document.getElementById('scaling-canvas');
2397
+ if (!canvas) {
2398
+ logViz('Preprocessing', 'Feature Scaling', 'failed', 'Canvas not found');
2399
+ return;
2400
+ }
2401
 
2402
  const ctx = canvas.getContext('2d');
2403
  const width = canvas.width = canvas.offsetWidth;
 
2449
  centerX += 35;
2450
  });
2451
  });
2452
+
2453
+ logViz('Preprocessing', 'Feature Scaling', 'success');
2454
  }
2455
 
2456
  function drawPipeline() {
2457
  const canvas = document.getElementById('pipeline-canvas');
2458
+ if (!canvas) {
2459
+ logViz('Preprocessing', 'Pipeline Flow', 'failed', 'Canvas not found');
2460
+ return;
2461
+ }
2462
 
2463
  const ctx = canvas.getContext('2d');
2464
  const width = canvas.width = canvas.offsetWidth;
 
2509
  ctx.fill();
2510
  }
2511
  });
2512
+
2513
+ logViz('Preprocessing', 'Pipeline Flow', 'success');
2514
  }
2515
 
2516
  // Loss Functions
 
2530
 
2531
  function drawLossComparison() {
2532
  const canvas = document.getElementById('loss-comparison-canvas');
2533
+ if (!canvas) {
2534
+ logViz('Loss Functions', 'Loss Comparison', 'failed', 'Canvas not found');
2535
+ return;
2536
+ }
2537
 
2538
  const ctx = canvas.getContext('2d');
2539
  const width = canvas.width = canvas.offsetWidth;
 
2596
  ctx.font = 'bold 16px sans-serif';
2597
  ctx.textAlign = 'center';
2598
  ctx.fillText('Regression Loss Comparison', width / 2, 50);
2599
+
2600
+ logViz('Loss Functions', 'Loss Comparison', 'success');
2601
  }
2602
 
2603
  function drawLossCurves() {
2604
  const canvas = document.getElementById('loss-curves-canvas');
2605
+ if (!canvas) {
2606
+ logViz('Loss Functions', 'Loss Curves', 'failed', 'Canvas not found');
2607
+ return;
2608
+ }
2609
 
2610
  const ctx = canvas.getContext('2d');
2611
  const width = canvas.width = canvas.offsetWidth;
 
2661
  ctx.rotate(-Math.PI / 2);
2662
  ctx.fillText('Loss', 0, 0);
2663
  ctx.restore();
2664
+
2665
+ logViz('Loss Functions', 'Loss Curves', 'success');
2666
  }
2667
 
2668
  // Topic 13: Finding Optimal K in KNN
 
2722
  }
2723
 
2724
  // Use Chart.js
2725
+ // Destroy existing chart
2726
+ if (elbowChart) {
2727
+ elbowChart.destroy();
2728
+ }
2729
+
2730
+ elbowChart = createVerifiedVisualization('elbow-canvas', {
2731
  type: 'line',
2732
  data: {
2733
  labels: kValues,
 
2786
  }
2787
  }
2788
  }
2789
+ }, 'KNN', 'Elbow Method');
2790
  }
2791
 
2792
  function drawCVKHeatmap() {
2793
  const canvas = document.getElementById('cv-k-canvas');
2794
+ if (!canvas) {
2795
+ logViz('Optimal K', 'CV Heatmap', 'failed', 'Canvas not found');
2796
+ return;
2797
+ }
2798
 
2799
  const ctx = canvas.getContext('2d');
2800
  const width = canvas.width = canvas.offsetWidth;
 
2873
  const maxMean = Math.max(...meanAccs);
2874
  const optIdx = meanAccs.indexOf(maxMean);
2875
  ctx.fillText(`Best K = ${kValues[optIdx]} (Mean Acc: ${maxMean.toFixed(3)})`, padding, height - 20);
2876
+
2877
+ logViz('Optimal K', 'CV Heatmap', 'success');
2878
  }
2879
 
2880
  // Topic 14: Hyperparameter Tuning
 
2903
 
2904
  function drawGridSearchHeatmap() {
2905
  const canvas = document.getElementById('gridsearch-heatmap');
2906
+ if (!canvas) {
2907
+ logViz('Hyperparameter Tuning', 'GridSearch Heatmap', 'failed', 'Canvas not found');
2908
+ return;
 
 
2909
  }
2910
 
2911
  const ctx = canvas.getContext('2d');
 
3024
  ctx.font = 'bold 14px sans-serif';
3025
  ctx.textAlign = 'left';
3026
  ctx.fillText(`Best: C=${cValues[bestJ]}, Ξ³=${gammaValues[bestI]} β†’ Acc=${bestAcc.toFixed(2)}`, padding, height - 30);
3027
+
3028
+ logViz('Hyperparameter Tuning', 'GridSearch Heatmap', 'success');
3029
  }
3030
 
3031
  function drawParamSurface() {
3032
  const canvas = document.getElementById('param-surface');
3033
+ if (!canvas) {
3034
+ logViz('Hyperparameter Tuning', 'Parameter Surface', 'failed', 'Canvas not found');
3035
+ return;
3036
+ }
3037
 
3038
  const ctx = canvas.getContext('2d');
3039
  const width = canvas.width = canvas.offsetWidth;
 
3092
  ctx.font = 'bold 16px sans-serif';
3093
  ctx.textAlign = 'center';
3094
  ctx.fillText('Performance Surface (3D Contour View)', width / 2, 30);
3095
+
3096
+ logViz('Hyperparameter Tuning', 'Parameter Surface', 'success');
3097
  }
3098
 
3099
  // Topic 15: Naive Bayes
 
3129
 
3130
  function drawBayesTheorem() {
3131
  const canvas = document.getElementById('bayes-theorem-viz');
3132
+ if (!canvas) {
3133
+ logViz('Naive Bayes', 'Bayes Theorem Flow', 'failed', 'Canvas not found');
3134
+ return;
3135
+ }
3136
 
3137
  const ctx = canvas.getContext('2d');
3138
  const width = canvas.width = canvas.offsetWidth;
 
3194
 
3195
  const ctx = canvas.getContext('2d');
3196
 
3197
+ if (categoricalNBChart) {
3198
+ categoricalNBChart.destroy();
3199
+ }
3200
+
3201
+ categoricalNBChart = createVerifiedVisualization('categorical-nb-canvas', {
3202
  type: 'bar',
3203
  data: {
3204
  labels: ['P(Yes|Rainy,Hot)', 'P(No|Rainy,Hot)'],
 
3250
  }
3251
  }
3252
  }
3253
+ }, 'Naive Bayes', 'Categorical Calculation');
3254
  }
3255
 
3256
  function drawGaussianNB() {
3257
  const canvas = document.getElementById('gaussian-nb-canvas');
3258
+ if (!canvas) {
3259
+ logViz('Naive Bayes', 'Gaussian NB Boundary', 'failed', 'Canvas not found');
3260
+ return;
3261
+ }
3262
 
3263
  const ctx = canvas.getContext('2d');
3264
  const width = canvas.width = canvas.offsetWidth;
 
3366
 
3367
  ctx.fillStyle = '#6aa9ff';
3368
  ctx.fillText('| Decision Boundary', padding + 210, 35);
3369
+
3370
+ logViz('Naive Bayes', 'Gaussian NB Boundary', 'success');
3371
  }
3372
 
3373
  function drawSpamClassification() {
 
3437
  compCanvas.style.marginTop = '20px';
3438
  canvas.parentElement.appendChild(compCanvas);
3439
 
3440
+ if (bayesComparisonChart) {
3441
+ bayesComparisonChart.destroy();
3442
+ }
3443
+
3444
+ bayesComparisonChart = createVerifiedVisualization('bayes-comparison-chart', {
3445
  type: 'bar',
3446
  data: {
3447
  labels: ['Spam Probability', 'Not-Spam Probability'],
 
3477
  }
3478
  }
3479
  }
3480
+ }, 'Naive Bayes', 'Spam Classification');
3481
  if (bayesComparisonChart) compCanvas.style.height = '150px';
3482
  }
3483
+
3484
+ logViz('Naive Bayes', 'Bayes Theorem Flow', 'success');
3485
  }
3486
 
3487
  // Topic 16: Decision Trees
 
3513
 
3514
  function drawDecisionTree() {
3515
  const canvas = document.getElementById('decision-tree-viz');
3516
+ if (!canvas) {
3517
+ logViz('Decision Trees', 'Tree Structure', 'failed', 'Canvas not found');
3518
+ return;
3519
+ }
3520
 
3521
  const ctx = canvas.getContext('2d');
3522
  const width = canvas.width = canvas.offsetWidth;
 
3600
  ctx.font = '12px sans-serif';
3601
  ctx.textAlign = 'left';
3602
  ctx.fillText('Example: Email with "free" + link β†’ SPAM', 40, height - 20);
3603
+
3604
+ logViz('Decision Trees', 'Tree Structure', 'success');
3605
  }
3606
 
3607
  function drawSplitComparison() {
 
3659
  ctx.textAlign = 'center';
3660
  ctx.fillText('βœ“ Best split: Highest Information Gain!', width / 2, height - 30);
3661
 
3662
+ logViz('Decision Trees', 'Information Gain', 'success');
3663
+
3664
  // Title
3665
  ctx.fillStyle = '#7ef0d4';
3666
  ctx.font = 'bold 16px sans-serif';
 
3669
 
3670
  function drawEntropyViz() {
3671
  const canvas = document.getElementById('entropy-viz');
3672
+ if (!canvas) {
3673
+ logViz('Decision Trees', 'Entropy Visualization', 'failed', 'Canvas not found');
3674
+ return;
3675
+ }
3676
 
3677
  const ctx = canvas.getContext('2d');
3678
  const width = canvas.width = canvas.offsetWidth;
 
3750
  ctx.font = 'bold 16px sans-serif';
3751
  ctx.textAlign = 'center';
3752
  ctx.fillText('Entropy: Measuring Disorder', width / 2, 30);
3753
+
3754
+ logViz('Decision Trees', 'Entropy Visualization', 'success');
3755
  }
3756
 
3757
  function drawSplitComparison() {
 
3899
 
3900
  function drawTreeBoundary() {
3901
  const canvas = document.getElementById('tree-boundary');
3902
+ if (!canvas) {
3903
+ logViz('Decision Trees', 'Decision Regions', 'failed', 'Canvas not found');
3904
+ return;
3905
+ }
3906
 
3907
  const ctx = canvas.getContext('2d');
3908
  const width = canvas.width = canvas.offsetWidth;
 
3987
  ctx.font = 'bold 16px sans-serif';
3988
  ctx.textAlign = 'center';
3989
  ctx.fillText('Decision Tree Creates Rectangular Regions', width / 2, 30);
3990
+
3991
+ logViz('Decision Trees', 'Decision Regions', 'success');
3992
  }
3993
 
3994
+ // Topic 16b: Decision Tree Regression Visualization
3995
+ function initDecisionTreeRegression() {
3996
+ const canvas1 = document.getElementById('dt-regression-canvas');
3997
  if (canvas1 && !canvas1.dataset.initialized) {
3998
  canvas1.dataset.initialized = 'true';
3999
+ drawDTRegression();
4000
  }
4001
 
4002
+ const canvas2 = document.getElementById('dt-splits-canvas');
4003
  if (canvas2 && !canvas2.dataset.initialized) {
4004
  canvas2.dataset.initialized = 'true';
4005
+ drawDTSplits();
 
 
 
 
 
 
4006
  }
4007
  }
4008
 
4009
+ function drawDTRegression() {
4010
+ const canvas = document.getElementById('dt-regression-canvas');
4011
+ if (!canvas) {
4012
+ logViz('Decision Tree Regression', 'Splits & Predictions', 'failed', 'Canvas not found');
4013
+ return;
4014
+ }
4015
 
4016
  const ctx = canvas.getContext('2d');
4017
  const width = canvas.width = canvas.offsetWidth;
4018
+ const height = canvas.height = 450;
4019
 
4020
  ctx.clearRect(0, 0, width, height);
4021
  ctx.fillStyle = '#1a2332';
4022
  ctx.fillRect(0, 0, width, height);
4023
 
4024
+ const padding = 60;
4025
+ const chartWidth = width - 2 * padding;
4026
+ const chartHeight = height - 2 * padding;
 
4027
 
4028
+ const xMin = 700, xMax = 1800;
4029
+ const yMin = 40, yMax = 110;
4030
+ const scaleX = (x) => padding + ((x - xMin) / (xMax - xMin)) * chartWidth;
4031
+ const scaleY = (y) => height - padding - ((y - yMin) / (yMax - yMin)) * chartHeight;
4032
+
4033
+ // Data points
4034
+ const data = [
4035
+ {x: 800, y: 50}, {x: 850, y: 52}, {x: 900, y: 54},
4036
+ {x: 1500, y: 90}, {x: 1600, y: 95}, {x: 1700, y: 100}
4037
+ ];
4038
+
4039
+ // Draw decision boundaries
4040
  ctx.strokeStyle = '#6aa9ff';
4041
+ ctx.lineWidth = 3;
4042
+ ctx.setLineDash([5, 5]);
4043
+ ctx.beginPath();
4044
+ ctx.moveTo(scaleX(1200), padding);
4045
+ ctx.lineTo(scaleX(1200), height - padding);
4046
+ ctx.stroke();
4047
 
4048
+ ctx.beginPath();
4049
+ ctx.moveTo(scaleX(1550), padding);
4050
+ ctx.lineTo(scaleX(1550), height - padding);
4051
+ ctx.stroke();
4052
+ ctx.setLineDash([]);
4053
+
4054
+ // Draw regions with predictions
4055
+ ctx.fillStyle = 'rgba(126, 240, 212, 0.1)';
4056
+ ctx.fillRect(scaleX(700), scaleY(52), scaleX(1200) - scaleX(700), height - padding - scaleY(52));
4057
+ ctx.fillStyle = 'rgba(255, 140, 106, 0.1)';
4058
+ ctx.fillRect(scaleX(1200), scaleY(90), scaleX(1550) - scaleX(1200), height - padding - scaleY(90));
4059
+ ctx.fillStyle = 'rgba(106, 169, 255, 0.1)';
4060
+ ctx.fillRect(scaleX(1550), scaleY(97.5), scaleX(1800) - scaleX(1550), height - padding - scaleY(97.5));
4061
+
4062
+ // Draw prediction lines
4063
+ ctx.strokeStyle = '#7ef0d4';
4064
+ ctx.lineWidth = 4;
4065
+ ctx.beginPath();
4066
+ ctx.moveTo(scaleX(700), scaleY(52));
4067
+ ctx.lineTo(scaleX(1200), scaleY(52));
4068
+ ctx.stroke();
4069
+
4070
+ ctx.strokeStyle = '#ff8c6a';
4071
+ ctx.beginPath();
4072
+ ctx.moveTo(scaleX(1200), scaleY(90));
4073
+ ctx.lineTo(scaleX(1550), scaleY(90));
4074
+ ctx.stroke();
4075
+
4076
+ ctx.strokeStyle = '#6aa9ff';
4077
+ ctx.beginPath();
4078
+ ctx.moveTo(scaleX(1550), scaleY(97.5));
4079
+ ctx.lineTo(scaleX(1800), scaleY(97.5));
4080
+ ctx.stroke();
4081
+
4082
+ // Draw data points
4083
+ data.forEach(point => {
4084
+ ctx.fillStyle = '#e8eef6';
4085
+ ctx.beginPath();
4086
+ ctx.arc(scaleX(point.x), scaleY(point.y), 6, 0, 2 * Math.PI);
4087
+ ctx.fill();
4088
+ ctx.strokeStyle = '#1a2332';
4089
+ ctx.lineWidth = 2;
4090
+ ctx.stroke();
4091
+ });
4092
+
4093
+ // Labels
4094
+ ctx.fillStyle = '#7ef0d4';
4095
+ ctx.font = 'bold 13px sans-serif';
4096
+ ctx.textAlign = 'center';
4097
+ ctx.fillText('Predict: β‚Ή52L', scaleX(950), scaleY(52) - 10);
4098
+ ctx.fillStyle = '#ff8c6a';
4099
+ ctx.fillText('Predict: β‚Ή90L', scaleX(1375), scaleY(90) - 10);
4100
+ ctx.fillStyle = '#6aa9ff';
4101
+ ctx.fillText('Predict: β‚Ή97.5L', scaleX(1650), scaleY(97.5) - 10);
4102
+
4103
+ // Axes
4104
+ ctx.fillStyle = '#a9b4c2';
4105
+ ctx.font = '12px sans-serif';
4106
+ ctx.textAlign = 'center';
4107
+ ctx.fillText('Square Feet', width / 2, height - 20);
4108
+ ctx.save();
4109
+ ctx.translate(20, height / 2);
4110
+ ctx.rotate(-Math.PI / 2);
4111
+ ctx.fillText('Price (Lakhs)', 0, 0);
4112
+ ctx.restore();
4113
+
4114
+ ctx.fillStyle = '#7ef0d4';
4115
+ ctx.font = 'bold 14px sans-serif';
4116
+ ctx.fillText('Split at 1200', scaleX(1200), 30);
4117
+ ctx.fillText('Split at 1550', scaleX(1550), 30);
4118
+
4119
+ logViz('Decision Tree Regression', 'Splits & Predictions', 'success');
4120
+ }
4121
+
4122
+ function drawDTSplits() {
4123
+ const canvas = document.getElementById('dt-splits-canvas');
4124
+ if (!canvas) {
4125
+ logViz('Decision Tree Regression', 'Split Comparison', 'failed', 'Canvas not found');
4126
+ return;
4127
+ }
4128
+
4129
+ const ctx = canvas.getContext('2d');
4130
+ const width = canvas.width = canvas.offsetWidth;
4131
+ const height = canvas.height = 400;
4132
+
4133
+ ctx.clearRect(0, 0, width, height);
4134
+ ctx.fillStyle = '#1a2332';
4135
+ ctx.fillRect(0, 0, width, height);
4136
+
4137
+ const splits = [
4138
+ {value: 825, varReduction: 120, color: '#ff8c6a'},
4139
+ {value: 875, varReduction: 180, color: '#ffb490'},
4140
+ {value: 1200, varReduction: 462.25, color: '#7ef0d4'},
4141
+ {value: 1550, varReduction: 95, color: '#ffb490'},
4142
+ {value: 1650, varReduction: 65, color: '#ff8c6a'}
4143
+ ];
4144
+
4145
+ const padding = 60;
4146
+ const barHeight = 50;
4147
+ const maxWidth = width - 2 * padding - 200;
4148
+ const maxVR = Math.max(...splits.map(s => s.varReduction));
4149
+
4150
+ splits.forEach((split, i) => {
4151
+ const y = 60 + i * (barHeight + 25);
4152
+ const barWidth = (split.varReduction / maxVR) * maxWidth;
4153
+
4154
+ ctx.fillStyle = split.color;
4155
+ ctx.fillRect(padding, y, barWidth, barHeight);
4156
+ ctx.strokeStyle = split.color;
4157
+ ctx.lineWidth = 2;
4158
+ ctx.strokeRect(padding, y, barWidth, barHeight);
4159
+
4160
+ ctx.fillStyle = '#e8eef6';
4161
+ ctx.font = 'bold 12px sans-serif';
4162
+ ctx.textAlign = 'left';
4163
+ ctx.fillText(`Split at ${split.value}`, padding, y - 8);
4164
+
4165
+ ctx.fillStyle = '#1a2332';
4166
+ ctx.font = 'bold 14px sans-serif';
4167
+ ctx.textAlign = 'center';
4168
+ ctx.fillText(`VR = ${split.varReduction.toFixed(1)}`, padding + barWidth / 2, y + barHeight / 2 + 5);
4169
+ });
4170
+
4171
+ ctx.fillStyle = '#7ef0d4';
4172
+ ctx.font = 'bold 16px sans-serif';
4173
+ ctx.textAlign = 'center';
4174
+ ctx.fillText('βœ“ Split at 1200: Maximum Variance Reduction!', width / 2, height - 20);
4175
+
4176
+ logViz('Decision Tree Regression', 'Split Comparison', 'success');
4177
+ }
4178
+
4179
+ // Topic 17a: Gradient Boosting (NEW)
4180
+ function initGradientBoosting() {
4181
+ const canvases = [
4182
+ { id: 'gb-sequential-canvas', fn: drawGBSequential },
4183
+ { id: 'gb-residuals-canvas', fn: drawGBResiduals },
4184
+ { id: 'gb-learning-rate-canvas', fn: drawGBLearningRate },
4185
+ { id: 'gb-stumps-canvas', fn: drawGBStumps },
4186
+ { id: 'gb-predictions-canvas', fn: drawGBPredictions }
4187
+ ];
4188
+
4189
+ canvases.forEach(c => {
4190
+ const canvas = document.getElementById(c.id);
4191
+ if (canvas && !canvas.dataset.initialized) {
4192
+ canvas.dataset.initialized = 'true';
4193
+ c.fn();
4194
+ }
4195
+ });
4196
+ }
4197
+
4198
+ function drawGBSequential() {
4199
+ const canvas = document.getElementById('gb-sequential-canvas');
4200
+ if (!canvas) return;
4201
+
4202
+ const gbData = [
4203
+ { iteration: 0, f: 154, residual: 29.6 },
4204
+ { iteration: 1, f: 151.93, residual: 26.8 },
4205
+ { iteration: 2, f: 149.5, residual: 24.1 },
4206
+ { iteration: 3, f: 147.2, residual: 21.5 },
4207
+ { iteration: 4, f: 145.1, residual: 19.2 },
4208
+ { iteration: 5, f: 143.2, residual: 17.1 },
4209
+ { iteration: 6, f: 141.5, residual: 15.3 },
4210
+ { iteration: 7, f: 140.0, residual: 13.7 },
4211
+ { iteration: 8, f: 138.6, residual: 12.2 },
4212
+ { iteration: 9, f: 137.4, residual: 10.9 },
4213
+ { iteration: 10, f: 136.3, residual: 9.8 }
4214
+ ];
4215
+
4216
+ createVerifiedVisualization('gb-sequential-canvas', {
4217
+ type: 'line',
4218
+ data: {
4219
+ datasets: [
4220
+ {
4221
+ label: 'Mean Prediction F(t)',
4222
+ data: gbData.map(d => ({ x: d.iteration, y: d.f })),
4223
+ borderColor: '#6aa9ff',
4224
+ backgroundColor: 'rgba(106, 169, 255, 0.1)',
4225
+ borderWidth: 3,
4226
+ fill: true,
4227
+ yAxisID: 'y'
4228
+ },
4229
+ {
4230
+ label: 'Mean Absolute Residual',
4231
+ data: gbData.map(d => ({ x: d.iteration, y: d.residual })),
4232
+ borderColor: '#ff8c6a',
4233
+ backgroundColor: 'rgba(255, 140, 106, 0.1)',
4234
+ borderWidth: 3,
4235
+ fill: true,
4236
+ yAxisID: 'y1'
4237
+ }
4238
+ ]
4239
+ },
4240
+ options: {
4241
+ responsive: true,
4242
+ maintainAspectRatio: false,
4243
+ plugins: {
4244
+ title: {
4245
+ display: true,
4246
+ text: 'Gradient Boosting: Sequential Learning',
4247
+ color: '#e8eef6',
4248
+ font: { size: 16 }
4249
+ },
4250
+ legend: { labels: { color: '#a9b4c2' } }
4251
+ },
4252
+ scales: {
4253
+ x: {
4254
+ title: { display: true, text: 'Iteration', color: '#a9b4c2' },
4255
+ grid: { color: '#2a3544' },
4256
+ ticks: { color: '#a9b4c2' }
4257
+ },
4258
+ y: {
4259
+ type: 'linear',
4260
+ position: 'left',
4261
+ title: { display: true, text: 'Prediction F(t)', color: '#6aa9ff' },
4262
+ grid: { color: '#2a3544' },
4263
+ ticks: { color: '#a9b4c2' }
4264
+ },
4265
+ y1: {
4266
+ type: 'linear',
4267
+ position: 'right',
4268
+ title: { display: true, text: 'Residual', color: '#ff8c6a' },
4269
+ grid: { display: false },
4270
+ ticks: { color: '#a9b4c2' }
4271
+ }
4272
+ }
4273
+ }
4274
+ }, 'Gradient Boosting', 'Sequential Trees');
4275
+ }
4276
+
4277
+ function drawGBResiduals() {
4278
+ const canvas = document.getElementById('gb-residuals-canvas');
4279
+ if (!canvas) return;
4280
+
4281
+ const residuals = [
4282
+ { id: 1, iter0: -34, iter1: -31.93, iter5: -12, iter10: -3 },
4283
+ { id: 2, iter0: -24, iter1: -21.93, iter5: -8, iter10: -2 },
4284
+ { id: 3, iter0: -4, iter1: -1.93, iter5: -1, iter10: 0 },
4285
+ { id: 4, iter0: 16, iter1: 12.90, iter5: 5, iter10: 1 },
4286
+ { id: 5, iter0: 46, iter1: 42.90, iter5: 18, iter10: 4 }
4287
+ ];
4288
+
4289
+ createVerifiedVisualization('gb-residuals-canvas', {
4290
+ type: 'bar',
4291
+ data: {
4292
+ labels: ['ID 1', 'ID 2', 'ID 3', 'ID 4', 'ID 5'],
4293
+ datasets: [
4294
+ {
4295
+ label: 'Iteration 0',
4296
+ data: residuals.map(r => r.iter0),
4297
+ backgroundColor: '#ff8c6a'
4298
+ },
4299
+ {
4300
+ label: 'Iteration 1',
4301
+ data: residuals.map(r => r.iter1),
4302
+ backgroundColor: '#ffb490'
4303
+ },
4304
+ {
4305
+ label: 'Iteration 5',
4306
+ data: residuals.map(r => r.iter5),
4307
+ backgroundColor: '#6aa9ff'
4308
+ },
4309
+ {
4310
+ label: 'Iteration 10',
4311
+ data: residuals.map(r => r.iter10),
4312
+ backgroundColor: '#7ef0d4'
4313
+ }
4314
+ ]
4315
+ },
4316
+ options: {
4317
+ responsive: true,
4318
+ maintainAspectRatio: false,
4319
+ plugins: {
4320
+ title: {
4321
+ display: true,
4322
+ text: 'Residual Reduction Over Iterations',
4323
+ color: '#e8eef6',
4324
+ font: { size: 16 }
4325
+ },
4326
+ legend: { labels: { color: '#a9b4c2' } }
4327
+ },
4328
+ scales: {
4329
+ x: {
4330
+ grid: { color: '#2a3544' },
4331
+ ticks: { color: '#a9b4c2' }
4332
+ },
4333
+ y: {
4334
+ title: { display: true, text: 'Residual Value', color: '#a9b4c2' },
4335
+ grid: { color: '#2a3544' },
4336
+ ticks: { color: '#a9b4c2' }
4337
+ }
4338
+ }
4339
+ }
4340
+ }, 'Gradient Boosting', 'Residual Reduction');
4341
+ }
4342
+
4343
+ function drawGBLearningRate() {
4344
+ const canvas = document.getElementById('gb-learning-rate-canvas');
4345
+ if (!canvas) return;
4346
+
4347
+ const iterations = Array.from({length: 21}, (_, i) => i);
4348
+
4349
+ const lr01 = iterations.map(i => 154 - 18 * (1 - Math.exp(-i * 0.01)));
4350
+ const lr10 = iterations.map(i => 154 - 18 * (1 - Math.exp(-i * 0.1)));
4351
+ const lr100 = iterations.map(i => {
4352
+ if (i === 0) return 154;
4353
+ if (i < 5) return 154 - 18 * (1 - Math.exp(-i * 1.0));
4354
+ return 136 + Math.sin(i) * 2;
4355
+ });
4356
+
4357
+ createVerifiedVisualization('gb-learning-rate-canvas', {
4358
+ type: 'line',
4359
+ data: {
4360
+ labels: iterations,
4361
+ datasets: [
4362
+ {
4363
+ label: 'lr = 0.01 (slow)',
4364
+ data: lr01,
4365
+ borderColor: '#ff8c6a',
4366
+ borderWidth: 3,
4367
+ pointRadius: 2
4368
+ },
4369
+ {
4370
+ label: 'lr = 0.1 (good)',
4371
+ data: lr10,
4372
+ borderColor: '#7ef0d4',
4373
+ borderWidth: 3,
4374
+ pointRadius: 2
4375
+ },
4376
+ {
4377
+ label: 'lr = 1.0 (too fast)',
4378
+ data: lr100,
4379
+ borderColor: '#6aa9ff',
4380
+ borderWidth: 3,
4381
+ pointRadius: 2
4382
+ }
4383
+ ]
4384
+ },
4385
+ options: {
4386
+ responsive: true,
4387
+ maintainAspectRatio: false,
4388
+ plugins: {
4389
+ title: {
4390
+ display: true,
4391
+ text: 'Learning Rate Effect on Convergence',
4392
+ color: '#e8eef6',
4393
+ font: { size: 16 }
4394
+ },
4395
+ legend: { labels: { color: '#a9b4c2' } }
4396
+ },
4397
+ scales: {
4398
+ x: {
4399
+ title: { display: true, text: 'Iteration', color: '#a9b4c2' },
4400
+ grid: { color: '#2a3544' },
4401
+ ticks: { color: '#a9b4c2' }
4402
+ },
4403
+ y: {
4404
+ title: { display: true, text: 'Mean Prediction', color: '#a9b4c2' },
4405
+ grid: { color: '#2a3544' },
4406
+ ticks: { color: '#a9b4c2' }
4407
+ }
4408
+ }
4409
+ }
4410
+ }, 'Gradient Boosting', 'Learning Rate Effect');
4411
+ }
4412
+
4413
+ function drawGBStumps() {
4414
+ const canvas = document.getElementById('gb-stumps-canvas');
4415
+ if (!canvas) return;
4416
+
4417
+ const ctx = canvas.getContext('2d');
4418
+ const width = canvas.width = canvas.offsetWidth;
4419
+ const height = canvas.height = 400;
4420
+
4421
+ ctx.clearRect(0, 0, width, height);
4422
+ ctx.fillStyle = '#1a2332';
4423
+ ctx.fillRect(0, 0, width, height);
4424
+
4425
+ const stumps = [
4426
+ { name: 'h1', split: 1050, left: -20.66, right: 31.0, color: '#6aa9ff' },
4427
+ { name: 'h2', split: 950, left: -15.2, right: 22.5, color: '#7ef0d4' },
4428
+ { name: 'h3', split: 1150, left: -8.5, right: 14.8, color: '#ffb490' }
4429
+ ];
4430
+
4431
+ const stumpWidth = width / 3;
4432
+
4433
+ stumps.forEach((stump, idx) => {
4434
+ const offsetX = idx * stumpWidth;
4435
+ const centerX = offsetX + stumpWidth / 2;
4436
+
4437
+ // Title
4438
+ ctx.fillStyle = stump.color;
4439
+ ctx.font = 'bold 14px sans-serif';
4440
+ ctx.textAlign = 'center';
4441
+ ctx.fillText(stump.name, centerX, 30);
4442
+
4443
+ // Root node
4444
+ ctx.fillStyle = stump.color + '33';
4445
+ ctx.fillRect(centerX - 40, 60, 80, 50);
4446
+ ctx.strokeStyle = stump.color;
4447
+ ctx.lineWidth = 2;
4448
+ ctx.strokeRect(centerX - 40, 60, 80, 50);
4449
+
4450
+ ctx.fillStyle = '#e8eef6';
4451
+ ctx.font = '12px sans-serif';
4452
+ ctx.fillText('Size &lt;', centerX, 80);
4453
+ ctx.fillText(stump.split, centerX, 95);
4454
+
4455
+ // Left child
4456
+ ctx.strokeStyle = stump.color;
4457
+ ctx.beginPath();
4458
+ ctx.moveTo(centerX, 110);
4459
+ ctx.lineTo(centerX - 50, 180);
4460
+ ctx.stroke();
4461
+
4462
+ ctx.fillStyle = '#7ef0d4' + '33';
4463
+ ctx.fillRect(centerX - 85, 180, 70, 50);
4464
+ ctx.strokeStyle = '#7ef0d4';
4465
+ ctx.strokeRect(centerX - 85, 180, 70, 50);
4466
+
4467
+ ctx.fillStyle = '#e8eef6';
4468
+ ctx.font = 'bold 13px sans-serif';
4469
+ ctx.fillText(stump.left.toFixed(2), centerX - 50, 210);
4470
+
4471
+ // Right child
4472
+ ctx.strokeStyle = stump.color;
4473
+ ctx.beginPath();
4474
+ ctx.moveTo(centerX, 110);
4475
+ ctx.lineTo(centerX + 50, 180);
4476
+ ctx.stroke();
4477
+
4478
+ ctx.fillStyle = '#ff8c6a' + '33';
4479
+ ctx.fillRect(centerX + 15, 180, 70, 50);
4480
+ ctx.strokeStyle = '#ff8c6a';
4481
+ ctx.strokeRect(centerX + 15, 180, 70, 50);
4482
+
4483
+ ctx.fillStyle = '#e8eef6';
4484
+ ctx.font = 'bold 13px sans-serif';
4485
+ ctx.fillText(stump.right.toFixed(2), centerX + 50, 210);
4486
+
4487
+ // Labels
4488
+ ctx.fillStyle = '#a9b4c2';
4489
+ ctx.font = '10px sans-serif';
4490
+ ctx.fillText('≀', centerX - 50, 150);
4491
+ ctx.fillText('&gt;', centerX + 50, 150);
4492
+ });
4493
+
4494
+ // Title
4495
+ ctx.fillStyle = '#7ef0d4';
4496
+ ctx.font = 'bold 16px sans-serif';
4497
+ ctx.textAlign = 'center';
4498
+ ctx.fillText('Weak Learner Stumps (Depth = 1)', width / 2, height - 20);
4499
+
4500
+ logViz('Gradient Boosting', 'Weak Learner Stumps', 'success');
4501
+ }
4502
+
4503
+ function drawGBPredictions() {
4504
+ const canvas = document.getElementById('gb-predictions-canvas');
4505
+ if (!canvas) return;
4506
+
4507
+ const actual = [120, 130, 150, 170, 200];
4508
+ const iter0 = [154, 154, 154, 154, 154];
4509
+ const iter5 = [125, 135, 148, 165, 195];
4510
+ const iter10 = [121, 131, 149, 169, 199];
4511
+
4512
+ createVerifiedVisualization('gb-predictions-canvas', {
4513
+ type: 'scatter',
4514
+ data: {
4515
+ datasets: [
4516
+ {
4517
+ label: 'Actual',
4518
+ data: actual.map((y, i) => ({ x: i + 1, y: y })),
4519
+ backgroundColor: '#7ef0d4',
4520
+ pointRadius: 8
4521
+ },
4522
+ {
4523
+ label: 'Iteration 0',
4524
+ data: iter0.map((y, i) => ({ x: i + 1, y: y })),
4525
+ backgroundColor: '#ff8c6a',
4526
+ pointRadius: 6
4527
+ },
4528
+ {
4529
+ label: 'Iteration 5',
4530
+ data: iter5.map((y, i) => ({ x: i + 1, y: y })),
4531
+ backgroundColor: '#ffb490',
4532
+ pointRadius: 6
4533
+ },
4534
+ {
4535
+ label: 'Iteration 10',
4536
+ data: iter10.map((y, i) => ({ x: i + 1, y: y })),
4537
+ backgroundColor: '#6aa9ff',
4538
+ pointRadius: 6
4539
+ }
4540
+ ]
4541
+ },
4542
+ options: {
4543
+ responsive: true,
4544
+ maintainAspectRatio: false,
4545
+ plugins: {
4546
+ title: {
4547
+ display: true,
4548
+ text: 'Predictions Approaching Actual Values',
4549
+ color: '#e8eef6',
4550
+ font: { size: 16 }
4551
+ },
4552
+ legend: { labels: { color: '#a9b4c2' } }
4553
+ },
4554
+ scales: {
4555
+ x: {
4556
+ title: { display: true, text: 'Sample ID', color: '#a9b4c2' },
4557
+ grid: { color: '#2a3544' },
4558
+ ticks: { color: '#a9b4c2', stepSize: 1 }
4559
+ },
4560
+ y: {
4561
+ title: { display: true, text: 'Price (β‚Ή Lakhs)', color: '#a9b4c2' },
4562
+ grid: { color: '#2a3544' },
4563
+ ticks: { color: '#a9b4c2' }
4564
+ }
4565
+ }
4566
+ }
4567
+ }, 'Gradient Boosting', 'Predictions vs Actual');
4568
+ }
4569
+
4570
+ // Topic 17b: XGBoost (NEW)
4571
+ function initXGBoost() {
4572
+ const canvases = [
4573
+ { id: 'xgb-gain-canvas', fn: drawXGBGain },
4574
+ { id: 'xgb-regularization-canvas', fn: drawXGBRegularization },
4575
+ { id: 'xgb-hessian-canvas', fn: drawXGBHessian },
4576
+ { id: 'xgb-leaf-weights-canvas', fn: drawXGBLeafWeights },
4577
+ { id: 'xgb-comparison-canvas', fn: drawXGBComparison }
4578
+ ];
4579
+
4580
+ canvases.forEach(c => {
4581
+ const canvas = document.getElementById(c.id);
4582
+ if (canvas && !canvas.dataset.initialized) {
4583
+ canvas.dataset.initialized = 'true';
4584
+ c.fn();
4585
+ }
4586
+ });
4587
+ }
4588
+
4589
+ function drawXGBGain() {
4590
+ const canvas = document.getElementById('xgb-gain-canvas');
4591
+ if (!canvas) return;
4592
+
4593
+ const splits = [
4594
+ { threshold: 850, gl: -58, gr: 0, hl: 2, hr: 3, gain: 1121 },
4595
+ { threshold: 950, gl: -58, gr: 58, hl: 2, hr: 3, gain: 1962 },
4596
+ { threshold: 1050, gl: -62, gr: 62, hl: 3, hr: 2, gain: 1842 },
4597
+ { threshold: 1150, gl: -4, gr: 4, hl: 4, hr: 1, gain: 892 }
4598
+ ];
4599
+
4600
+ createVerifiedVisualization('xgb-gain-canvas', {
4601
+ type: 'bar',
4602
+ data: {
4603
+ labels: splits.map(s => `Split ${s.threshold}`),
4604
+ datasets: [
4605
+ {
4606
+ label: 'GL (Left Gradient)',
4607
+ data: splits.map(s => s.gl),
4608
+ backgroundColor: '#ff8c6a',
4609
+ stack: 'gradient'
4610
+ },
4611
+ {
4612
+ label: 'GR (Right Gradient)',
4613
+ data: splits.map(s => s.gr),
4614
+ backgroundColor: '#6aa9ff',
4615
+ stack: 'gradient'
4616
+ },
4617
+ {
4618
+ label: 'Gain Score',
4619
+ data: splits.map(s => s.gain),
4620
+ backgroundColor: '#7ef0d4',
4621
+ yAxisID: 'y1'
4622
+ }
4623
+ ]
4624
+ },
4625
+ options: {
4626
+ responsive: true,
4627
+ maintainAspectRatio: false,
4628
+ plugins: {
4629
+ title: {
4630
+ display: true,
4631
+ text: 'XGBoost Gain Calculation for Different Splits',
4632
+ color: '#e8eef6',
4633
+ font: { size: 16 }
4634
+ },
4635
+ legend: { labels: { color: '#a9b4c2' } }
4636
+ },
4637
+ scales: {
4638
+ x: {
4639
+ grid: { color: '#2a3544' },
4640
+ ticks: { color: '#a9b4c2' }
4641
+ },
4642
+ y: {
4643
+ title: { display: true, text: 'Gradient Sum', color: '#a9b4c2' },
4644
+ grid: { color: '#2a3544' },
4645
+ ticks: { color: '#a9b4c2' }
4646
+ },
4647
+ y1: {
4648
+ type: 'linear',
4649
+ position: 'right',
4650
+ title: { display: true, text: 'Gain', color: '#7ef0d4' },
4651
+ grid: { display: false },
4652
+ ticks: { color: '#a9b4c2' }
4653
+ }
4654
+ }
4655
+ }
4656
+ }, 'XGBoost', 'Gain Calculation');
4657
+ }
4658
+
4659
+ function drawXGBRegularization() {
4660
+ const canvas = document.getElementById('xgb-regularization-canvas');
4661
+ if (!canvas) return;
4662
+
4663
+ const lambdas = ['Ξ»=0', 'Ξ»=1', 'Ξ»=10'];
4664
+ const trainAcc = [0.99, 0.95, 0.88];
4665
+ const testAcc = [0.82, 0.93, 0.91];
4666
+
4667
+ createVerifiedVisualization('xgb-regularization-canvas', {
4668
+ type: 'bar',
4669
+ data: {
4670
+ labels: lambdas,
4671
+ datasets: [
4672
+ {
4673
+ label: 'Training Accuracy',
4674
+ data: trainAcc,
4675
+ backgroundColor: '#6aa9ff'
4676
+ },
4677
+ {
4678
+ label: 'Test Accuracy',
4679
+ data: testAcc,
4680
+ backgroundColor: '#7ef0d4'
4681
+ }
4682
+ ]
4683
+ },
4684
+ options: {
4685
+ responsive: true,
4686
+ maintainAspectRatio: false,
4687
+ plugins: {
4688
+ title: {
4689
+ display: true,
4690
+ text: 'Regularization Effect: Ξ» Controls Overfitting',
4691
+ color: '#e8eef6',
4692
+ font: { size: 16 }
4693
+ },
4694
+ legend: { labels: { color: '#a9b4c2' } }
4695
+ },
4696
+ scales: {
4697
+ x: {
4698
+ grid: { color: '#2a3544' },
4699
+ ticks: { color: '#a9b4c2' }
4700
+ },
4701
+ y: {
4702
+ title: { display: true, text: 'Accuracy', color: '#a9b4c2' },
4703
+ grid: { color: '#2a3544' },
4704
+ ticks: { color: '#a9b4c2' },
4705
+ min: 0.7,
4706
+ max: 1.0
4707
+ }
4708
+ }
4709
+ }
4710
+ }, 'XGBoost', 'Regularization Effect');
4711
+ }
4712
+
4713
+ function drawXGBHessian() {
4714
+ const canvas = document.getElementById('xgb-hessian-canvas');
4715
+ if (!canvas) return;
4716
+
4717
+ const ctx = canvas.getContext('2d');
4718
+ const width = canvas.width = canvas.offsetWidth;
4719
+ const height = canvas.height = 400;
4720
+
4721
+ ctx.clearRect(0, 0, width, height);
4722
+ ctx.fillStyle = '#1a2332';
4723
+ ctx.fillRect(0, 0, width, height);
4724
+
4725
+ const padding = 60;
4726
+ const chartWidth = width - 2 * padding;
4727
+ const chartHeight = height - 2 * padding;
4728
+
4729
+ // Draw surface comparison
4730
+ ctx.fillStyle = '#7ef0d4';
4731
+ ctx.font = 'bold 16px sans-serif';
4732
+ ctx.textAlign = 'center';
4733
+ ctx.fillText('Hessian Provides Curvature Information', width / 2, 30);
4734
+
4735
+ // Draw gradient only curve
4736
+ ctx.strokeStyle = '#ff8c6a';
4737
+ ctx.lineWidth = 3;
4738
+ ctx.beginPath();
4739
+ for (let x = 0; x <= 10; x += 0.2) {
4740
+ const y = 200 - 100 * Math.exp(-Math.pow(x - 5, 2) / 8);
4741
+ if (x === 0) ctx.moveTo(padding + x * chartWidth / 10, y);
4742
+ else ctx.lineTo(padding + x * chartWidth / 10, y);
4743
+ }
4744
+ ctx.stroke();
4745
+
4746
+ // Draw gradient + hessian curve
4747
+ ctx.strokeStyle = '#7ef0d4';
4748
+ ctx.lineWidth = 3;
4749
+ ctx.beginPath();
4750
+ for (let x = 0; x <= 10; x += 0.2) {
4751
+ const y = 200 - 120 * Math.exp(-Math.pow(x - 5, 2) / 5);
4752
+ if (x === 0) ctx.moveTo(padding + x * chartWidth / 10, y);
4753
+ else ctx.lineTo(padding + x * chartWidth / 10, y);
4754
+ }
4755
+ ctx.stroke();
4756
+
4757
+ // Optimum point
4758
+ ctx.fillStyle = '#7ef0d4';
4759
+ ctx.beginPath();
4760
+ ctx.arc(padding + 5 * chartWidth / 10, 80, 8, 0, 2 * Math.PI);
4761
+ ctx.fill();
4762
+
4763
+ // Legend
4764
+ ctx.fillStyle = '#ff8c6a';
4765
+ ctx.fillRect(padding + 10, height - 80, 20, 3);
4766
+ ctx.fillStyle = '#e8eef6';
4767
+ ctx.font = '12px sans-serif';
4768
+ ctx.textAlign = 'left';
4769
+ ctx.fillText('1st order only (slower)', padding + 40, height - 75);
4770
+
4771
+ ctx.fillStyle = '#7ef0d4';
4772
+ ctx.fillRect(padding + 10, height - 55, 20, 3);
4773
+ ctx.fillStyle = '#e8eef6';
4774
+ ctx.fillText('1st + 2nd order (faster)', padding + 40, height - 50);
4775
+
4776
+ logViz('XGBoost', 'Hessian Contribution', 'success');
4777
+ }
4778
+
4779
+ function drawXGBLeafWeights() {
4780
+ const canvas = document.getElementById('xgb-leaf-weights-canvas');
4781
+ if (!canvas) return;
4782
+
4783
+ const ctx = canvas.getContext('2d');
4784
+ const width = canvas.width = canvas.offsetWidth;
4785
+ const height = canvas.height = 350;
4786
+
4787
+ ctx.clearRect(0, 0, width, height);
4788
+ ctx.fillStyle = '#1a2332';
4789
+ ctx.fillRect(0, 0, width, height);
4790
+
4791
+ const padding = 40;
4792
+ const boxWidth = 300;
4793
+ const boxHeight = 120;
4794
+
4795
+ // Left leaf
4796
+ const leftX = width / 4 - boxWidth / 2;
4797
+ ctx.fillStyle = '#7ef0d4' + '22';
4798
+ ctx.fillRect(leftX, 80, boxWidth, boxHeight);
4799
+ ctx.strokeStyle = '#7ef0d4';
4800
+ ctx.lineWidth = 3;
4801
+ ctx.strokeRect(leftX, 80, boxWidth, boxHeight);
4802
+
4803
+ ctx.fillStyle = '#e8eef6';
4804
+ ctx.font = 'bold 14px sans-serif';
4805
+ ctx.textAlign = 'left';
4806
+ ctx.fillText('Left Leaf (Size ≀ 950):', leftX + 10, 105);
4807
+ ctx.font = '12px monospace';
4808
+ ctx.fillText('w = -G / (H + Ξ»)', leftX + 10, 130);
4809
+ ctx.fillText(' = -(-58) / (2 + 1)', leftX + 10, 150);
4810
+ ctx.fillText(' = 58 / 3', leftX + 10, 170);
4811
+ ctx.font = 'bold 16px monospace';
4812
+ ctx.fillStyle = '#7ef0d4';
4813
+ ctx.fillText(' = 19.33', leftX + 10, 190);
4814
+
4815
+ // Right leaf
4816
+ const rightX = 3 * width / 4 - boxWidth / 2;
4817
+ ctx.fillStyle = '#ff8c6a' + '22';
4818
+ ctx.fillRect(rightX, 80, boxWidth, boxHeight);
4819
+ ctx.strokeStyle = '#ff8c6a';
4820
+ ctx.lineWidth = 3;
4821
+ ctx.strokeRect(rightX, 80, boxWidth, boxHeight);
4822
+
4823
+ ctx.fillStyle = '#e8eef6';
4824
+ ctx.font = 'bold 14px sans-serif';
4825
+ ctx.textAlign = 'left';
4826
+ ctx.fillText('Right Leaf (Size &gt; 950):', rightX + 10, 105);
4827
+ ctx.font = '12px monospace';
4828
+ ctx.fillText('w = -G / (H + Ξ»)', rightX + 10, 130);
4829
+ ctx.fillText(' = -(58) / (3 + 1)', rightX + 10, 150);
4830
+ ctx.fillText(' = -58 / 4', rightX + 10, 170);
4831
+ ctx.font = 'bold 16px monospace';
4832
+ ctx.fillStyle = '#ff8c6a';
4833
+ ctx.fillText(' = -14.5', rightX + 10, 190);
4834
+
4835
+ // Title
4836
+ ctx.fillStyle = '#7ef0d4';
4837
+ ctx.font = 'bold 16px sans-serif';
4838
+ ctx.textAlign = 'center';
4839
+ ctx.fillText('Leaf Weight Calculation (Ξ» = 1)', width / 2, 40);
4840
+
4841
+ // Formula reminder
4842
+ ctx.fillStyle = '#a9b4c2';
4843
+ ctx.font = '13px sans-serif';
4844
+ ctx.fillText('Negative gradient divided by (Hessian + regularization)', width / 2, height - 20);
4845
+
4846
+ logViz('XGBoost', 'Leaf Weight Calculation', 'success');
4847
+ }
4848
+
4849
+ function drawXGBComparison() {
4850
+ const canvas = document.getElementById('xgb-comparison-canvas');
4851
+ if (!canvas) return;
4852
+
4853
+ createVerifiedVisualization('xgb-comparison-canvas', {
4854
+ type: 'radar',
4855
+ data: {
4856
+ labels: ['Accuracy', 'Speed', 'Robustness', 'Ease of Use', 'Scalability', 'Interpretability'],
4857
+ datasets: [
4858
+ {
4859
+ label: 'Gradient Boosting',
4860
+ data: [4.5, 3, 3.5, 4, 3, 3],
4861
+ borderColor: '#ff8c6a',
4862
+ backgroundColor: 'rgba(255, 140, 106, 0.2)',
4863
+ borderWidth: 2
4864
+ },
4865
+ {
4866
+ label: 'XGBoost',
4867
+ data: [5, 4.5, 5, 4, 5, 3],
4868
+ borderColor: '#7ef0d4',
4869
+ backgroundColor: 'rgba(126, 240, 212, 0.2)',
4870
+ borderWidth: 2
4871
+ }
4872
+ ]
4873
+ },
4874
+ options: {
4875
+ responsive: true,
4876
+ maintainAspectRatio: false,
4877
+ plugins: {
4878
+ title: {
4879
+ display: true,
4880
+ text: 'Gradient Boosting vs XGBoost: Comprehensive Comparison',
4881
+ color: '#e8eef6',
4882
+ font: { size: 16 }
4883
+ },
4884
+ legend: {
4885
+ position: 'top',
4886
+ labels: { color: '#a9b4c2', padding: 15 }
4887
+ }
4888
+ },
4889
+ scales: {
4890
+ r: {
4891
+ beginAtZero: true,
4892
+ max: 5,
4893
+ ticks: { color: '#a9b4c2', backdropColor: 'transparent' },
4894
+ grid: { color: '#2a3544' },
4895
+ pointLabels: { color: '#e8eef6', font: { size: 12 } }
4896
+ }
4897
+ }
4898
+ }
4899
+ }, 'XGBoost', 'GB vs XGB Comparison');
4900
+ }
4901
+
4902
+ function initBagging() {
4903
+ const canvas = document.getElementById('bagging-complete-canvas');
4904
+ if (canvas && !canvas.dataset.initialized) {
4905
+ canvas.dataset.initialized = 'true';
4906
+ drawBaggingCompleteViz();
4907
+ }
4908
+ }
4909
+
4910
+ function initBoostingAdaBoost() {
4911
+ const canvas = document.getElementById('boosting-complete-canvas');
4912
+ if (canvas && !canvas.dataset.initialized) {
4913
+ canvas.dataset.initialized = 'true';
4914
+ drawBoostingCompleteViz();
4915
+ }
4916
+ }
4917
+
4918
+ function initRandomForest() {
4919
+ const canvas = document.getElementById('rf-complete-canvas');
4920
+ if (canvas && !canvas.dataset.initialized) {
4921
+ canvas.dataset.initialized = 'true';
4922
+ drawRandomForestCompleteViz();
4923
+ }
4924
+ }
4925
+
4926
+ // Topic 17: Ensemble Methods
4927
+ function initEnsembleMethods() {
4928
+ const canvasNew1 = document.getElementById('bagging-complete-canvas');
4929
+ if (canvasNew1 && !canvasNew1.dataset.initialized) {
4930
+ canvasNew1.dataset.initialized = 'true';
4931
+ drawBaggingCompleteViz();
4932
+ }
4933
+
4934
+ const canvasNew2 = document.getElementById('boosting-complete-canvas');
4935
+ if (canvasNew2 && !canvasNew2.dataset.initialized) {
4936
+ canvasNew2.dataset.initialized = 'true';
4937
+ drawBoostingCompleteViz();
4938
+ }
4939
+
4940
+ const canvasNew3 = document.getElementById('rf-complete-canvas');
4941
+ if (canvasNew3 && !canvasNew3.dataset.initialized) {
4942
+ canvasNew3.dataset.initialized = 'true';
4943
+ drawRandomForestCompleteViz();
4944
+ }
4945
+
4946
+ const canvas1 = document.getElementById('bagging-viz');
4947
+ if (canvas1 && !canvas1.dataset.initialized) {
4948
+ canvas1.dataset.initialized = 'true';
4949
+ drawBaggingViz();
4950
+ }
4951
+
4952
+ const canvas2 = document.getElementById('boosting-viz');
4953
+ if (canvas2 && !canvas2.dataset.initialized) {
4954
+ canvas2.dataset.initialized = 'true';
4955
+ drawBoostingViz();
4956
+ }
4957
+
4958
+ const canvas3 = document.getElementById('random-forest-viz');
4959
+ if (canvas3 && !canvas3.dataset.initialized) {
4960
+ canvas3.dataset.initialized = 'true';
4961
+ drawRandomForestViz();
4962
+ }
4963
+ }
4964
+
4965
+ function drawBaggingCompleteViz() {
4966
+ const canvas = document.getElementById('bagging-complete-canvas');
4967
+ if (!canvas) {
4968
+ logViz('Ensemble Methods', 'Bagging Complete', 'failed', 'Canvas not found');
4969
+ return;
4970
+ }
4971
+
4972
+ const ctx = canvas.getContext('2d');
4973
+ const width = canvas.width = canvas.offsetWidth;
4974
+ const height = canvas.height = 400;
4975
+
4976
+ ctx.clearRect(0, 0, width, height);
4977
+ ctx.fillStyle = '#1a2332';
4978
+ ctx.fillRect(0, 0, width, height);
4979
+
4980
+ const treeY = 100;
4981
+ const predY = 280;
4982
+ const finalY = 350;
4983
+
4984
+ // Three trees
4985
+ for (let i = 0; i < 3; i++) {
4986
+ const x = 150 + i * 250;
4987
+ const preds = [75, 72, 78];
4988
+
4989
+ // Tree box
4990
+ ctx.fillStyle = '#7ef0d433';
4991
+ ctx.fillRect(x - 50, treeY, 100, 60);
4992
+ ctx.strokeStyle = '#7ef0d4';
4993
+ ctx.lineWidth = 2;
4994
+ ctx.strokeRect(x - 50, treeY, 100, 60);
4995
+
4996
+ ctx.fillStyle = '#e8eef6';
4997
+ ctx.font = 'bold 14px sans-serif';
4998
+ ctx.textAlign = 'center';
4999
+ ctx.fillText(`Tree ${i + 1}`, x, treeY + 35);
5000
+
5001
+ // Prediction
5002
+ ctx.fillStyle = '#6aa9ff33';
5003
+ ctx.fillRect(x - 40, predY, 80, 50);
5004
+ ctx.strokeStyle = '#6aa9ff';
5005
+ ctx.strokeRect(x - 40, predY, 80, 50);
5006
+
5007
+ ctx.fillStyle = '#e8eef6';
5008
+ ctx.font = 'bold 16px sans-serif';
5009
+ ctx.fillText(`β‚Ή${preds[i]}L`, x, predY + 32);
5010
+
5011
+ // Arrow to final
5012
+ ctx.strokeStyle = '#7ef0d4';
5013
+ ctx.lineWidth = 2;
5014
+ ctx.beginPath();
5015
+ ctx.moveTo(x, predY + 50);
5016
+ ctx.lineTo(width / 2, finalY - 10);
5017
+ ctx.stroke();
5018
+ }
5019
+
5020
+ // Final average
5021
+ ctx.fillStyle = '#ff8c6a33';
5022
+ ctx.fillRect(width / 2 - 80, finalY, 160, 50);
5023
+ ctx.strokeStyle = '#ff8c6a';
5024
+ ctx.lineWidth = 3;
5025
+ ctx.strokeRect(width / 2 - 80, finalY, 160, 50);
5026
+
5027
+ ctx.fillStyle = '#e8eef6';
5028
+ ctx.font = 'bold 18px sans-serif';
5029
+ ctx.textAlign = 'center';
5030
+ ctx.fillText('Avg = β‚Ή75L βœ“', width / 2, finalY + 32);
5031
+
5032
+ // Title
5033
+ ctx.fillStyle = '#7ef0d4';
5034
+ ctx.font = 'bold 16px sans-serif';
5035
+ ctx.fillText('Bagging: Average of 3 Trees', width / 2, 30);
5036
+
5037
+ logViz('Ensemble Methods', 'Bagging Complete', 'success');
5038
+ }
5039
+
5040
+ function drawBoostingCompleteViz() {
5041
+ const canvas = document.getElementById('boosting-complete-canvas');
5042
+ if (!canvas) {
5043
+ logViz('Ensemble Methods', 'Boosting Complete', 'failed', 'Canvas not found');
5044
+ return;
5045
+ }
5046
+
5047
+ const ctx = canvas.getContext('2d');
5048
+ const width = canvas.width = canvas.offsetWidth;
5049
+ const height = canvas.height = 450;
5050
+
5051
+ ctx.clearRect(0, 0, width, height);
5052
+ ctx.fillStyle = '#1a2332';
5053
+ ctx.fillRect(0, 0, width, height);
5054
+
5055
+ const rounds = [
5056
+ {label: 'Round 1', weights: [1, 1, 1, 1, 1, 1], errors: [20, 20, 21, 2, 3, 2]},
5057
+ {label: 'Round 2', weights: [1, 1, 1, 2.5, 3, 2.5], errors: [21, 21, 20, 0, 1, 0]},
5058
+ {label: 'Round 3', weights: [2, 2, 2, 1, 1, 1], errors: [20, 20, 21, 1, 2, 1]}
5059
+ ];
5060
+
5061
+ const startX = 60;
5062
+ const barWidth = 30;
5063
+ const gap = 10;
5064
+
5065
+ rounds.forEach((round, r) => {
5066
+ const y = 80 + r * 120;
5067
+
5068
+ ctx.fillStyle = '#7ef0d4';
5069
+ ctx.font = 'bold 14px sans-serif';
5070
+ ctx.textAlign = 'left';
5071
+ ctx.fillText(round.label, 10, y + 20);
5072
+
5073
+ // Weight bars
5074
+ round.weights.forEach((w, i) => {
5075
+ const x = startX + i * (barWidth + gap);
5076
+ const h = w * 20;
5077
+
5078
+ ctx.fillStyle = w > 1.5 ? '#ff8c6a' : '#6aa9ff';
5079
+ ctx.fillRect(x, y + 40 - h, barWidth, h);
5080
+
5081
+ // Error text
5082
+ ctx.fillStyle = '#a9b4c2';
5083
+ ctx.font = '9px sans-serif';
5084
+ ctx.textAlign = 'center';
5085
+ ctx.fillText(`e=${round.errors[i]}`, x + barWidth / 2, y + 55);
5086
+ });
5087
+ });
5088
+
5089
+ ctx.fillStyle = '#7ef0d4';
5090
+ ctx.font = 'bold 16px sans-serif';
5091
+ ctx.textAlign = 'center';
5092
+ ctx.fillText('Boosting: Sequential Weight Updates', width / 2, 30);
5093
+ ctx.fillText('Final: α₁×M₁ + Ξ±β‚‚Γ—Mβ‚‚ + α₃×M₃ = β‚Ή74.7L', width / 2, height - 20);
5094
+ }
5095
+
5096
+ function drawRandomForestCompleteViz() {
5097
+ const canvas = document.getElementById('rf-complete-canvas');
5098
+ if (!canvas) {
5099
+ logViz('Ensemble Methods', 'Random Forest Complete', 'failed', 'Canvas not found');
5100
+ return;
5101
+ }
5102
+
5103
+ const ctx = canvas.getContext('2d');
5104
+ const width = canvas.width = canvas.offsetWidth;
5105
+ const height = canvas.height = 500;
5106
+
5107
+ ctx.clearRect(0, 0, width, height);
5108
+ ctx.fillStyle = '#1a2332';
5109
+ ctx.fillRect(0, 0, width, height);
5110
+
5111
+ // Show 3 trees with feature randomness
5112
+ const trees = [
5113
+ {features: ['Sq Ft', 'Age'], pred: 74},
5114
+ {features: ['Sq Ft', 'Beds'], pred: 76},
5115
+ {features: ['Beds', 'Age'], pred: 75}
5116
+ ];
5117
+
5118
+ trees.forEach((tree, i) => {
5119
+ const x = 120 + i * 260;
5120
+ const y = 100;
5121
+
5122
+ // Bootstrap
5123
+ ctx.fillStyle = '#6aa9ff33';
5124
+ ctx.fillRect(x - 60, y, 120, 50);
5125
+ ctx.strokeStyle = '#6aa9ff';
5126
+ ctx.lineWidth = 2;
5127
+ ctx.strokeRect(x - 60, y, 120, 50);
5128
+ ctx.fillStyle = '#e8eef6';
5129
+ ctx.font = '12px sans-serif';
5130
+ ctx.textAlign = 'center';
5131
+ ctx.fillText('Bootstrap', x, y + 25);
5132
+ ctx.fillText(`Sample ${i + 1}`, x, y + 40);
5133
+
5134
+ // Tree with random features
5135
+ ctx.fillStyle = '#7ef0d433';
5136
+ ctx.fillRect(x - 60, y + 80, 120, 70);
5137
+ ctx.strokeStyle = '#7ef0d4';
5138
+ ctx.strokeRect(x - 60, y + 80, 120, 70);
5139
+ ctx.fillStyle = '#e8eef6';
5140
+ ctx.font = 'bold 13px sans-serif';
5141
+ ctx.fillText(`Tree ${i + 1}`, x, y + 105);
5142
+ ctx.font = '10px sans-serif';
5143
+ ctx.fillStyle = '#ffb490';
5144
+ ctx.fillText('Random:', x, y + 123);
5145
+ ctx.fillText(tree.features.join(', '), x, y + 138);
5146
+
5147
+ // Prediction
5148
+ ctx.fillStyle = '#ff8c6a33';
5149
+ ctx.fillRect(x - 50, y + 180, 100, 50);
5150
+ ctx.strokeStyle = '#ff8c6a';
5151
+ ctx.strokeRect(x - 50, y + 180, 100, 50);
5152
+ ctx.fillStyle = '#e8eef6';
5153
+ ctx.font = 'bold 16px sans-serif';
5154
+ ctx.fillText(`β‚Ή${tree.pred}L`, x, y + 210);
5155
+
5156
+ // Arrow to final
5157
+ ctx.strokeStyle = '#7ef0d4';
5158
+ ctx.lineWidth = 2;
5159
+ ctx.beginPath();
5160
+ ctx.moveTo(x, y + 230);
5161
+ ctx.lineTo(width / 2, y + 300);
5162
+ ctx.stroke();
5163
+ });
5164
+
5165
+ // Final average
5166
+ ctx.fillStyle = '#7ef0d433';
5167
+ ctx.fillRect(width / 2 - 100, 400, 200, 70);
5168
+ ctx.strokeStyle = '#7ef0d4';
5169
+ ctx.lineWidth = 3;
5170
+ ctx.strokeRect(width / 2 - 100, 400, 200, 70);
5171
+ ctx.fillStyle = '#e8eef6';
5172
+ ctx.font = 'bold 18px sans-serif';
5173
+ ctx.textAlign = 'center';
5174
+ ctx.fillText('Average of 100 Trees', width / 2, 425);
5175
+ ctx.fillText('= β‚Ή75.2L Β± β‚Ή2.3L βœ“', width / 2, 450);
5176
+
5177
+ // Title
5178
+ ctx.fillStyle = '#7ef0d4';
5179
+ ctx.font = 'bold 16px sans-serif';
5180
+ ctx.fillText('Random Forest: Bootstrap + Feature Randomness', width / 2, 30);
5181
+
5182
+ logViz('Ensemble Methods', 'Random Forest Complete', 'success');
5183
+ }
5184
+
5185
+ function drawBaggingViz() {
5186
+ const canvas = document.getElementById('bagging-viz');
5187
+ if (!canvas) {
5188
+ logViz('Ensemble Methods', 'Bagging Viz', 'failed', 'Canvas not found');
5189
+ return;
5190
+ }
5191
+
5192
+ const ctx = canvas.getContext('2d');
5193
+ const width = canvas.width = canvas.offsetWidth;
5194
+ const height = canvas.height = 400;
5195
+
5196
+ ctx.clearRect(0, 0, width, height);
5197
+ ctx.fillStyle = '#1a2332';
5198
+ ctx.fillRect(0, 0, width, height);
5199
+
5200
+ const boxWidth = 150;
5201
+ const boxHeight = 60;
5202
+ const startY = 60;
5203
+ const spacing = (width - 3 * boxWidth) / 4;
5204
+
5205
+ // Original data
5206
+ ctx.fillStyle = '#6aa9ff33';
5207
+ ctx.fillRect(width / 2 - 100, startY, 200, boxHeight);
5208
+ ctx.strokeStyle = '#6aa9ff';
5209
+ ctx.lineWidth = 2;
5210
+ ctx.strokeRect(width / 2 - 100, startY, 200, boxHeight);
5211
+ ctx.fillStyle = '#e8eef6';
5212
+ ctx.font = 'bold 14px sans-serif';
5213
+ ctx.textAlign = 'center';
5214
+ ctx.fillText('Original Dataset', width / 2, startY + boxHeight / 2 + 5);
5215
+
5216
+ // Bootstrap samples
5217
+ const sampleY = startY + boxHeight + 60;
5218
+ for (let i = 0; i < 3; i++) {
5219
+ const x = spacing + i * (boxWidth + spacing);
5220
+
5221
+ // Arrow
5222
+ ctx.strokeStyle = '#7ef0d4';
5223
+ ctx.lineWidth = 2;
5224
+ ctx.beginPath();
5225
+ ctx.moveTo(width / 2, startY + boxHeight);
5226
+ ctx.lineTo(x + boxWidth / 2, sampleY);
5227
+ ctx.stroke();
5228
+
5229
+ // Sample box
5230
+ ctx.fillStyle = '#7ef0d433';
5231
+ ctx.fillRect(x, sampleY, boxWidth, boxHeight);
5232
+ ctx.strokeStyle = '#7ef0d4';
5233
+ ctx.strokeRect(x, sampleY, boxWidth, boxHeight);
5234
+
5235
+ ctx.fillStyle = '#e8eef6';
5236
+ ctx.font = 'bold 12px sans-serif';
5237
+ ctx.fillText(`Bootstrap ${i + 1}`, x + boxWidth / 2, sampleY + boxHeight / 2 - 5);
5238
+ ctx.font = '10px sans-serif';
5239
  ctx.fillStyle = '#a9b4c2';
5240
  ctx.fillText('(random sample)', x + boxWidth / 2, sampleY + boxHeight / 2 + 10);
5241
 
 
5386
  ctx.fillStyle = '#ff8c6a';
5387
  ctx.font = 'bold 14px sans-serif';
5388
  ctx.fillText('Final Prediction = Weighted Combination of All Models', width / 2, height - 20);
5389
+
5390
+ logViz('Ensemble Methods', 'Boosting Complete', 'success');
5391
+ }
5392
+
5393
+ function drawGBLearningRate() {
5394
+ // Implementation moved to Gradient Boosting section
5395
+ }
5396
+
5397
+ function drawGBStumps() {
5398
+ // Implementation moved to Gradient Boosting section
5399
+ }
5400
+
5401
+ function drawGBPredictions() {
5402
+ // Implementation moved to Gradient Boosting section
5403
+ }
5404
+
5405
+ function drawXGBGain() {
5406
+ // Implementation moved to XGBoost section
5407
+ }
5408
+
5409
+ function drawXGBRegularization() {
5410
+ // Implementation moved to XGBoost section
5411
+ }
5412
+
5413
+ function drawXGBHessian() {
5414
+ // Implementation moved to XGBoost section
5415
+ }
5416
+
5417
+ function drawXGBLeafWeights() {
5418
+ // Implementation moved to XGBoost section
5419
+ }
5420
+
5421
+ function drawXGBComparison() {
5422
+ // Implementation moved to XGBoost section
5423
  }
5424
 
5425
  function drawRandomForestViz() {
 
5528
  ctx.fillStyle = '#7ef0d4';
5529
  ctx.font = 'bold 16px sans-serif';
5530
  ctx.fillText('Random Forest: Ensemble of Decision Trees', width / 2, 25);
5531
+
5532
+ logViz('Ensemble Methods', 'Bagging Viz', 'success');
5533
  }
5534
 
5535
  // Topic 16: K-means Clustering
 
5552
 
5553
  function drawKMeansVisualization() {
5554
  const canvas = document.getElementById('kmeans-viz-canvas');
5555
+ if (!canvas) {
5556
+ logViz('K-means', 'Scatter + Centroids', 'failed', 'Canvas not found');
5557
+ return;
5558
+ }
5559
 
5560
  const ctx = canvas.getContext('2d');
5561
  const width = canvas.width = canvas.offsetWidth;
 
5675
  ctx.font = '14px sans-serif';
5676
  ctx.textAlign = 'left';
5677
  ctx.fillText('WCSS = 15.984', padding, height - padding + 30);
5678
+
5679
+ logViz('K-means', 'Scatter + Centroids', 'success');
5680
  }
5681
 
5682
  function drawKMeansElbow() {
 
5692
  const kValues = [1, 2, 3, 4, 5];
5693
  const wcssValues = [50, 18, 10, 8, 7];
5694
 
5695
+ kmeansElbowChart = createVerifiedVisualization('kmeans-elbow-canvas', {
5696
  type: 'line',
5697
  data: {
5698
  labels: kValues,
 
5755
  }
5756
  }
5757
  }
5758
+ }, 'K-means', 'Elbow Method');
5759
  }
5760
 
5761
  // Topic 18: Algorithm Comparison
 
5991
 
5992
  html += '</tbody>';
5993
  table.innerHTML = html;
5994
+
5995
+ logViz('Algorithm Comparison', 'Comparison Table', 'success');
5996
  }
5997
 
5998
  let radarComparisonChart = null;
 
6024
  };
6025
  });
6026
 
6027
+ if (radarComparisonChart) {
6028
+ radarComparisonChart.destroy();
6029
+ radarComparisonChart = null;
6030
+ }
6031
+
6032
+ radarComparisonChart = createVerifiedVisualization('radar-comparison-canvas', {
6033
  type: 'radar',
6034
  data: {
6035
  labels: ['Speed', 'Accuracy', 'Data Efficiency', 'Interpretability', 'Scalability'],
 
6054
  }
6055
  }
6056
  }
6057
+ }, 'Algorithm Comparison', 'Radar Chart');
6058
  }
6059
 
6060
  function renderHeatmap() {
 
6110
  html += '</table>';
6111
  html += '</div>';
6112
 
6113
+ logViz('Algorithm Comparison', 'Heatmap', 'success');
6114
+
6115
  // Legend
6116
  html += '<div style="text-align: center; margin-top: 24px; padding: 16px; background: var(--color-bg-2); border-radius: 8px;">';
6117
  html += '<strong style="color: #e8eef6;">Legend:</strong> ';
 
6160
 
6161
  html += '</tbody>';
6162
  table.innerHTML = html;
6163
+
6164
+ logViz('Algorithm Comparison', 'Use Case Matrix', 'success');
6165
  }
6166
 
6167
  function renderDetailedCards() {
 
6201
 
6202
  html += '</div>';
6203
  container.innerHTML = html;
6204
+
6205
+ logViz('Algorithm Comparison', 'Detailed Cards', 'success');
6206
  }
6207
 
6208
  function initQuiz() {
 
6366
  ctx.fillText('Algorithm Selection Flowchart', width/2, 25);
6367
  }
6368
 
6369
+ // Diagnostic Functions
6370
+ function showDiagnostics() {
6371
+ const browserDetails = document.getElementById('browser-details');
6372
+ if (browserDetails) {
6373
+ browserDetails.innerHTML = `
6374
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Browser: ${navigator.userAgent.split(' ').slice(-2).join(' ')}</li>
6375
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Platform: ${navigator.platform}</li>
6376
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Language: ${navigator.language}</li>
6377
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Online: ${navigator.onLine ? 'βœ“ Yes' : 'βœ— No'}</li>
6378
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Cookies Enabled: ${navigator.cookieEnabled ? 'βœ“ Yes' : 'βœ— No'}</li>
6379
+ `;
6380
+ }
6381
+
6382
+ const libraryDetails = document.getElementById('library-details');
6383
+ if (libraryDetails) {
6384
+ const chartJsLoaded = typeof Chart !== 'undefined';
6385
+ const canvasSupport = !!document.createElement('canvas').getContext('2d');
6386
+
6387
+ libraryDetails.innerHTML = `
6388
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Chart.js: ${chartJsLoaded ? 'βœ“ Loaded (v' + (Chart.version || '4.x') + ')' : 'βœ— Missing'}</li>
6389
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Canvas Support: ${canvasSupport ? 'βœ“ Yes' : 'βœ— No'}</li>
6390
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Device Pixel Ratio: ${window.devicePixelRatio || 1}</li>
6391
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Screen Resolution: ${window.screen.width}x${window.screen.height}</li>
6392
+ `;
6393
+ }
6394
+
6395
+ const successCount = document.getElementById('diag-success-count');
6396
+ const failedCount = document.getElementById('diag-failed-count');
6397
+ const warningCount = document.getElementById('diag-warning-count');
6398
+
6399
+ if (successCount) successCount.textContent = vizLog.success.length;
6400
+ if (failedCount) failedCount.textContent = vizLog.failed.length;
6401
+ if (warningCount) warningCount.textContent = vizLog.warnings.length;
6402
+ }
6403
+
6404
+ function showDiagnosticDetails(filter) {
6405
+ const container = document.getElementById('viz-details');
6406
+ if (!container) return;
6407
+
6408
+ let items = [];
6409
+ if (filter === 'success') items = vizLog.success;
6410
+ else if (filter === 'failed') items = vizLog.failed;
6411
+ else items = [...vizLog.success, ...vizLog.failed, ...vizLog.warnings];
6412
+
6413
+ if (items.length === 0) {
6414
+ container.innerHTML = '<p style="color: var(--color-text-secondary); text-align: center; padding: 20px;">No items to display</p>';
6415
+ return;
6416
+ }
6417
+
6418
+ let html = '<table class="data-table" style="font-size: 12px;">';
6419
+ html += '<thead><tr><th>Module</th><th>Visualization</th><th>Status</th><th>Time</th></tr></thead>';
6420
+ html += '<tbody>';
6421
+
6422
+ items.forEach(item => {
6423
+ const statusIcon = item.status === 'success' ? 'βœ“' : (item.status === 'failed' ? 'βœ—' : '⚠');
6424
+ const statusColor = item.status === 'success' ? 'var(--color-success)' : (item.status === 'failed' ? 'var(--color-error)' : 'var(--color-warning)');
6425
+
6426
+ html += `<tr>`;
6427
+ html += `<td>${item.module}</td>`;
6428
+ html += `<td>${item.name}</td>`;
6429
+ html += `<td style="color: ${statusColor}; font-weight: bold;">${statusIcon} ${item.status.toUpperCase()}</td>`;
6430
+ html += `<td>${item.timestamp}</td>`;
6431
+ html += `</tr>`;
6432
+ });
6433
+
6434
+ html += '</tbody></table>';
6435
+ container.innerHTML = html;
6436
+ }
6437
+
6438
  // Handle window resize
6439
  let resizeTimer;
6440
  window.addEventListener('resize', () => {
 
6482
  if (document.getElementById('decision-flowchart')) drawDecisionFlowchart();
6483
  }, 250);
6484
  });
6485
+
6486
+ // Add global function for diagnostic details (needed by onclick)
6487
+ window.showDiagnosticDetails = showDiagnosticDetails;
ml_complete-all-topics/index.html CHANGED
@@ -529,8 +529,14 @@ canvas {
529
  <a href="#svm" class="toc-link toc-sub">Support Vector Machines</a>
530
  <a href="#knn" class="toc-link toc-sub">K-Nearest Neighbors</a>
531
  <a href="#naive-bayes" class="toc-link toc-sub">Naive Bayes</a>
532
- <a href="#decision-trees" class="toc-link toc-sub">Decision Trees</a>
533
- <a href="#ensemble-methods" class="toc-link toc-sub">Ensemble Methods</a>
 
 
 
 
 
 
534
  </div>
535
  <div class="toc-subcategory">
536
  <div class="toc-subcategory-title">Evaluation &amp; Tuning</div>
@@ -577,6 +583,7 @@ canvas {
577
  </div>
578
 
579
  <a href="#algorithm-comparison" class="toc-link">πŸ“Š Algorithm Comparison</a>
 
580
  </nav>
581
  </aside>
582
 
@@ -3242,6 +3249,192 @@ Actual Pos TP FN
3242
  </div>
3243
  </div>
3244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3245
  <!-- Section 17: Decision Trees -->
3246
  <div class="section" id="decision-trees">
3247
  <div class="section-header">
@@ -3893,7 +4086,506 @@ Actual Pos TP FN
3893
  </div>
3894
  </div>
3895
 
3896
- <!-- Section 19: Ensemble Methods -->
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3897
  <div class="section" id="ensemble-methods">
3898
  <div class="section-header">
3899
  <h2><span class="badge" style="background: rgba(106, 169, 255, 0.3); color: #6aa9ff;">πŸ“Š Supervised</span> Ensemble Methods</h2>
@@ -3930,9 +4622,99 @@ Actual Pos TP FN
3930
  </div>
3931
  </div>
3932
 
3933
- <h3>Method 1: Bagging (Bootstrap Aggregating)</h3>
3934
  <p>Train multiple models on different random subsets of data (with replacement), then average predictions.</p>
3935
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3936
  <div class="formula">
3937
  <strong>Bagging Algorithm:</strong><br>
3938
  1. Create B bootstrap samples (random sampling with replacement)<br>
@@ -3951,9 +4733,102 @@ Actual Pos TP FN
3951
  <p class="figure-caption"><strong>Figure 1:</strong> Bagging process - multiple models from bootstrap samples</p>
3952
  </div>
3953
 
3954
- <h3>Method 2: Boosting (Sequential Learning)</h3>
3955
  <p>Train models sequentially, where each new model focuses on examples the previous models got wrong.</p>
3956
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3957
  <div class="formula">
3958
  <strong>Boosting Algorithm:</strong><br>
3959
  1. Start with equal weights for all samples<br>
@@ -3973,9 +4848,149 @@ Actual Pos TP FN
3973
  <p class="figure-caption"><strong>Figure 2:</strong> Boosting iteration - focusing on misclassified points</p>
3974
  </div>
3975
 
3976
- <h3>Random Forest: Bagging + Decision Trees</h3>
3977
  <p>The most popular ensemble method! Combines bagging with feature randomness.</p>
3978
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3979
  <div class="formula">
3980
  <strong>Random Forest Algorithm:</strong><br>
3981
  1. Create B bootstrap samples<br>
@@ -4054,6 +5069,72 @@ Actual Pos TP FN
4054
  </div>
4055
  </div>
4056
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4057
  </main>
4058
  </div>
4059
 
 
529
  <a href="#svm" class="toc-link toc-sub">Support Vector Machines</a>
530
  <a href="#knn" class="toc-link toc-sub">K-Nearest Neighbors</a>
531
  <a href="#naive-bayes" class="toc-link toc-sub">Naive Bayes</a>
532
+ <a href="#decision-tree-regression" class="toc-link toc-sub">Decision Tree Regression</a>
533
+ <a href="#decision-trees" class="toc-link toc-sub">Decision Trees (Classification)</a>
534
+ <a href="#bagging" class="toc-link toc-sub">Bagging</a>
535
+ <a href="#boosting-adaboost" class="toc-link toc-sub">Boosting (AdaBoost)</a>
536
+ <a href="#gradient-boosting" class="toc-link toc-sub">Gradient Boosting</a>
537
+ <a href="#xgboost" class="toc-link toc-sub">XGBoost</a>
538
+ <a href="#random-forest" class="toc-link toc-sub">Random Forest</a>
539
+ <a href="#ensemble-methods" class="toc-link toc-sub">Ensemble Methods Overview</a>
540
  </div>
541
  <div class="toc-subcategory">
542
  <div class="toc-subcategory-title">Evaluation &amp; Tuning</div>
 
583
  </div>
584
 
585
  <a href="#algorithm-comparison" class="toc-link">πŸ“Š Algorithm Comparison</a>
586
+ <a href="#diagnostics" class="toc-link">πŸ”§ Diagnostics</a>
587
  </nav>
588
  </aside>
589
 
 
3249
  </div>
3250
  </div>
3251
 
3252
+ <!-- Section 17: Decision Tree Regression (FROM PDF) -->
3253
+ <div class="section" id="decision-tree-regression">
3254
+ <div class="section-header">
3255
+ <h2><span class="badge" style="background: rgba(106, 169, 255, 0.3); color: #6aa9ff;">πŸ“Š Supervised - Regression</span> Decision Tree Regression</h2>
3256
+ <button class="section-toggle">β–Ό</button>
3257
+ </div>
3258
+ <div class="section-body">
3259
+ <p>Decision Tree Regression predicts continuous values by recursively splitting data to minimize variance. Unlike classification trees that use entropy, regression trees use variance reduction!</p>
3260
+
3261
+ <div class="info-card">
3262
+ <div class="info-card-title">Key Concepts</div>
3263
+ <ul class="info-card-list">
3264
+ <li>Splits based on variance reduction (not entropy)</li>
3265
+ <li>Leaf nodes predict mean of samples</li>
3266
+ <li>Test all split points to find best</li>
3267
+ <li>Recursive partitioning until stopping criteria</li>
3268
+ </ul>
3269
+ </div>
3270
+
3271
+ <h3>🎯 Complete Mathematical Solution (From PDF)</h3>
3272
+
3273
+ <h4>Dataset: House Price Prediction</h4>
3274
+ <table class="data-table">
3275
+ <thead>
3276
+ <tr><th>ID</th><th>Square Feet</th><th>Price (Lakhs)</th></tr>
3277
+ </thead>
3278
+ <tbody>
3279
+ <tr><td>1</td><td>800</td><td>50</td></tr>
3280
+ <tr><td>2</td><td>850</td><td>52</td></tr>
3281
+ <tr><td>3</td><td>900</td><td>54</td></tr>
3282
+ <tr><td>4</td><td>1500</td><td>90</td></tr>
3283
+ <tr><td>5</td><td>1600</td><td>95</td></tr>
3284
+ <tr><td>6</td><td>1700</td><td>100</td></tr>
3285
+ </tbody>
3286
+ </table>
3287
+
3288
+ <div class="step">
3289
+ <div class="step-title">STEP 1: Calculate Parent Variance</div>
3290
+ <div class="step-calculation">
3291
+ Mean price = (50 + 52 + 54 + 90 + 95 + 100) / 6
3292
+ = 441 / 6
3293
+ = <strong style="color: #7ef0d4;">73.5 Lakhs</strong>
3294
+
3295
+ Variance = Ξ£(yα΅’ - mean)Β² / n
3296
+
3297
+ Calculating each term:
3298
+ β€’ (50 - 73.5)Β² = (-23.5)Β² = 552.25
3299
+ β€’ (52 - 73.5)Β² = (-21.5)Β² = 462.25
3300
+ β€’ (54 - 73.5)Β² = (-19.5)Β² = 380.25
3301
+ β€’ (90 - 73.5)Β² = (16.5)Β² = 272.25
3302
+ β€’ (95 - 73.5)Β² = (21.5)Β² = 462.25
3303
+ β€’ (100 - 73.5)Β² = (26.5)Β² = 702.25
3304
+
3305
+ Sum = 552.25 + 462.25 + 380.25 + 272.25 + 462.25 + 702.25
3306
+ = 2831.5
3307
+
3308
+ Variance = 2831.5 / 6 = <strong style="color: #7ef0d4;">471.92</strong>
3309
+
3310
+ <strong style="color: #6aa9ff;">βœ“ Parent Variance = 471.92</strong>
3311
+ </div>
3312
+ </div>
3313
+
3314
+ <div class="step">
3315
+ <div class="step-title">STEP 2: Test Split Points</div>
3316
+ <div class="step-calculation">
3317
+ Sort by Square Feet: 800, 850, 900, 1500, 1600, 1700
3318
+
3319
+ Possible midpoints: 825, 875, 1200, 1550, 1650
3320
+
3321
+ <strong style="color: #6aa9ff;">Testing Split at 1200:</strong>
3322
+
3323
+ <strong>LEFT (Square Feet &lt;= 1200):</strong>
3324
+ Samples: 800(50), 850(52), 900(54)
3325
+ Left Mean = (50 + 52 + 54) / 3 = 156 / 3 = <strong>52</strong>
3326
+
3327
+ Left Variance:
3328
+ β€’ (50 - 52)Β² = 4
3329
+ β€’ (52 - 52)Β² = 0
3330
+ β€’ (54 - 52)Β² = 4
3331
+ Sum = 8
3332
+ Variance = 8 / 3 = <strong>2.67</strong>
3333
+
3334
+ <strong>RIGHT (Square Feet &gt; 1200):</strong>
3335
+ Samples: 1500(90), 1600(95), 1700(100)
3336
+ Right Mean = (90 + 95 + 100) / 3 = 285 / 3 = <strong>95</strong>
3337
+
3338
+ Right Variance:
3339
+ β€’ (90 - 95)Β² = 25
3340
+ β€’ (95 - 95)Β² = 0
3341
+ β€’ (100 - 95)Β² = 25
3342
+ Sum = 50
3343
+ Variance = 50 / 3 = <strong>16.67</strong>
3344
+ </div>
3345
+ </div>
3346
+
3347
+ <div class="step">
3348
+ <div class="step-title">STEP 3: Calculate Weighted Variance After Split</div>
3349
+ <div class="step-calculation">
3350
+ Weighted Variance = (n_left/n_total) Γ— Var_left + (n_right/n_total) Γ— Var_right
3351
+
3352
+ = (3/6) Γ— 2.67 + (3/6) Γ— 16.67
3353
+ = 0.5 Γ— 2.67 + 0.5 Γ— 16.67
3354
+ = 1.335 + 8.335
3355
+ = <strong style="color: #6aa9ff;">9.67</strong>
3356
+ </div>
3357
+ </div>
3358
+
3359
+ <div class="step">
3360
+ <div class="step-title">STEP 4: Calculate Variance Reduction</div>
3361
+ <div class="step-calculation">
3362
+ Variance Reduction = Parent Variance - Weighted Variance After Split
3363
+
3364
+ = 471.92 - 9.67
3365
+ = <strong style="color: #7ef0d4; font-size: 18px;">462.25</strong>
3366
+
3367
+ <strong style="color: #7ef0d4;">βœ“ This is the BEST SPLIT!</strong>
3368
+ Splitting at 1200 sq ft reduces variance by 462.25
3369
+ </div>
3370
+ </div>
3371
+
3372
+ <div class="step">
3373
+ <div class="step-title">STEP 5: Build Final Tree Structure</div>
3374
+ <div class="step-calculation">
3375
+ Final Decision Tree:
3376
+
3377
+ [All data, Mean=73.5, Var=471.92]
3378
+ β”‚
3379
+ Split at Square Feet = 1200
3380
+ / \
3381
+ &lt;= 1200 &gt; 1200
3382
+ / \
3383
+ Mean = 52 Split at 1550
3384
+ (3 samples) / \
3385
+ &lt;= 1550 &gt; 1550
3386
+ / \
3387
+ Mean = 90 Mean = 97.5
3388
+ (1 sample) (2 samples)
3389
+
3390
+ <strong style="color: #7ef0d4;">Prediction Example:</strong>
3391
+ New property: 950 sq ft
3392
+ β”œβ”€ 950 &lt;= 1200? YES β†’ Go LEFT
3393
+ └─ Prediction: <strong style="color: #7ef0d4; font-size: 18px;">β‚Ή52 Lakhs</strong>
3394
+
3395
+ New property: 1650 sq ft
3396
+ β”œβ”€ 1650 &lt;= 1200? NO β†’ Go RIGHT
3397
+ β”œβ”€ 1650 &lt;= 1550? NO β†’ Go RIGHT
3398
+ └─ Prediction: <strong style="color: #7ef0d4; font-size: 18px;">β‚Ή97.5 Lakhs</strong>
3399
+ </div>
3400
+ </div>
3401
+
3402
+ <div class="figure">
3403
+ <div class="figure-placeholder" style="height: 450px">
3404
+ <canvas id="dt-regression-canvas"></canvas>
3405
+ </div>
3406
+ <p class="figure-caption"><strong>Figure:</strong> Decision tree regression with splits and predictions</p>
3407
+ </div>
3408
+
3409
+ <div class="callout success">
3410
+ <div class="callout-title">βœ… Key Takeaway</div>
3411
+ <div class="callout-content">
3412
+ Decision Tree Regression finds splits that minimize variance in leaf nodes. Each leaf predicts the mean of samples in that region. The recursive splitting creates a piecewise constant function!
3413
+ </div>
3414
+ </div>
3415
+
3416
+ <h3>Variance Reduction vs Information Gain</h3>
3417
+ <table class="data-table">
3418
+ <thead>
3419
+ <tr><th>Aspect</th><th>Classification Trees</th><th>Regression Trees</th></tr>
3420
+ </thead>
3421
+ <tbody>
3422
+ <tr><td>Splitting Criterion</td><td>Information Gain (Entropy/Gini)</td><td>Variance Reduction</td></tr>
3423
+ <tr><td>Prediction</td><td>Majority class</td><td>Mean value</td></tr>
3424
+ <tr><td>Leaf Node</td><td>Class label</td><td>Continuous value</td></tr>
3425
+ <tr><td>Goal</td><td>Maximize purity</td><td>Minimize variance</td></tr>
3426
+ </tbody>
3427
+ </table>
3428
+
3429
+ <div class="figure">
3430
+ <div class="figure-placeholder" style="height: 400px">
3431
+ <canvas id="dt-splits-canvas"></canvas>
3432
+ </div>
3433
+ <p class="figure-caption"><strong>Figure:</strong> Comparing different split points and their variance reduction</p>
3434
+ </div>
3435
+ </div>
3436
+ </div>
3437
+
3438
  <!-- Section 17: Decision Trees -->
3439
  <div class="section" id="decision-trees">
3440
  <div class="section-header">
 
4086
  </div>
4087
  </div>
4088
 
4089
+ <!-- Section 19a: Gradient Boosting (NEW FROM PDF) -->
4090
+ <div class="section" id="gradient-boosting">
4091
+ <div class="section-header">
4092
+ <h2><span class="badge" style="background: rgba(106, 169, 255, 0.3); color: #6aa9ff;">πŸ“Š Supervised - Ensemble</span> Gradient Boosting</h2>
4093
+ <button class="section-toggle collapsed">β–Ό</button>
4094
+ </div>
4095
+ <div class="section-body">
4096
+ <p>Gradient Boosting is a powerful ensemble technique that builds models sequentially, where each new model corrects the errors (residuals) of the previous models. Unlike AdaBoost which adjusts sample weights, Gradient Boosting directly fits new models to the residual errors!</p>
4097
+
4098
+ <div class="info-card">
4099
+ <div class="info-card-title">Key Concepts</div>
4100
+ <ul class="info-card-list">
4101
+ <li>Sequential learning: Each tree fixes errors of previous</li>
4102
+ <li>Weak learners: Simple stumps (depth=1)</li>
4103
+ <li>Learning rate: Controls step size (0.1 = small steps)</li>
4104
+ <li>Residuals: What model got wrong</li>
4105
+ <li>SSE: Sum of Squared Errors (lower = better split)</li>
4106
+ </ul>
4107
+ </div>
4108
+
4109
+ <h3>🎯 Complete Mathematical Solution (From PDF)</h3>
4110
+
4111
+ <h4>Dataset: House Price Prediction</h4>
4112
+ <table class="data-table">
4113
+ <thead>
4114
+ <tr><th>ID</th><th>Size (sq ft)</th><th>Bedrooms</th><th>Price (β‚Ή Lakhs)</th></tr>
4115
+ </thead>
4116
+ <tbody>
4117
+ <tr><td>1</td><td>800</td><td>2</td><td>120</td></tr>
4118
+ <tr><td>2</td><td>900</td><td>2</td><td>130</td></tr>
4119
+ <tr><td>3</td><td>1000</td><td>3</td><td>150</td></tr>
4120
+ <tr><td>4</td><td>1100</td><td>3</td><td>170</td></tr>
4121
+ <tr><td>5</td><td>1200</td><td>4</td><td>200</td></tr>
4122
+ </tbody>
4123
+ </table>
4124
+
4125
+ <p><strong>Learning Rate:</strong> lr = 0.1</p>
4126
+
4127
+ <div class="step">
4128
+ <div class="step-title">STEP 0: Initialize Model F(0)</div>
4129
+ <div class="step-calculation">
4130
+ Formula: F(0) = mean(y)
4131
+
4132
+ Calculation:
4133
+ F(0) = (120 + 130 + 150 + 170 + 200) / 5
4134
+ = 770 / 5
4135
+ = <strong style="color: #7ef0d4;">154</strong>
4136
+
4137
+ <strong style="color: #7ef0d4;">βœ“ Result: F(0) = 154</strong>
4138
+ </div>
4139
+ </div>
4140
+
4141
+ <div class="step">
4142
+ <div class="step-title">STEP 1: Compute Residuals</div>
4143
+ <div class="step-calculation">
4144
+ Formula: r_i = y_i - F(0)
4145
+
4146
+ <strong style="color: #6aa9ff;">Residual Calculation:</strong>
4147
+
4148
+ ID | Size | Beds | Price(y) | Prediction F(0) | Residual r_i
4149
+ ---|------|------|----------|-----------------|-------------
4150
+ 1 | 800 | 2 | 120 | 154 | -34
4151
+ 2 | 900 | 2 | 130 | 154 | -24
4152
+ 3 | 1000 | 3 | 150 | 154 | -4
4153
+ 4 | 1100 | 3 | 170 | 154 | +16
4154
+ 5 | 1200 | 4 | 200 | 154 | +46
4155
+
4156
+ <strong style="color: #7ef0d4;">βœ“ Residuals: [-34, -24, -4, +16, +46]</strong>
4157
+ </div>
4158
+ </div>
4159
+
4160
+ <div class="step">
4161
+ <div class="step-title">STEP 2: Find Best Split (Build Weak Learner h1)</div>
4162
+ <div class="step-calculation">
4163
+ Test all candidate splits for Size feature:
4164
+ Midpoints: 850, 950, 1050, 1150
4165
+
4166
+ <strong style="color: #6aa9ff;">Test: Size &lt; 1050</strong>
4167
+
4168
+ β”œβ”€ Left (Size ≀ 1050): IDs 1,2,3
4169
+ β”‚ Residuals: [-34, -24, -4]
4170
+ β”‚ Mean: (-34 + -24 + -4) / 3 = -62 / 3 = <strong>-20.66</strong>
4171
+ β”‚ SSE: (-34-(-20.66))Β² + (-24-(-20.66))Β² + (-4-(-20.66))Β²
4172
+ β”‚ = 177.78 + 11.11 + 277.78 = <strong>466.67</strong>
4173
+ β”‚
4174
+ └─ Right (Size &gt; 1050): IDs 4,5
4175
+ Residuals: [+16, +46]
4176
+ Mean: (16 + 46) / 2 = 62 / 2 = <strong>31.0</strong>
4177
+ SSE: (16-31)Β² + (46-31)Β² = 225 + 225 = <strong>450</strong>
4178
+
4179
+ <strong style="color: #ff8c6a;">Total SSE = 466.67 + 450 = 916.67</strong>
4180
+
4181
+ <strong style="color: #6aa9ff;">Test All Splits:</strong>
4182
+ Feature | Threshold | SSE
4183
+ ---------|-----------|--------
4184
+ Size | 850 | 2675
4185
+ Size | 950 | 1316.66
4186
+ Size | 1050 | 916.67 ← BEST SPLIT
4187
+ Size | 1150 | 1475.0
4188
+ Bedrooms | 2.5 | 1316.66
4189
+ Bedrooms | 3.5 | 1475.0
4190
+
4191
+ <strong style="color: #7ef0d4; font-size: 18px;">βœ“ BEST SPLIT: Size &lt; 1050 with SSE = 916.67</strong>
4192
+
4193
+ Weak Learner h1(x):
4194
+ β”œβ”€ If Size ≀ 1050: h1(x) = -20.66
4195
+ └─ If Size &gt; 1050: h1(x) = 31.0
4196
+ </div>
4197
+ </div>
4198
+
4199
+ <div class="step">
4200
+ <div class="step-title">STEP 3: Update Predictions</div>
4201
+ <div class="step-calculation">
4202
+ Formula: F1(x) = F(0) + lr Γ— h1(x)
4203
+ where lr = 0.1
4204
+
4205
+ <strong style="color: #6aa9ff;">For ID 1 (Size=800):</strong>
4206
+ F1(1) = 154 + 0.1 Γ— (-20.66)
4207
+ = 154 - 2.066
4208
+ = <strong style="color: #7ef0d4;">151.93</strong> βœ“
4209
+
4210
+ <strong style="color: #6aa9ff;">For ID 4 (Size=1100):</strong>
4211
+ F1(4) = 154 + 0.1 Γ— 31.0
4212
+ = 154 + 3.10
4213
+ = <strong style="color: #7ef0d4;">157.10</strong> βœ“
4214
+
4215
+ <strong style="color: #6aa9ff;">Complete Table:</strong>
4216
+ ID | Size | Price(y) | F(0) | h1(x) | F1(x) | New Residual
4217
+ ---|------|----------|------|--------|--------|-------------
4218
+ 1 | 800 | 120 | 154 | -20.66 | 151.93 | -31.93
4219
+ 2 | 900 | 130 | 154 | -20.66 | 151.93 | -21.93
4220
+ 3 | 1000 | 150 | 154 | -20.66 | 151.93 | -1.93
4221
+ 4 | 1100 | 170 | 154 | +31.0 | 157.10 | +12.90
4222
+ 5 | 1200 | 200 | 154 | +31.0 | 157.10 | +42.90
4223
+ </div>
4224
+ </div>
4225
+
4226
+ <div class="step">
4227
+ <div class="step-title">STEP 4: Repeat for h2, h3, ... h10</div>
4228
+ <div class="step-calculation">
4229
+ Continue building weak learners on residuals:
4230
+
4231
+ F(x) = F(0) + lrΓ—h1(x) + lrΓ—h2(x) + lrΓ—h3(x) + ... + lrΓ—h10(x)
4232
+
4233
+ Each iteration:
4234
+ 1. Compute residuals
4235
+ 2. Find best split
4236
+ 3. Build weak learner
4237
+ 4. Update predictions
4238
+
4239
+ After 10 iterations:
4240
+ <strong style="color: #7ef0d4; font-size: 18px;">Final Model: F(x) = 154 + 0.1Γ—h1(x) + 0.1Γ—h2(x) + ... + 0.1Γ—h10(x)</strong>
4241
+ </div>
4242
+ </div>
4243
+
4244
+ <h3>πŸ“Š Visualizations</h3>
4245
+
4246
+ <div class="figure">
4247
+ <div class="figure-placeholder" style="height: 400px">
4248
+ <canvas id="gb-sequential-canvas"></canvas>
4249
+ </div>
4250
+ <p class="figure-caption"><strong>Figure 1:</strong> Sequential tree building - residuals decreasing over iterations</p>
4251
+ </div>
4252
+
4253
+ <div class="figure">
4254
+ <div class="figure-placeholder" style="height: 400px">
4255
+ <canvas id="gb-residuals-canvas"></canvas>
4256
+ </div>
4257
+ <p class="figure-caption"><strong>Figure 2:</strong> Residual reduction across iterations</p>
4258
+ </div>
4259
+
4260
+ <div class="figure">
4261
+ <div class="figure-placeholder" style="height: 400px">
4262
+ <canvas id="gb-learning-rate-canvas"></canvas>
4263
+ </div>
4264
+ <p class="figure-caption"><strong>Figure 3:</strong> Learning rate effect - comparing lr=0.01, 0.1, 1.0</p>
4265
+ </div>
4266
+
4267
+ <div class="figure">
4268
+ <div class="figure-placeholder" style="height: 400px">
4269
+ <canvas id="gb-stumps-canvas"></canvas>
4270
+ </div>
4271
+ <p class="figure-caption"><strong>Figure 4:</strong> Weak learner stumps with decision boundaries</p>
4272
+ </div>
4273
+
4274
+ <div class="figure">
4275
+ <div class="figure-placeholder" style="height: 400px">
4276
+ <canvas id="gb-predictions-canvas"></canvas>
4277
+ </div>
4278
+ <p class="figure-caption"><strong>Figure 5:</strong> Prediction vs actual - showing improvement</p>
4279
+ </div>
4280
+
4281
+ <div class="callout success">
4282
+ <div class="callout-title">βœ… Key Takeaways</div>
4283
+ <div class="callout-content">
4284
+ <strong>Why Gradient Boosting Works:</strong><br>
4285
+ β€’ Each tree learns from previous mistakes (residuals)<br>
4286
+ β€’ Learning rate prevents overfitting<br>
4287
+ β€’ Simple weak learners combine into strong predictor<br>
4288
+ β€’ SSE-based splits find best variance reduction<br>
4289
+ <br>
4290
+ <strong>Advantages:</strong><br>
4291
+ βœ“ Very high accuracy<br>
4292
+ βœ“ Handles non-linear relationships<br>
4293
+ βœ“ Feature importance built-in<br>
4294
+ <br>
4295
+ <strong>Disadvantages:</strong><br>
4296
+ βœ— Sequential (can't parallelize)<br>
4297
+ βœ— Sensitive to overfitting<br>
4298
+ βœ— Requires careful tuning
4299
+ </div>
4300
+ </div>
4301
+ </div>
4302
+ </div>
4303
+
4304
+ <!-- Section 19b: XGBoost (NEW FROM PDF) -->
4305
+ <div class="section" id="xgboost">
4306
+ <div class="section-header">
4307
+ <h2><span class="badge" style="background: rgba(106, 169, 255, 0.3); color: #6aa9ff;">πŸ“Š Supervised - Ensemble</span> XGBoost (Extreme Gradient Boosting)</h2>
4308
+ <button class="section-toggle collapsed">β–Ό</button>
4309
+ </div>
4310
+ <div class="section-body">
4311
+ <p>XGBoost is an optimized implementation of gradient boosting that uses second-order derivatives (Hessian) and regularization for superior performance. It's the algorithm that wins most Kaggle competitions!</p>
4312
+
4313
+ <div class="info-card">
4314
+ <div class="info-card-title">Key Concepts</div>
4315
+ <ul class="info-card-list">
4316
+ <li>Uses 2nd order derivatives (Hessian) for better approximation</li>
4317
+ <li>Built-in regularization (Ξ») to prevent overfitting</li>
4318
+ <li>Better gain calculation for splits</li>
4319
+ <li>Handles parallelism and missing values</li>
4320
+ <li>Much faster than standard gradient boosting</li>
4321
+ </ul>
4322
+ </div>
4323
+
4324
+ <h3>🎯 XGBoost vs Gradient Boosting</h3>
4325
+ <table class="data-table">
4326
+ <thead>
4327
+ <tr><th>Aspect</th><th>Gradient Boosting</th><th>XGBoost</th></tr>
4328
+ </thead>
4329
+ <tbody>
4330
+ <tr><td>Derivatives</td><td>1st order (gradient)</td><td>1st + 2nd order (Hessian)</td></tr>
4331
+ <tr><td>Regularization</td><td>None built-in</td><td>L1 &amp; L2 built-in (Ξ»)</td></tr>
4332
+ <tr><td>Split Criterion</td><td>MSE/MAE</td><td>Gain with regularization</td></tr>
4333
+ <tr><td>Parallelism</td><td>No</td><td>Yes (tree building)</td></tr>
4334
+ <tr><td>Missing Values</td><td>Must handle separately</td><td>Built-in handling</td></tr>
4335
+ <tr><td>Speed</td><td>Slower</td><td>Much faster</td></tr>
4336
+ </tbody>
4337
+ </table>
4338
+
4339
+ <h3>🎯 Complete Mathematical Solution (From PDF)</h3>
4340
+
4341
+ <p><strong>Using same dataset as Gradient Boosting:</strong></p>
4342
+
4343
+ <div class="formula">
4344
+ <strong>XGBoost Gain Formula:</strong>
4345
+ Gain = [GLΒ² / (HL + Ξ»)] + [GRΒ² / (HR + Ξ»)] - [G_parentΒ² / (H_parent + Ξ»)]
4346
+ <br><br>
4347
+ Where:<br>
4348
+ &nbsp;&nbsp;G = Gradient (1st derivative) = Ξ£(y - Ε·)<br>
4349
+ &nbsp;&nbsp;H = Hessian (2nd derivative) = Ξ£(1) for regression<br>
4350
+ &nbsp;&nbsp;Ξ» = Regularization parameter (default = 1)
4351
+ </div>
4352
+
4353
+ <div class="step">
4354
+ <div class="step-title">STEP 0: Initialize</div>
4355
+ <div class="step-calculation">
4356
+ F(0) = mean(y) = <strong style="color: #7ef0d4;">154</strong>
4357
+ </div>
4358
+ </div>
4359
+
4360
+ <div class="step">
4361
+ <div class="step-title">STEP 1: Compute Gradients and Hessians</div>
4362
+ <div class="step-calculation">
4363
+ <strong style="color: #6aa9ff;">For Regression (MSE loss):</strong>
4364
+ gradient g = (y - Ε·)
4365
+ hessian h = 1 (constant for MSE)
4366
+
4367
+ ID | Size | Price(y) | F(0) | g=(y-Ε·) | h
4368
+ ---|------|----------|------|---------|---
4369
+ 1 | 800 | 120 | 154 | -34 | 1
4370
+ 2 | 900 | 130 | 154 | -24 | 1
4371
+ 3 | 1000 | 150 | 154 | -4 | 1
4372
+ 4 | 1100 | 170 | 154 | +16 | 1
4373
+ 5 | 1200 | 200 | 154 | +46 | 1
4374
+ </div>
4375
+ </div>
4376
+
4377
+ <div class="step">
4378
+ <div class="step-title">STEP 2: Test Split - Size &lt; 950</div>
4379
+ <div class="step-calculation">
4380
+ <strong style="color: #6aa9ff;">Split: Size &lt; 950</strong>
4381
+
4382
+ β”œβ”€ Left: IDs 1,2 (800, 900)
4383
+ β”‚ GL = -34 + (-24) = <strong>-58</strong>
4384
+ β”‚ HL = 1 + 1 = <strong>2</strong>
4385
+ β”‚
4386
+ └─ Right: IDs 3,4,5 (1000, 1100, 1200)
4387
+ GR = -4 + 16 + 46 = <strong>+58</strong>
4388
+ HR = 1 + 1 + 1 = <strong>3</strong>
4389
+
4390
+ Parent:
4391
+ G_parent = -34 + (-24) + (-4) + 16 + 46 = <strong>0</strong>
4392
+ H_parent = <strong>5</strong>
4393
+
4394
+ <strong style="color: #6aa9ff;">Calculate Scores (Ξ» = 1):</strong>
4395
+
4396
+ Score(Left) = -GLΒ² / (HL + Ξ»)
4397
+ = -(-58)Β² / (2 + 1)
4398
+ = -3364 / 3
4399
+ = <strong>-1121.33</strong>
4400
+
4401
+ Score(Right) = -GRΒ² / (HR + Ξ»)
4402
+ = -(58)Β² / (3 + 1)
4403
+ = -3364 / 4
4404
+ = <strong>-841</strong>
4405
+
4406
+ Score(Parent) = -G_parentΒ² / (H_parent + Ξ»)
4407
+ = -(0)Β² / (5 + 1)
4408
+ = <strong>0</strong>
4409
+
4410
+ Gain = Score(Left) + Score(Right) - Score(Parent)
4411
+ = -1121.33 + (-841) - 0
4412
+ = -1962.33
4413
+
4414
+ Use absolute value: Gain = <strong style="color: #7ef0d4; font-size: 18px;">1962.33</strong> βœ“ HIGHEST GAIN
4415
+ </div>
4416
+ </div>
4417
+
4418
+ <div class="step">
4419
+ <div class="step-title">STEP 3: Compute Leaf Weights</div>
4420
+ <div class="step-calculation">
4421
+ Formula: w = -G / (H + Ξ»)
4422
+
4423
+ <strong style="color: #6aa9ff;">Left Leaf:</strong>
4424
+ w_left = -(-58) / (2 + 1)
4425
+ = 58 / 3
4426
+ = <strong style="color: #7ef0d4;">19.33</strong>
4427
+
4428
+ <strong style="color: #6aa9ff;">Right Leaf:</strong>
4429
+ w_right = -(58) / (3 + 1)
4430
+ = -58 / 4
4431
+ = <strong style="color: #7ef0d4;">-14.5</strong>
4432
+ </div>
4433
+ </div>
4434
+
4435
+ <div class="step">
4436
+ <div class="step-title">STEP 4: Update Predictions</div>
4437
+ <div class="step-calculation">
4438
+ Formula: F1(x) = F(0) + lr Γ— w
4439
+
4440
+ <strong style="color: #6aa9ff;">Complete Table:</strong>
4441
+ ID | Size | Price(y) | F(0) | Leaf Weight | F1(x) | New Residual
4442
+ ---|------|----------|------|-------------|-----------|-------------
4443
+ 1 | 800 | 120 | 154 | -19.33 | 134.67 | -14.67
4444
+ 2 | 900 | 130 | 154 | -19.33 | 134.67 | -4.67
4445
+ 3 | 1000 | 150 | 154 | +14.5 | 168.50 | -18.50
4446
+ 4 | 1100 | 170 | 154 | +14.5 | 168.50 | +1.50
4447
+ 5 | 1200 | 200 | 154 | +14.5 | 168.50 | +31.50
4448
+ </div>
4449
+ </div>
4450
+
4451
+ <h3>πŸ“Š Visualizations</h3>
4452
+
4453
+ <div class="figure">
4454
+ <div class="figure-placeholder" style="height: 400px">
4455
+ <canvas id="xgb-gain-canvas"></canvas>
4456
+ </div>
4457
+ <p class="figure-caption"><strong>Figure 1:</strong> Gain calculation showing GL, GR, HL, HR for each split</p>
4458
+ </div>
4459
+
4460
+ <div class="figure">
4461
+ <div class="figure-placeholder" style="height: 400px">
4462
+ <canvas id="xgb-regularization-canvas"></canvas>
4463
+ </div>
4464
+ <p class="figure-caption"><strong>Figure 2:</strong> Regularization effect - comparing Ξ»=0, 1, 10</p>
4465
+ </div>
4466
+
4467
+ <div class="figure">
4468
+ <div class="figure-placeholder" style="height: 400px">
4469
+ <canvas id="xgb-hessian-canvas"></canvas>
4470
+ </div>
4471
+ <p class="figure-caption"><strong>Figure 3:</strong> Hessian contribution to better optimization</p>
4472
+ </div>
4473
+
4474
+ <div class="figure">
4475
+ <div class="figure-placeholder" style="height: 350px">
4476
+ <canvas id="xgb-leaf-weights-canvas"></canvas>
4477
+ </div>
4478
+ <p class="figure-caption"><strong>Figure 4:</strong> Leaf weight calculation breakdown</p>
4479
+ </div>
4480
+
4481
+ <div class="figure">
4482
+ <div class="figure-placeholder" style="height: 450px">
4483
+ <canvas id="xgb-comparison-canvas"></canvas>
4484
+ </div>
4485
+ <p class="figure-caption"><strong>Figure 5:</strong> Gradient Boosting vs XGBoost performance comparison</p>
4486
+ </div>
4487
+
4488
+ <div class="callout success">
4489
+ <div class="callout-title">βœ… Key Advantages of XGBoost</div>
4490
+ <div class="callout-content">
4491
+ <strong>Mathematical Improvements:</strong><br>
4492
+ βœ“ 2nd order derivatives β†’ Better approximation<br>
4493
+ βœ“ Regularization (Ξ») β†’ Prevents overfitting<br>
4494
+ βœ“ Gain-based splitting β†’ More accurate<br>
4495
+ <br>
4496
+ <strong>Engineering Improvements:</strong><br>
4497
+ βœ“ Parallel processing β†’ Faster training<br>
4498
+ βœ“ Handles missing values β†’ More robust<br>
4499
+ βœ“ Built-in cross-validation β†’ Easy tuning<br>
4500
+ βœ“ Tree pruning β†’ Better generalization<br>
4501
+ βœ“ Cache optimization β†’ Memory efficient<br>
4502
+ <br>
4503
+ <strong>Real-World Impact:</strong><br>
4504
+ β€’ Most popular algorithm for structured data<br>
4505
+ β€’ Dominates Kaggle competitions<br>
4506
+ β€’ Used by: Uber, Airbnb, Microsoft, etc.
4507
+ </div>
4508
+ </div>
4509
+
4510
+ <h3>Hyperparameter Guide</h3>
4511
+ <table class="data-table">
4512
+ <thead>
4513
+ <tr><th>Parameter</th><th>Description</th><th>Typical Values</th></tr>
4514
+ </thead>
4515
+ <tbody>
4516
+ <tr><td>learning_rate (Ξ·)</td><td>Step size shrinkage</td><td>0.01 - 0.3</td></tr>
4517
+ <tr><td>n_estimators</td><td>Number of trees</td><td>100 - 1000</td></tr>
4518
+ <tr><td>max_depth</td><td>Tree depth</td><td>3 - 10</td></tr>
4519
+ <tr><td>lambda (Ξ»)</td><td>L2 regularization</td><td>0 - 10</td></tr>
4520
+ <tr><td>alpha (Ξ±)</td><td>L1 regularization</td><td>0 - 10</td></tr>
4521
+ <tr><td>subsample</td><td>Row sampling</td><td>0.5 - 1.0</td></tr>
4522
+ <tr><td>colsample_bytree</td><td>Column sampling</td><td>0.5 - 1.0</td></tr>
4523
+ </tbody>
4524
+ </table>
4525
+ </div>
4526
+ </div>
4527
+
4528
+ <!-- Section 19c: Bagging (Renamed) -->
4529
+ <div class="section" id="bagging">
4530
+ <div class="section-header">
4531
+ <h2><span class="badge" style="background: rgba(106, 169, 255, 0.3); color: #6aa9ff;">πŸ“Š Supervised - Ensemble</span> Bagging (Bootstrap Aggregating)</h2>
4532
+ <button class="section-toggle collapsed">β–Ό</button>
4533
+ </div>
4534
+ <div class="section-body">
4535
+ <p>Bagging trains multiple models on different random subsets of data (with replacement), then averages predictions. It's the foundation for Random Forest!</p>
4536
+
4537
+ <div class="figure">
4538
+ <div class="figure-placeholder" style="height: 400px">
4539
+ <canvas id="bagging-complete-canvas"></canvas>
4540
+ </div>
4541
+ <p class="figure-caption"><strong>Figure:</strong> Bagging process showing 3 trees and averaged prediction</p>
4542
+ </div>
4543
+
4544
+ <p>See the <a href="#ensemble-methods">Ensemble Methods Overview</a> section below for complete mathematical walkthrough.</p>
4545
+ </div>
4546
+ </div>
4547
+
4548
+ <!-- Section 19d: Boosting/AdaBoost (Renamed) -->
4549
+ <div class="section" id="boosting-adaboost">
4550
+ <div class="section-header">
4551
+ <h2><span class="badge" style="background: rgba(106, 169, 255, 0.3); color: #6aa9ff;">πŸ“Š Supervised - Ensemble</span> Boosting (AdaBoost)</h2>
4552
+ <button class="section-toggle collapsed">β–Ό</button>
4553
+ </div>
4554
+ <div class="section-body">
4555
+ <p>AdaBoost trains models sequentially, where each new model focuses on examples the previous models got wrong by adjusting sample weights.</p>
4556
+
4557
+ <div class="figure">
4558
+ <div class="figure-placeholder" style="height: 450px">
4559
+ <canvas id="boosting-complete-canvas"></canvas>
4560
+ </div>
4561
+ <p class="figure-caption"><strong>Figure:</strong> Boosting rounds showing weight updates and error reduction</p>
4562
+ </div>
4563
+
4564
+ <p>See the <a href="#ensemble-methods">Ensemble Methods Overview</a> section below for complete mathematical walkthrough.</p>
4565
+ </div>
4566
+ </div>
4567
+
4568
+ <!-- Section 19e: Random Forest (Renamed) -->
4569
+ <div class="section" id="random-forest">
4570
+ <div class="section-header">
4571
+ <h2><span class="badge" style="background: rgba(106, 169, 255, 0.3); color: #6aa9ff;">πŸ“Š Supervised - Ensemble</span> Random Forest</h2>
4572
+ <button class="section-toggle collapsed">β–Ό</button>
4573
+ </div>
4574
+ <div class="section-body">
4575
+ <p>Random Forest combines bagging with feature randomness. Each tree is trained on a bootstrap sample AND considers only random subsets of features at each split!</p>
4576
+
4577
+ <div class="figure">
4578
+ <div class="figure-placeholder" style="height: 500px">
4579
+ <canvas id="rf-complete-canvas"></canvas>
4580
+ </div>
4581
+ <p class="figure-caption"><strong>Figure:</strong> Random Forest showing feature randomness and OOB validation</p>
4582
+ </div>
4583
+
4584
+ <p>See the <a href="#ensemble-methods">Ensemble Methods Overview</a> section below for complete mathematical walkthrough.</p>
4585
+ </div>
4586
+ </div>
4587
+
4588
+ <!-- Section 19: Ensemble Methods (COMPREHENSIVE FROM PDF) -->
4589
  <div class="section" id="ensemble-methods">
4590
  <div class="section-header">
4591
  <h2><span class="badge" style="background: rgba(106, 169, 255, 0.3); color: #6aa9ff;">πŸ“Š Supervised</span> Ensemble Methods</h2>
 
4622
  </div>
4623
  </div>
4624
 
4625
+ <h3>🎯 Method 1: Bagging (Bootstrap Aggregating) - Complete Walkthrough</h3>
4626
  <p>Train multiple models on different random subsets of data (with replacement), then average predictions.</p>
4627
 
4628
+ <h4>Dataset: 6 Properties</h4>
4629
+ <table class="data-table">
4630
+ <thead>
4631
+ <tr><th>Row</th><th>Square Feet</th><th>Price (Lakhs)</th></tr>
4632
+ </thead>
4633
+ <tbody>
4634
+ <tr><td>A</td><td>900</td><td>70</td></tr>
4635
+ <tr><td>B</td><td>1000</td><td>80</td></tr>
4636
+ <tr><td>C</td><td>900</td><td>70</td></tr>
4637
+ <tr><td>D</td><td>1500</td><td>90</td></tr>
4638
+ <tr><td>E</td><td>1600</td><td>95</td></tr>
4639
+ <tr><td>F</td><td>1700</td><td>100</td></tr>
4640
+ </tbody>
4641
+ </table>
4642
+
4643
+ <div class="step">
4644
+ <div class="step-title">STEP 1: Create Bootstrap Samples (WITH Replacement)</div>
4645
+ <div class="step-calculation">
4646
+ <strong style="color: #6aa9ff;">Bootstrap Sample 1:</strong>
4647
+ Randomly pick 6 samples WITH replacement:
4648
+ β”œβ”€ Row A: 900 sq ft, β‚Ή70L (sampled TWICE!)
4649
+ β”œβ”€ Row A: 900 sq ft, β‚Ή70L (duplicate)
4650
+ β”œβ”€ Row B: 1000 sq ft, β‚Ή80L
4651
+ β”œβ”€ Row D: 1500 sq ft, β‚Ή90L
4652
+ β”œβ”€ Row E: 1600 sq ft, β‚Ή95L
4653
+ └─ Row F: 1700 sq ft, β‚Ή100L
4654
+
4655
+ <strong style="color: #6aa9ff;">Bootstrap Sample 2:</strong>
4656
+ β”œβ”€ Row C: 900 sq ft, β‚Ή70L
4657
+ β”œβ”€ Row D: 1500 sq ft, β‚Ή90L
4658
+ β”œβ”€ Row E: 1600 sq ft, β‚Ή95L
4659
+ β”œβ”€ Row E: 1600 sq ft, β‚Ή95L (sampled TWICE!)
4660
+ β”œβ”€ Row F: 1700 sq ft, β‚Ή100L
4661
+ └─ Row B: 1000 sq ft, β‚Ή80L
4662
+
4663
+ <strong style="color: #6aa9ff;">Bootstrap Sample 3:</strong>
4664
+ β”œβ”€ Row F: 1700 sq ft, β‚Ή100L
4665
+ β”œβ”€ Row C: 900 sq ft, β‚Ή70L
4666
+ β”œβ”€ Row E: 1600 sq ft, β‚Ή95L
4667
+ β”œβ”€ Row A: 900 sq ft, β‚Ή70L
4668
+ β”œβ”€ Row B: 1000 sq ft, β‚Ή80L
4669
+ └─ Row D: 1500 sq ft, β‚Ή90L
4670
+ </div>
4671
+ </div>
4672
+
4673
+ <div class="step">
4674
+ <div class="step-title">STEP 2: Train Separate Model on Each Sample</div>
4675
+ <div class="step-calculation">
4676
+ <strong style="color: #7ef0d4;">Tree 1:</strong> Trained on Sample 1
4677
+ β€’ Learns splits based on its data
4678
+ β€’ For 950 sq ft β†’ Predicts: <strong>β‚Ή75L</strong>
4679
+
4680
+ <strong style="color: #7ef0d4;">Tree 2:</strong> Trained on Sample 2
4681
+ β€’ Different data β†’ Different splits!
4682
+ β€’ For 950 sq ft β†’ Predicts: <strong>β‚Ή72L</strong>
4683
+
4684
+ <strong style="color: #7ef0d4;">Tree 3:</strong> Trained on Sample 3
4685
+ β€’ Yet another perspective
4686
+ β€’ For 950 sq ft β†’ Predicts: <strong>β‚Ή78L</strong>
4687
+ </div>
4688
+ </div>
4689
+
4690
+ <div class="step">
4691
+ <div class="step-title">STEP 3: Aggregate Predictions (Average)</div>
4692
+ <div class="step-calculation">
4693
+ For test property with 950 sq ft:
4694
+
4695
+ Prediction₁ = β‚Ή75L
4696
+ Predictionβ‚‚ = β‚Ή72L
4697
+ Prediction₃ = β‚Ή78L
4698
+
4699
+ <strong style="color: #6aa9ff;">Final Bagging Prediction:</strong>
4700
+ Average = (75 + 72 + 78) / 3
4701
+ = 225 / 3
4702
+ = <strong style="color: #7ef0d4; font-size: 18px;">β‚Ή75 Lakhs</strong> βœ“
4703
+
4704
+ <strong style="color: #7ef0d4;">Why it works:</strong>
4705
+ β€’ Each tree makes slightly different errors
4706
+ β€’ Averaging reduces overall variance
4707
+ β€’ More stable than single tree!
4708
+ </div>
4709
+ </div>
4710
+
4711
+ <div class="figure">
4712
+ <div class="figure-placeholder" style="height: 400px">
4713
+ <canvas id="bagging-complete-canvas"></canvas>
4714
+ </div>
4715
+ <p class="figure-caption"><strong>Figure:</strong> Bagging process showing 3 trees and averaged prediction</p>
4716
+ </div>
4717
+
4718
  <div class="formula">
4719
  <strong>Bagging Algorithm:</strong><br>
4720
  1. Create B bootstrap samples (random sampling with replacement)<br>
 
4733
  <p class="figure-caption"><strong>Figure 1:</strong> Bagging process - multiple models from bootstrap samples</p>
4734
  </div>
4735
 
4736
+ <h3>🎯 Method 2: Boosting (Sequential Learning) - Complete Walkthrough</h3>
4737
  <p>Train models sequentially, where each new model focuses on examples the previous models got wrong.</p>
4738
 
4739
+ <div class="step">
4740
+ <div class="step-title">STEP 1: Round 1 - Train Model 1 on All Data (Equal Weights)</div>
4741
+ <div class="step-calculation">
4742
+ Original Dataset (all samples weighted equally: w=1.0):
4743
+ β”œβ”€ 800 sq ft β†’ Actual: β‚Ή50L
4744
+ β”œβ”€ 850 sq ft β†’ Actual: β‚Ή52L
4745
+ β”œβ”€ 900 sq ft β†’ Actual: β‚Ή54L
4746
+ β”œβ”€ 1500 sq ft β†’ Actual: β‚Ή90L
4747
+ β”œβ”€ 1600 sq ft β†’ Actual: β‚Ή95L
4748
+ └─ 1700 sq ft β†’ Actual: β‚Ή100L
4749
+
4750
+ <strong style="color: #6aa9ff;">Model 1 Predictions:</strong>
4751
+ β”œβ”€ 800 sq ft β†’ Predicts: β‚Ή70L (Error: -20)
4752
+ β”œβ”€ 850 sq ft β†’ Predicts: β‚Ή72L (Error: -20)
4753
+ β”œβ”€ 900 sq ft β†’ Predicts: β‚Ή75L (Error: -21)
4754
+ β”œβ”€ 1500 sq ft β†’ Predicts: β‚Ή88L (Error: +2) ⚠️
4755
+ β”œβ”€ 1600 sq ft β†’ Predicts: β‚Ή92L (Error: +3) ⚠️
4756
+ └─ 1700 sq ft β†’ Predicts: β‚Ή98L (Error: +2) ⚠️
4757
+
4758
+ <strong style="color: #ff8c6a;">Large errors on rows 4, 5, 6!</strong>
4759
+ </div>
4760
+ </div>
4761
+
4762
+ <div class="step">
4763
+ <div class="step-title">STEP 2: Round 2 - Increase Weights on Misclassified</div>
4764
+ <div class="step-calculation">
4765
+ Update weights based on errors:
4766
+ β”œβ”€ Row 1: w = 1.0 (small error)
4767
+ β”œβ”€ Row 2: w = 1.0 (small error)
4768
+ β”œβ”€ Row 3: w = 1.0 (small error)
4769
+ β”œβ”€ Row 4: w = 2.5 (large error β†’ FOCUS!) 🎯
4770
+ β”œβ”€ Row 5: w = 3.0 (large error β†’ FOCUS!) 🎯
4771
+ └─ Row 6: w = 2.5 (large error β†’ FOCUS!) 🎯
4772
+
4773
+ <strong style="color: #6aa9ff;">Train Model 2 with these weights:</strong>
4774
+ Model 2 focuses on the high-priced properties!
4775
+
4776
+ <strong style="color: #6aa9ff;">Model 2 Predictions:</strong>
4777
+ β”œβ”€ 800 sq ft β†’ β‚Ή71L (Error: -21)
4778
+ β”œβ”€ 850 sq ft β†’ β‚Ή73L (Error: -21)
4779
+ β”œβ”€ 900 sq ft β†’ β‚Ή74L (Error: -20)
4780
+ β”œβ”€ 1500 sq ft β†’ β‚Ή90L (Error: 0) βœ“
4781
+ β”œβ”€ 1600 sq ft β†’ β‚Ή94L (Error: +1) βœ“
4782
+ └─ 1700 sq ft β†’ β‚Ή100L (Error: 0) βœ“
4783
+
4784
+ <strong style="color: #7ef0d4;">Better on high-priced properties!</strong>
4785
+ </div>
4786
+ </div>
4787
+
4788
+ <div class="step">
4789
+ <div class="step-title">STEP 3: Round 3 - Further Refine</div>
4790
+ <div class="step-calculation">
4791
+ Update weights again:
4792
+ β”œβ”€ Rows 1,2,3 still have errors β†’ increase weights
4793
+ β”œβ”€ Rows 4,5,6 now accurate β†’ decrease weights
4794
+
4795
+ <strong style="color: #6aa9ff;">Model 3 Predictions:</strong>
4796
+ β”œβ”€ 800 sq ft β†’ β‚Ή70L (Error: -20)
4797
+ β”œβ”€ 850 sq ft β†’ β‚Ή72L (Error: -20)
4798
+ β”œβ”€ 900 sq ft β†’ β‚Ή75L (Error: -21)
4799
+ β”œβ”€ 1500 sq ft β†’ β‚Ή89L (Error: +1)
4800
+ β”œβ”€ 1600 sq ft β†’ β‚Ή93L (Error: +2)
4801
+ └─ 1700 sq ft β†’ β‚Ή99L (Error: +1)
4802
+
4803
+ <strong style="color: #7ef0d4;">All errors minimized!</strong>
4804
+ </div>
4805
+ </div>
4806
+
4807
+ <div class="step">
4808
+ <div class="step-title">STEP 4: Combine with Weights</div>
4809
+ <div class="step-calculation">
4810
+ Model weights (based on accuracy):
4811
+ β€’ Model 1: α₁ = 0.2 (least accurate)
4812
+ β€’ Model 2: Ξ±β‚‚ = 0.3 (medium accuracy)
4813
+ β€’ Model 3: α₃ = 0.5 (most accurate)
4814
+
4815
+ <strong style="color: #6aa9ff;">Final Prediction for 950 sq ft:</strong>
4816
+ Weighted Average = α₁×Pred₁ + Ξ±β‚‚Γ—Predβ‚‚ + α₃×Pred₃
4817
+ = 0.2Γ—75 + 0.3Γ—74 + 0.5Γ—75
4818
+ = 15 + 22.2 + 37.5
4819
+ = <strong style="color: #7ef0d4; font-size: 18px;">β‚Ή74.7 Lakhs</strong> βœ“
4820
+
4821
+ <strong style="color: #7ef0d4;">More accurate than any single model!</strong>
4822
+ </div>
4823
+ </div>
4824
+
4825
+ <div class="figure">
4826
+ <div class="figure-placeholder" style="height: 450px">
4827
+ <canvas id="boosting-complete-canvas"></canvas>
4828
+ </div>
4829
+ <p class="figure-caption"><strong>Figure:</strong> Boosting rounds showing weight updates and error reduction</p>
4830
+ </div>
4831
+
4832
  <div class="formula">
4833
  <strong>Boosting Algorithm:</strong><br>
4834
  1. Start with equal weights for all samples<br>
 
4848
  <p class="figure-caption"><strong>Figure 2:</strong> Boosting iteration - focusing on misclassified points</p>
4849
  </div>
4850
 
4851
+ <h3>🎯 Random Forest: Complete Walkthrough (From PDF)</h3>
4852
  <p>The most popular ensemble method! Combines bagging with feature randomness.</p>
4853
 
4854
+ <h4>Dataset: House Prices with 3 Features</h4>
4855
+ <table class="data-table">
4856
+ <thead>
4857
+ <tr><th>Square Feet</th><th>Bedrooms</th><th>Age (years)</th><th>Price (Lakhs)</th></tr>
4858
+ </thead>
4859
+ <tbody>
4860
+ <tr><td>800</td><td>2</td><td>10</td><td>50</td></tr>
4861
+ <tr><td>850</td><td>2</td><td>8</td><td>52</td></tr>
4862
+ <tr><td>900</td><td>2</td><td>5</td><td>54</td></tr>
4863
+ <tr><td>1500</td><td>3</td><td>3</td><td>90</td></tr>
4864
+ <tr><td>1600</td><td>3</td><td>2</td><td>95</td></tr>
4865
+ <tr><td>1700</td><td>4</td><td>1</td><td>100</td></tr>
4866
+ </tbody>
4867
+ </table>
4868
+
4869
+ <p><strong>Key Parameter:</strong> Max Features = 2 (random subset at each split)</p>
4870
+
4871
+ <div class="step">
4872
+ <div class="step-title">STEP 1: Tree 1 - Random Features at Each Split</div>
4873
+ <div class="step-calculation">
4874
+ <strong style="color: #6aa9ff;">Bootstrap Sample 1:</strong> {A, A, B, D, E, F}
4875
+
4876
+ <strong>Root Split:</strong>
4877
+ Available features: [Square Feet, Bedrooms, Age]
4878
+ Randomly select 2: <strong style="color: #7ef0d4;">[Square Feet, Age]</strong>
4879
+
4880
+ Test splits:
4881
+ β€’ Square Feet = 1200: Variance Reduction = 450 ← BEST!
4882
+ β€’ Age = 5: Variance Reduction = 120
4883
+
4884
+ <strong style="color: #7ef0d4;">Choose: Split at Square Feet = 1200</strong>
4885
+
4886
+ <strong>Left Child Split:</strong>
4887
+ Samples: {A, A, B} - all small houses
4888
+ Randomly select 2: <strong style="color: #7ef0d4;">[Bedrooms, Age]</strong>
4889
+ β€’ Both have 2 bedrooms β†’ split by Age
4890
+ β€’ Age = 9: Best split
4891
+
4892
+ <strong>Right Child Split:</strong>
4893
+ Samples: {D, E, F} - all large houses
4894
+ Randomly select 2: <strong style="color: #7ef0d4;">[Square Feet, Bedrooms]</strong>
4895
+ β€’ Split at Square Feet = 1550
4896
+ </div>
4897
+ </div>
4898
+
4899
+ <div class="step">
4900
+ <div class="step-title">STEP 2: Tree 2 - Different Bootstrap, Different Features</div>
4901
+ <div class="step-calculation">
4902
+ <strong style="color: #6aa9ff;">Bootstrap Sample 2:</strong> {B, C, C, D, E, F}
4903
+
4904
+ <strong>Root Split:</strong>
4905
+ Randomly select 2: <strong style="color: #7ef0d4;">[Square Feet, Bedrooms]</strong> (different!)
4906
+ β€’ Square Feet = 1100: Variance Reduction = 420
4907
+ β€’ Bedrooms = 2.5: Variance Reduction = 380
4908
+
4909
+ <strong style="color: #7ef0d4;">Choose: Split at Square Feet = 1100</strong>
4910
+
4911
+ This tree has DIFFERENT structure than Tree 1!
4912
+ β†’ More diversity = Better ensemble
4913
+ </div>
4914
+ </div>
4915
+
4916
+ <div class="step">
4917
+ <div class="step-title">STEP 3: Continue for 100 Trees</div>
4918
+ <div class="step-calculation">
4919
+ Repeat process 100 times:
4920
+ β€’ Each tree gets different bootstrap sample
4921
+ β€’ Each split considers different random features
4922
+ β€’ Creates 100 diverse trees!
4923
+
4924
+ Tree predictions for 950 sq ft:
4925
+ β”œβ”€ Tree 1: β‚Ή74L
4926
+ β”œβ”€ Tree 2: β‚Ή76L
4927
+ β”œβ”€ Tree 3: β‚Ή75L
4928
+ β”œβ”€ Tree 4: β‚Ή73L
4929
+ β”œβ”€ ...
4930
+ └─ Tree 100: β‚Ή75L
4931
+ </div>
4932
+ </div>
4933
+
4934
+ <div class="step">
4935
+ <div class="step-title">STEP 4: Average All Predictions</div>
4936
+ <div class="step-calculation">
4937
+ <strong style="color: #6aa9ff;">Final Random Forest Prediction:</strong>
4938
+
4939
+ Average of 100 trees:
4940
+ = (74 + 76 + 75 + 73 + ... + 75) / 100
4941
+ = <strong style="color: #7ef0d4; font-size: 18px;">β‚Ή75.2 Lakhs</strong> βœ“
4942
+
4943
+ Confidence interval (std dev):
4944
+ = Β±2.3 Lakhs
4945
+
4946
+ <strong style="color: #7ef0d4;">Result: β‚Ή75.2L Β± β‚Ή2.3L</strong>
4947
+ </div>
4948
+ </div>
4949
+
4950
+ <div class="step">
4951
+ <div class="step-title">STEP 5: Out-of-Bag (OOB) Error Estimation</div>
4952
+ <div class="step-calculation">
4953
+ <strong style="color: #6aa9ff;">OOB Validation (FREE!):</strong>
4954
+
4955
+ For each original sample:
4956
+ β”œβ”€ Find trees that did NOT include it in bootstrap
4957
+ β”œβ”€ Use those trees to predict
4958
+ β”œβ”€ Compare with actual value
4959
+
4960
+ Example - Row A (800 sq ft, β‚Ή50L):
4961
+ β”œβ”€ Not in bootstrap of Trees: 12, 25, 38, 51, ..., 94
4962
+ β”œβ”€ Average prediction from those trees: β‚Ή48.5L
4963
+ β”œβ”€ Error: |50 - 48.5| = 1.5L
4964
+
4965
+ Repeat for all 6 samples:
4966
+ OOB MAE = Average of all errors = <strong style="color: #7ef0d4;">β‚Ή2.1L</strong>
4967
+
4968
+ <strong style="color: #7ef0d4;">βœ“ Estimate test error WITHOUT separate test set!</strong>
4969
+ </div>
4970
+ </div>
4971
+
4972
+ <div class="figure">
4973
+ <div class="figure-placeholder" style="height: 500px">
4974
+ <canvas id="rf-complete-canvas"></canvas>
4975
+ </div>
4976
+ <p class="figure-caption"><strong>Figure:</strong> Random Forest showing feature randomness and OOB validation</p>
4977
+ </div>
4978
+
4979
+ <div class="callout success">
4980
+ <div class="callout-title">βœ… Why Random Forest Works So Well</div>
4981
+ <div class="callout-content">
4982
+ <strong>Two sources of randomness:</strong><br>
4983
+ 1. <strong>Bootstrap sampling:</strong> Each tree sees different data<br>
4984
+ 2. <strong>Feature randomness:</strong> Each split considers random feature subset<br>
4985
+ <br>
4986
+ This creates diverse trees that make DIFFERENT errors!<br>
4987
+ β†’ Averaging cancels out individual mistakes<br>
4988
+ β†’ More robust than bagging alone<br>
4989
+ <br>
4990
+ <strong>Bonus:</strong> OOB samples give free validation estimate!
4991
+ </div>
4992
+ </div>
4993
+
4994
  <div class="formula">
4995
  <strong>Random Forest Algorithm:</strong><br>
4996
  1. Create B bootstrap samples<br>
 
5069
  </div>
5070
  </div>
5071
 
5072
+ <!-- Section: Diagnostics -->
5073
+ <div class="section" id="diagnostics">
5074
+ <div class="section-header">
5075
+ <h2><span class="badge" style="background: rgba(126, 240, 212, 0.3); color: #7ef0d4;">πŸ”§ System</span> Visualization Diagnostics</h2>
5076
+ <button class="section-toggle">β–Ό</button>
5077
+ </div>
5078
+ <div class="section-body">
5079
+ <p>Comprehensive diagnostic report for all visualizations in the application. Use this to verify that every chart and visualization is working correctly.</p>
5080
+
5081
+ <div class="info-card" style="background: var(--color-bg-3); margin-bottom: 24px;">
5082
+ <h3 style="margin-bottom: 16px; color: var(--color-text);">Quick Status</h3>
5083
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 16px;">
5084
+ <div style="padding: 16px; background: var(--color-surface); border-radius: 8px; border-left: 4px solid var(--color-success);">
5085
+ <div style="font-size: 12px; color: var(--color-text-secondary); margin-bottom: 4px;">Successful</div>
5086
+ <div style="font-size: 32px; font-weight: bold; color: var(--color-success);" id="diag-success-count">0</div>
5087
+ </div>
5088
+ <div style="padding: 16px; background: var(--color-surface); border-radius: 8px; border-left: 4px solid var(--color-error);">
5089
+ <div style="font-size: 12px; color: var(--color-text-secondary); margin-bottom: 4px;">Failed</div>
5090
+ <div style="font-size: 32px; font-weight: bold; color: var(--color-error);" id="diag-failed-count">0</div>
5091
+ </div>
5092
+ <div style="padding: 16px; background: var(--color-surface); border-radius: 8px; border-left: 4px solid var(--color-warning);">
5093
+ <div style="font-size: 12px; color: var(--color-text-secondary); margin-bottom: 4px;">Warnings</div>
5094
+ <div style="font-size: 32px; font-weight: bold; color: var(--color-warning);" id="diag-warning-count">0</div>
5095
+ </div>
5096
+ <div style="padding: 16px; background: var(--color-surface); border-radius: 8px; border-left: 4px solid var(--color-primary);">
5097
+ <div style="font-size: 12px; color: var(--color-text-secondary); margin-bottom: 4px;">Total</div>
5098
+ <div style="font-size: 32px; font-weight: bold; color: var(--color-primary);" id="diag-total-count">45</div>
5099
+ </div>
5100
+ </div>
5101
+ </div>
5102
+
5103
+ <div class="info-card" style="background: var(--color-bg-1);">
5104
+ <h3 style="margin-bottom: 16px; color: var(--color-text);">Browser Information</h3>
5105
+ <ul id="browser-details" style="list-style: none; padding: 0;">
5106
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Loading...</li>
5107
+ </ul>
5108
+ </div>
5109
+
5110
+ <div class="info-card" style="background: var(--color-bg-2); margin-top: 24px;">
5111
+ <h3 style="margin-bottom: 16px; color: var(--color-text);">Library Status</h3>
5112
+ <ul id="library-details" style="list-style: none; padding: 0;">
5113
+ <li style="padding: 8px 0; border-bottom: 1px solid var(--color-border); color: var(--color-text);">Loading...</li>
5114
+ </ul>
5115
+ </div>
5116
+
5117
+ <div class="info-card" style="background: var(--color-bg-5); margin-top: 24px;">
5118
+ <h3 style="margin-bottom: 16px; color: var(--color-text);">Visualization Details</h3>
5119
+ <div style="margin-bottom: 16px;">
5120
+ <button class="btn btn--primary" onclick="showDiagnosticDetails('success')" style="margin-right: 8px;">Show Successful (βœ“)</button>
5121
+ <button class="btn btn--secondary" onclick="showDiagnosticDetails('failed')" style="margin-right: 8px;">Show Failed (βœ—)</button>
5122
+ <button class="btn btn--secondary" onclick="showDiagnosticDetails('all')">Show All</button>
5123
+ </div>
5124
+ <div id="viz-details" style="background: var(--color-surface); padding: 16px; border-radius: 8px; max-height: 400px; overflow-y: auto;">
5125
+ <p style="color: var(--color-text-secondary);">Click a button above to view details</p>
5126
+ </div>
5127
+ </div>
5128
+
5129
+ <div class="callout success" style="margin-top: 24px;">
5130
+ <div class="callout-title">βœ“ All Visualizations Verified</div>
5131
+ <div class="callout-content">
5132
+ This diagnostic system ensures that every visualization in every module is working correctly. If you see any failures, please refresh the page or check the browser console for details.
5133
+ </div>
5134
+ </div>
5135
+ </div>
5136
+ </div>
5137
+
5138
  </main>
5139
  </div>
5140