Spaces:
Running
Running
Commit ·
0751fec
1
Parent(s): 6782452
update files
Browse files- ml_complete-all-topics/app.js +801 -221
- ml_complete-all-topics/index.html +458 -13
ml_complete-all-topics/app.js
CHANGED
|
@@ -107,8 +107,10 @@ function initSections() {
|
|
| 107 |
if (section.id === 'optimal-k') initOptimalK();
|
| 108 |
if (section.id === 'hyperparameter-tuning') initHyperparameterTuning();
|
| 109 |
if (section.id === 'naive-bayes') initNaiveBayes();
|
|
|
|
| 110 |
if (section.id === 'decision-trees') initDecisionTrees();
|
| 111 |
if (section.id === 'ensemble-methods') initEnsembleMethods();
|
|
|
|
| 112 |
}
|
| 113 |
});
|
| 114 |
});
|
|
@@ -204,82 +206,24 @@ function initLinearRegression() {
|
|
| 204 |
drawLinearRegression();
|
| 205 |
}
|
| 206 |
|
|
|
|
|
|
|
| 207 |
function drawLinearRegression() {
|
| 208 |
const canvas = document.getElementById('lr-canvas');
|
| 209 |
if (!canvas) return;
|
| 210 |
|
| 211 |
-
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
|
| 215 |
-
ctx.clearRect(0, 0, width, height);
|
| 216 |
-
|
| 217 |
-
const padding = 60;
|
| 218 |
-
const chartWidth = width - 2 * padding;
|
| 219 |
-
const chartHeight = height - 2 * padding;
|
| 220 |
-
|
| 221 |
-
const xMin = 0, xMax = 7;
|
| 222 |
-
const yMin = 0, yMax = 100;
|
| 223 |
-
|
| 224 |
-
// Draw axes
|
| 225 |
-
ctx.strokeStyle = '#2a3544';
|
| 226 |
-
ctx.lineWidth = 2;
|
| 227 |
-
ctx.beginPath();
|
| 228 |
-
ctx.moveTo(padding, padding);
|
| 229 |
-
ctx.lineTo(padding, height - padding);
|
| 230 |
-
ctx.lineTo(width - padding, height - padding);
|
| 231 |
-
ctx.stroke();
|
| 232 |
-
|
| 233 |
-
// Grid
|
| 234 |
-
ctx.strokeStyle = 'rgba(42, 53, 68, 0.3)';
|
| 235 |
-
ctx.lineWidth = 1;
|
| 236 |
-
for (let i = 0; i <= 5; i++) {
|
| 237 |
-
const x = padding + (chartWidth / 5) * i;
|
| 238 |
-
ctx.beginPath();
|
| 239 |
-
ctx.moveTo(x, padding);
|
| 240 |
-
ctx.lineTo(x, height - padding);
|
| 241 |
-
ctx.stroke();
|
| 242 |
-
|
| 243 |
-
const y = height - padding - (chartHeight / 5) * i;
|
| 244 |
-
ctx.beginPath();
|
| 245 |
-
ctx.moveTo(padding, y);
|
| 246 |
-
ctx.lineTo(width - padding, y);
|
| 247 |
-
ctx.stroke();
|
| 248 |
}
|
| 249 |
|
| 250 |
-
const
|
| 251 |
-
const scaleY = (y) => height - padding - ((y - yMin) / (yMax - yMin)) * chartHeight;
|
| 252 |
-
|
| 253 |
-
// Draw data points
|
| 254 |
-
ctx.fillStyle = '#6aa9ff';
|
| 255 |
-
data.linearRegression.forEach(point => {
|
| 256 |
-
const x = scaleX(point.experience);
|
| 257 |
-
const y = scaleY(point.salary);
|
| 258 |
-
ctx.beginPath();
|
| 259 |
-
ctx.arc(x, y, 6, 0, 2 * Math.PI);
|
| 260 |
-
ctx.fill();
|
| 261 |
-
});
|
| 262 |
-
|
| 263 |
-
// Draw regression line
|
| 264 |
-
ctx.strokeStyle = '#ff8c6a';
|
| 265 |
-
ctx.lineWidth = 3;
|
| 266 |
-
ctx.beginPath();
|
| 267 |
-
const y1 = state.slope * xMin + state.intercept;
|
| 268 |
-
const y2 = state.slope * xMax + state.intercept;
|
| 269 |
-
ctx.moveTo(scaleX(xMin), scaleY(y1));
|
| 270 |
-
ctx.lineTo(scaleX(xMax), scaleY(y2));
|
| 271 |
-
ctx.stroke();
|
| 272 |
|
| 273 |
-
//
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
| 278 |
-
ctx.save();
|
| 279 |
-
ctx.translate(20, height / 2);
|
| 280 |
-
ctx.rotate(-Math.PI / 2);
|
| 281 |
-
ctx.fillText('Salary ($k)', 0, 0);
|
| 282 |
-
ctx.restore();
|
| 283 |
|
| 284 |
// Calculate MSE
|
| 285 |
let mse = 0;
|
|
@@ -290,11 +234,57 @@ function drawLinearRegression() {
|
|
| 290 |
});
|
| 291 |
mse /= data.linearRegression.length;
|
| 292 |
|
| 293 |
-
|
| 294 |
-
|
| 295 |
-
|
| 296 |
-
|
| 297 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 298 |
}
|
| 299 |
|
| 300 |
// Gradient Descent Visualization
|
|
@@ -386,87 +376,73 @@ function animateGradientDescent() {
|
|
| 386 |
}, 50);
|
| 387 |
}
|
| 388 |
|
|
|
|
|
|
|
| 389 |
function drawGradientDescent(currentStep = -1) {
|
| 390 |
const canvas = document.getElementById('gd-canvas');
|
| 391 |
if (!canvas) return;
|
| 392 |
|
| 393 |
-
const ctx = canvas.getContext('2d');
|
| 394 |
-
const width = canvas.width = canvas.offsetWidth;
|
| 395 |
-
const height = canvas.height = 400;
|
| 396 |
-
|
| 397 |
-
ctx.clearRect(0, 0, width, height);
|
| 398 |
-
|
| 399 |
if (state.gdIterations.length === 0) {
|
|
|
|
|
|
|
| 400 |
ctx.fillStyle = '#a9b4c2';
|
| 401 |
ctx.font = '16px sans-serif';
|
| 402 |
ctx.textAlign = 'center';
|
| 403 |
-
ctx.fillText('Click "Run Gradient Descent" to see the algorithm in action', width / 2, height / 2);
|
| 404 |
return;
|
| 405 |
}
|
| 406 |
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
const maxLoss = Math.max(...state.gdIterations.map(i => i.loss));
|
| 412 |
-
const minLoss = Math.min(...state.gdIterations.map(i => i.loss));
|
| 413 |
-
|
| 414 |
-
// Draw axes
|
| 415 |
-
ctx.strokeStyle = '#2a3544';
|
| 416 |
-
ctx.lineWidth = 2;
|
| 417 |
-
ctx.beginPath();
|
| 418 |
-
ctx.moveTo(padding, padding);
|
| 419 |
-
ctx.lineTo(padding, height - padding);
|
| 420 |
-
ctx.lineTo(width - padding, height - padding);
|
| 421 |
-
ctx.stroke();
|
| 422 |
-
|
| 423 |
-
const scaleX = (i) => padding + (i / (state.gdIterations.length - 1)) * chartWidth;
|
| 424 |
-
const scaleY = (loss) => height - padding - ((loss - minLoss) / (maxLoss - minLoss)) * chartHeight;
|
| 425 |
|
| 426 |
-
|
| 427 |
-
|
| 428 |
-
|
| 429 |
-
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
|
| 433 |
-
|
| 434 |
-
|
| 435 |
-
|
| 436 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 437 |
}
|
| 438 |
});
|
| 439 |
-
ctx.stroke();
|
| 440 |
-
|
| 441 |
-
// Highlight current step
|
| 442 |
-
if (currentStep >= 0 && currentStep < state.gdIterations.length) {
|
| 443 |
-
const iter = state.gdIterations[currentStep];
|
| 444 |
-
const x = scaleX(currentStep);
|
| 445 |
-
const y = scaleY(iter.loss);
|
| 446 |
-
|
| 447 |
-
ctx.fillStyle = '#ff8c6a';
|
| 448 |
-
ctx.beginPath();
|
| 449 |
-
ctx.arc(x, y, 6, 0, 2 * Math.PI);
|
| 450 |
-
ctx.fill();
|
| 451 |
-
|
| 452 |
-
// Display current values
|
| 453 |
-
ctx.fillStyle = '#e8eef6';
|
| 454 |
-
ctx.font = '12px sans-serif';
|
| 455 |
-
ctx.textAlign = 'left';
|
| 456 |
-
ctx.fillText(`Step: ${currentStep + 1}`, padding + 10, padding + 20);
|
| 457 |
-
ctx.fillText(`Loss: ${iter.loss.toFixed(2)}`, padding + 10, padding + 40);
|
| 458 |
-
}
|
| 459 |
-
|
| 460 |
-
// Labels
|
| 461 |
-
ctx.fillStyle = '#a9b4c2';
|
| 462 |
-
ctx.font = '12px sans-serif';
|
| 463 |
-
ctx.textAlign = 'center';
|
| 464 |
-
ctx.fillText('Iterations', width / 2, height - 20);
|
| 465 |
-
ctx.save();
|
| 466 |
-
ctx.translate(20, height / 2);
|
| 467 |
-
ctx.rotate(-Math.PI / 2);
|
| 468 |
-
ctx.fillText('Loss (MSE)', 0, 0);
|
| 469 |
-
ctx.restore();
|
| 470 |
}
|
| 471 |
|
| 472 |
// Initialize everything when DOM is ready
|
|
@@ -766,10 +742,17 @@ function initSVMCParameter() {
|
|
| 766 |
drawSVMCParameter();
|
| 767 |
}
|
| 768 |
|
|
|
|
|
|
|
| 769 |
function drawSVMCParameter() {
|
| 770 |
const canvas = document.getElementById('svm-c-canvas');
|
| 771 |
if (!canvas) return;
|
| 772 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 773 |
const ctx = canvas.getContext('2d');
|
| 774 |
const width = canvas.width = canvas.offsetWidth;
|
| 775 |
const height = canvas.height = 450;
|
|
@@ -852,8 +835,10 @@ function drawSVMCParameter() {
|
|
| 852 |
// Update info
|
| 853 |
const wNorm = Math.sqrt(w1 * w1 + w2 * w2);
|
| 854 |
const marginWidth = 2 / wNorm;
|
| 855 |
-
document.getElementById('margin-width')
|
| 856 |
-
document.getElementById('violations-count')
|
|
|
|
|
|
|
| 857 |
}
|
| 858 |
|
| 859 |
function initSVMTraining() {
|
|
@@ -1009,6 +994,8 @@ function drawSVMTraining() {
|
|
| 1009 |
});
|
| 1010 |
}
|
| 1011 |
|
|
|
|
|
|
|
| 1012 |
function initSVMKernel() {
|
| 1013 |
const canvas = document.getElementById('svm-kernel-canvas');
|
| 1014 |
if (!canvas || canvas.dataset.initialized) return;
|
|
@@ -1030,7 +1017,8 @@ function initSVMKernel() {
|
|
| 1030 |
if (paramSlider) {
|
| 1031 |
paramSlider.addEventListener('input', (e) => {
|
| 1032 |
state.svm.kernelParam = parseFloat(e.target.value);
|
| 1033 |
-
document.getElementById('kernel-param-val')
|
|
|
|
| 1034 |
drawSVMKernel();
|
| 1035 |
});
|
| 1036 |
}
|
|
@@ -2357,6 +2345,9 @@ function drawLossCurves() {
|
|
| 2357 |
}
|
| 2358 |
|
| 2359 |
// Topic 13: Finding Optimal K in KNN
|
|
|
|
|
|
|
|
|
|
| 2360 |
function initOptimalK() {
|
| 2361 |
const canvas1 = document.getElementById('elbow-canvas');
|
| 2362 |
if (canvas1 && !canvas1.dataset.initialized) {
|
|
@@ -2404,57 +2395,72 @@ function drawElbowCurve() {
|
|
| 2404 |
ctx.lineTo(width - padding, height - padding);
|
| 2405 |
ctx.stroke();
|
| 2406 |
|
| 2407 |
-
//
|
| 2408 |
-
|
| 2409 |
-
|
| 2410 |
-
|
| 2411 |
-
kValues.forEach((k, i) => {
|
| 2412 |
-
const x = scaleX(k);
|
| 2413 |
-
const y = scaleY(accuracies[i]);
|
| 2414 |
-
if (i === 0) ctx.moveTo(x, y);
|
| 2415 |
-
else ctx.lineTo(x, y);
|
| 2416 |
-
});
|
| 2417 |
-
ctx.stroke();
|
| 2418 |
|
| 2419 |
-
//
|
| 2420 |
-
|
| 2421 |
-
|
| 2422 |
-
|
| 2423 |
-
|
| 2424 |
-
|
| 2425 |
-
|
| 2426 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2427 |
});
|
| 2428 |
-
|
| 2429 |
-
// Highlight optimal K
|
| 2430 |
-
const optX = scaleX(optimalK);
|
| 2431 |
-
const optY = scaleY(accuracies[optimalK - 1]);
|
| 2432 |
-
ctx.strokeStyle = '#7ef0d4';
|
| 2433 |
-
ctx.lineWidth = 2;
|
| 2434 |
-
ctx.setLineDash([5, 5]);
|
| 2435 |
-
ctx.beginPath();
|
| 2436 |
-
ctx.moveTo(optX, optY);
|
| 2437 |
-
ctx.lineTo(optX, height - padding);
|
| 2438 |
-
ctx.stroke();
|
| 2439 |
-
ctx.setLineDash([]);
|
| 2440 |
-
|
| 2441 |
-
// Labels
|
| 2442 |
-
ctx.fillStyle = '#a9b4c2';
|
| 2443 |
-
ctx.font = '12px sans-serif';
|
| 2444 |
-
ctx.textAlign = 'center';
|
| 2445 |
-
ctx.fillText('K (Number of Neighbors)', width / 2, height - 20);
|
| 2446 |
-
ctx.save();
|
| 2447 |
-
ctx.translate(20, height / 2);
|
| 2448 |
-
ctx.rotate(-Math.PI / 2);
|
| 2449 |
-
ctx.fillText('Accuracy', 0, 0);
|
| 2450 |
-
ctx.restore();
|
| 2451 |
-
|
| 2452 |
-
// Optimal K label
|
| 2453 |
-
ctx.fillStyle = '#7ef0d4';
|
| 2454 |
-
ctx.font = 'bold 14px sans-serif';
|
| 2455 |
-
ctx.textAlign = 'center';
|
| 2456 |
-
ctx.fillText(`Optimal K = ${optimalK}`, optX, padding + 30);
|
| 2457 |
-
ctx.fillText(`Accuracy: ${accuracies[optimalK - 1].toFixed(2)}`, optX, padding + 50);
|
| 2458 |
}
|
| 2459 |
|
| 2460 |
function drawCVKHeatmap() {
|
|
@@ -2541,6 +2547,8 @@ function drawCVKHeatmap() {
|
|
| 2541 |
}
|
| 2542 |
|
| 2543 |
// Topic 14: Hyperparameter Tuning
|
|
|
|
|
|
|
| 2544 |
function initHyperparameterTuning() {
|
| 2545 |
const canvas1 = document.getElementById('gridsearch-heatmap');
|
| 2546 |
if (canvas1 && !canvas1.dataset.initialized) {
|
|
@@ -2566,6 +2574,11 @@ function drawGridSearchHeatmap() {
|
|
| 2566 |
const canvas = document.getElementById('gridsearch-heatmap');
|
| 2567 |
if (!canvas) return;
|
| 2568 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2569 |
const ctx = canvas.getContext('2d');
|
| 2570 |
const width = canvas.width = canvas.offsetWidth;
|
| 2571 |
const height = canvas.height = 450;
|
|
@@ -2660,7 +2673,24 @@ function drawGridSearchHeatmap() {
|
|
| 2660 |
ctx.fillText('Gamma Parameter', 0, 0);
|
| 2661 |
ctx.restore();
|
| 2662 |
|
| 2663 |
-
// Best params
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2664 |
ctx.fillStyle = '#7ef0d4';
|
| 2665 |
ctx.font = 'bold 14px sans-serif';
|
| 2666 |
ctx.textAlign = 'left';
|
|
@@ -2731,6 +2761,10 @@ function drawParamSurface() {
|
|
| 2731 |
}
|
| 2732 |
|
| 2733 |
// Topic 15: Naive Bayes
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2734 |
function initNaiveBayes() {
|
| 2735 |
const canvas1 = document.getElementById('bayes-theorem-viz');
|
| 2736 |
if (canvas1 && !canvas1.dataset.initialized) {
|
|
@@ -2743,6 +2777,18 @@ function initNaiveBayes() {
|
|
| 2743 |
canvas2.dataset.initialized = 'true';
|
| 2744 |
drawSpamClassification();
|
| 2745 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2746 |
}
|
| 2747 |
|
| 2748 |
function drawBayesTheorem() {
|
|
@@ -2799,6 +2845,183 @@ function drawBayesTheorem() {
|
|
| 2799 |
ctx.fillText("Bayes' Theorem Breakdown", centerX, 40);
|
| 2800 |
}
|
| 2801 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2802 |
function drawSpamClassification() {
|
| 2803 |
const canvas = document.getElementById('spam-classification');
|
| 2804 |
if (!canvas) return;
|
|
@@ -2859,20 +3082,52 @@ function drawSpamClassification() {
|
|
| 2859 |
ctx.font = 'bold 18px sans-serif';
|
| 2860 |
ctx.fillText('→ SPAM! 📧❌', padding, y4 + 30);
|
| 2861 |
|
| 2862 |
-
//
|
| 2863 |
-
|
| 2864 |
-
|
| 2865 |
-
|
| 2866 |
-
|
| 2867 |
-
|
| 2868 |
-
|
| 2869 |
-
|
| 2870 |
-
|
| 2871 |
-
|
| 2872 |
-
|
| 2873 |
-
|
| 2874 |
-
|
| 2875 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2876 |
}
|
| 2877 |
|
| 2878 |
// Topic 16: Decision Trees
|
|
@@ -3552,6 +3807,326 @@ function drawRandomForestViz() {
|
|
| 3552 |
ctx.fillText('Random Forest: Ensemble of Decision Trees', width / 2, 25);
|
| 3553 |
}
|
| 3554 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3555 |
// Handle window resize
|
| 3556 |
let resizeTimer;
|
| 3557 |
window.addEventListener('resize', () => {
|
|
@@ -3579,18 +4154,23 @@ window.addEventListener('resize', () => {
|
|
| 3579 |
drawSVMTraining();
|
| 3580 |
drawSVMKernel();
|
| 3581 |
// New topics
|
| 3582 |
-
drawElbowCurve();
|
| 3583 |
-
drawCVKHeatmap();
|
| 3584 |
-
drawGridSearchHeatmap();
|
| 3585 |
-
drawParamSurface();
|
| 3586 |
-
drawBayesTheorem();
|
| 3587 |
-
drawSpamClassification();
|
| 3588 |
-
drawDecisionTree();
|
| 3589 |
-
drawEntropyViz();
|
| 3590 |
-
drawSplitComparison();
|
| 3591 |
-
drawTreeBoundary();
|
| 3592 |
-
drawBaggingViz();
|
| 3593 |
-
drawBoostingViz();
|
| 3594 |
-
drawRandomForestViz();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3595 |
}, 250);
|
| 3596 |
});
|
|
|
|
| 107 |
if (section.id === 'optimal-k') initOptimalK();
|
| 108 |
if (section.id === 'hyperparameter-tuning') initHyperparameterTuning();
|
| 109 |
if (section.id === 'naive-bayes') initNaiveBayes();
|
| 110 |
+
if (section.id === 'kmeans') initKMeans();
|
| 111 |
if (section.id === 'decision-trees') initDecisionTrees();
|
| 112 |
if (section.id === 'ensemble-methods') initEnsembleMethods();
|
| 113 |
+
if (section.id === 'algorithm-comparison') initAlgorithmComparison();
|
| 114 |
}
|
| 115 |
});
|
| 116 |
});
|
|
|
|
| 206 |
drawLinearRegression();
|
| 207 |
}
|
| 208 |
|
| 209 |
+
let lrChart = null;
|
| 210 |
+
|
| 211 |
function drawLinearRegression() {
|
| 212 |
const canvas = document.getElementById('lr-canvas');
|
| 213 |
if (!canvas) return;
|
| 214 |
|
| 215 |
+
// Destroy existing chart
|
| 216 |
+
if (lrChart) {
|
| 217 |
+
lrChart.destroy();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 218 |
}
|
| 219 |
|
| 220 |
+
const ctx = canvas.getContext('2d');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 221 |
|
| 222 |
+
// Calculate fitted line points
|
| 223 |
+
const fittedLine = [];
|
| 224 |
+
for (let x = 0; x <= 7; x += 0.1) {
|
| 225 |
+
fittedLine.push({ x: x, y: state.slope * x + state.intercept });
|
| 226 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 227 |
|
| 228 |
// Calculate MSE
|
| 229 |
let mse = 0;
|
|
|
|
| 234 |
});
|
| 235 |
mse /= data.linearRegression.length;
|
| 236 |
|
| 237 |
+
lrChart = new Chart(ctx, {
|
| 238 |
+
type: 'scatter',
|
| 239 |
+
data: {
|
| 240 |
+
datasets: [
|
| 241 |
+
{
|
| 242 |
+
label: 'Data Points',
|
| 243 |
+
data: data.linearRegression.map(p => ({ x: p.experience, y: p.salary })),
|
| 244 |
+
backgroundColor: '#6aa9ff',
|
| 245 |
+
pointRadius: 8,
|
| 246 |
+
pointHoverRadius: 10
|
| 247 |
+
},
|
| 248 |
+
{
|
| 249 |
+
label: 'Fitted Line',
|
| 250 |
+
data: fittedLine,
|
| 251 |
+
type: 'line',
|
| 252 |
+
borderColor: '#ff8c6a',
|
| 253 |
+
borderWidth: 3,
|
| 254 |
+
fill: false,
|
| 255 |
+
pointRadius: 0,
|
| 256 |
+
tension: 0
|
| 257 |
+
}
|
| 258 |
+
]
|
| 259 |
+
},
|
| 260 |
+
options: {
|
| 261 |
+
responsive: true,
|
| 262 |
+
maintainAspectRatio: false,
|
| 263 |
+
plugins: {
|
| 264 |
+
title: {
|
| 265 |
+
display: true,
|
| 266 |
+
text: `Experience vs Salary (MSE: ${mse.toFixed(2)})`,
|
| 267 |
+
color: '#e8eef6',
|
| 268 |
+
font: { size: 16 }
|
| 269 |
+
},
|
| 270 |
+
legend: {
|
| 271 |
+
labels: { color: '#a9b4c2' }
|
| 272 |
+
}
|
| 273 |
+
},
|
| 274 |
+
scales: {
|
| 275 |
+
x: {
|
| 276 |
+
title: { display: true, text: 'Years of Experience', color: '#a9b4c2' },
|
| 277 |
+
grid: { color: '#2a3544' },
|
| 278 |
+
ticks: { color: '#a9b4c2' }
|
| 279 |
+
},
|
| 280 |
+
y: {
|
| 281 |
+
title: { display: true, text: 'Salary ($k)', color: '#a9b4c2' },
|
| 282 |
+
grid: { color: '#2a3544' },
|
| 283 |
+
ticks: { color: '#a9b4c2' }
|
| 284 |
+
}
|
| 285 |
+
}
|
| 286 |
+
}
|
| 287 |
+
});
|
| 288 |
}
|
| 289 |
|
| 290 |
// Gradient Descent Visualization
|
|
|
|
| 376 |
}, 50);
|
| 377 |
}
|
| 378 |
|
| 379 |
+
let gdChart = null;
|
| 380 |
+
|
| 381 |
function drawGradientDescent(currentStep = -1) {
|
| 382 |
const canvas = document.getElementById('gd-canvas');
|
| 383 |
if (!canvas) return;
|
| 384 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 385 |
if (state.gdIterations.length === 0) {
|
| 386 |
+
const ctx = canvas.getContext('2d');
|
| 387 |
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
| 388 |
ctx.fillStyle = '#a9b4c2';
|
| 389 |
ctx.font = '16px sans-serif';
|
| 390 |
ctx.textAlign = 'center';
|
| 391 |
+
ctx.fillText('Click "Run Gradient Descent" to see the algorithm in action', canvas.width / 2, canvas.height / 2);
|
| 392 |
return;
|
| 393 |
}
|
| 394 |
|
| 395 |
+
// Destroy existing chart
|
| 396 |
+
if (gdChart) {
|
| 397 |
+
gdChart.destroy();
|
| 398 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 399 |
|
| 400 |
+
const ctx = canvas.getContext('2d');
|
| 401 |
+
const lossData = state.gdIterations.map((iter, i) => ({ x: i + 1, y: iter.loss }));
|
| 402 |
+
|
| 403 |
+
gdChart = new Chart(ctx, {
|
| 404 |
+
type: 'line',
|
| 405 |
+
data: {
|
| 406 |
+
datasets: [{
|
| 407 |
+
label: 'Training Loss',
|
| 408 |
+
data: lossData,
|
| 409 |
+
borderColor: '#7ef0d4',
|
| 410 |
+
backgroundColor: 'rgba(126, 240, 212, 0.1)',
|
| 411 |
+
borderWidth: 3,
|
| 412 |
+
fill: true,
|
| 413 |
+
tension: 0.4,
|
| 414 |
+
pointRadius: currentStep >= 0 ? lossData.map((_, i) => i === currentStep ? 8 : 2) : 4,
|
| 415 |
+
pointBackgroundColor: currentStep >= 0 ? lossData.map((_, i) => i === currentStep ? '#ff8c6a' : '#7ef0d4') : '#7ef0d4'
|
| 416 |
+
}]
|
| 417 |
+
},
|
| 418 |
+
options: {
|
| 419 |
+
responsive: true,
|
| 420 |
+
maintainAspectRatio: false,
|
| 421 |
+
plugins: {
|
| 422 |
+
title: {
|
| 423 |
+
display: true,
|
| 424 |
+
text: currentStep >= 0 ? `Gradient Descent Progress (Step ${currentStep + 1}/${state.gdIterations.length})` : 'Gradient Descent Progress',
|
| 425 |
+
color: '#e8eef6',
|
| 426 |
+
font: { size: 16 }
|
| 427 |
+
},
|
| 428 |
+
legend: {
|
| 429 |
+
labels: { color: '#a9b4c2' }
|
| 430 |
+
}
|
| 431 |
+
},
|
| 432 |
+
scales: {
|
| 433 |
+
x: {
|
| 434 |
+
title: { display: true, text: 'Iterations', color: '#a9b4c2' },
|
| 435 |
+
grid: { color: '#2a3544' },
|
| 436 |
+
ticks: { color: '#a9b4c2' }
|
| 437 |
+
},
|
| 438 |
+
y: {
|
| 439 |
+
title: { display: true, text: 'Loss (MSE)', color: '#a9b4c2' },
|
| 440 |
+
grid: { color: '#2a3544' },
|
| 441 |
+
ticks: { color: '#a9b4c2' }
|
| 442 |
+
}
|
| 443 |
+
}
|
| 444 |
}
|
| 445 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 446 |
}
|
| 447 |
|
| 448 |
// Initialize everything when DOM is ready
|
|
|
|
| 742 |
drawSVMCParameter();
|
| 743 |
}
|
| 744 |
|
| 745 |
+
let svmCChart = null;
|
| 746 |
+
|
| 747 |
function drawSVMCParameter() {
|
| 748 |
const canvas = document.getElementById('svm-c-canvas');
|
| 749 |
if (!canvas) return;
|
| 750 |
|
| 751 |
+
// Destroy existing chart
|
| 752 |
+
if (svmCChart) {
|
| 753 |
+
svmCChart.destroy();
|
| 754 |
+
}
|
| 755 |
+
|
| 756 |
const ctx = canvas.getContext('2d');
|
| 757 |
const width = canvas.width = canvas.offsetWidth;
|
| 758 |
const height = canvas.height = 450;
|
|
|
|
| 835 |
// Update info
|
| 836 |
const wNorm = Math.sqrt(w1 * w1 + w2 * w2);
|
| 837 |
const marginWidth = 2 / wNorm;
|
| 838 |
+
const marginEl = document.getElementById('margin-width');
|
| 839 |
+
const violEl = document.getElementById('violations-count');
|
| 840 |
+
if (marginEl) marginEl.textContent = marginWidth.toFixed(2);
|
| 841 |
+
if (violEl) violEl.textContent = violations;
|
| 842 |
}
|
| 843 |
|
| 844 |
function initSVMTraining() {
|
|
|
|
| 994 |
});
|
| 995 |
}
|
| 996 |
|
| 997 |
+
let svmKernelChart = null;
|
| 998 |
+
|
| 999 |
function initSVMKernel() {
|
| 1000 |
const canvas = document.getElementById('svm-kernel-canvas');
|
| 1001 |
if (!canvas || canvas.dataset.initialized) return;
|
|
|
|
| 1017 |
if (paramSlider) {
|
| 1018 |
paramSlider.addEventListener('input', (e) => {
|
| 1019 |
state.svm.kernelParam = parseFloat(e.target.value);
|
| 1020 |
+
const paramVal = document.getElementById('kernel-param-val');
|
| 1021 |
+
if (paramVal) paramVal.textContent = state.svm.kernelParam.toFixed(1);
|
| 1022 |
drawSVMKernel();
|
| 1023 |
});
|
| 1024 |
}
|
|
|
|
| 2345 |
}
|
| 2346 |
|
| 2347 |
// Topic 13: Finding Optimal K in KNN
|
| 2348 |
+
let elbowChart = null;
|
| 2349 |
+
let cvKChart = null;
|
| 2350 |
+
|
| 2351 |
function initOptimalK() {
|
| 2352 |
const canvas1 = document.getElementById('elbow-canvas');
|
| 2353 |
if (canvas1 && !canvas1.dataset.initialized) {
|
|
|
|
| 2395 |
ctx.lineTo(width - padding, height - padding);
|
| 2396 |
ctx.stroke();
|
| 2397 |
|
| 2398 |
+
// Destroy existing chart
|
| 2399 |
+
if (elbowChart) {
|
| 2400 |
+
elbowChart.destroy();
|
| 2401 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2402 |
|
| 2403 |
+
// Use Chart.js
|
| 2404 |
+
elbowChart = new Chart(ctx, {
|
| 2405 |
+
type: 'line',
|
| 2406 |
+
data: {
|
| 2407 |
+
labels: kValues,
|
| 2408 |
+
datasets: [{
|
| 2409 |
+
label: 'Accuracy',
|
| 2410 |
+
data: accuracies,
|
| 2411 |
+
borderColor: '#6aa9ff',
|
| 2412 |
+
backgroundColor: 'rgba(106, 169, 255, 0.1)',
|
| 2413 |
+
borderWidth: 3,
|
| 2414 |
+
fill: true,
|
| 2415 |
+
tension: 0.4,
|
| 2416 |
+
pointRadius: kValues.map(k => k === optimalK ? 10 : 5),
|
| 2417 |
+
pointBackgroundColor: kValues.map(k => k === optimalK ? '#7ef0d4' : '#6aa9ff'),
|
| 2418 |
+
pointBorderColor: kValues.map(k => k === optimalK ? '#7ef0d4' : '#6aa9ff'),
|
| 2419 |
+
pointBorderWidth: kValues.map(k => k === optimalK ? 3 : 2)
|
| 2420 |
+
}]
|
| 2421 |
+
},
|
| 2422 |
+
options: {
|
| 2423 |
+
responsive: true,
|
| 2424 |
+
maintainAspectRatio: false,
|
| 2425 |
+
plugins: {
|
| 2426 |
+
title: {
|
| 2427 |
+
display: true,
|
| 2428 |
+
text: `Elbow Method: Optimal K = ${optimalK} (Accuracy: ${accuracies[optimalK - 1].toFixed(2)})`,
|
| 2429 |
+
color: '#7ef0d4',
|
| 2430 |
+
font: { size: 16, weight: 'bold' }
|
| 2431 |
+
},
|
| 2432 |
+
legend: {
|
| 2433 |
+
labels: { color: '#a9b4c2' }
|
| 2434 |
+
},
|
| 2435 |
+
annotation: {
|
| 2436 |
+
annotations: {
|
| 2437 |
+
line1: {
|
| 2438 |
+
type: 'line',
|
| 2439 |
+
xMin: optimalK,
|
| 2440 |
+
xMax: optimalK,
|
| 2441 |
+
borderColor: '#7ef0d4',
|
| 2442 |
+
borderWidth: 2,
|
| 2443 |
+
borderDash: [5, 5]
|
| 2444 |
+
}
|
| 2445 |
+
}
|
| 2446 |
+
}
|
| 2447 |
+
},
|
| 2448 |
+
scales: {
|
| 2449 |
+
x: {
|
| 2450 |
+
title: { display: true, text: 'K (Number of Neighbors)', color: '#a9b4c2' },
|
| 2451 |
+
grid: { color: '#2a3544' },
|
| 2452 |
+
ticks: { color: '#a9b4c2' }
|
| 2453 |
+
},
|
| 2454 |
+
y: {
|
| 2455 |
+
title: { display: true, text: 'Accuracy', color: '#a9b4c2' },
|
| 2456 |
+
grid: { color: '#2a3544' },
|
| 2457 |
+
ticks: { color: '#a9b4c2' },
|
| 2458 |
+
min: 0.7,
|
| 2459 |
+
max: 1.0
|
| 2460 |
+
}
|
| 2461 |
+
}
|
| 2462 |
+
}
|
| 2463 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2464 |
}
|
| 2465 |
|
| 2466 |
function drawCVKHeatmap() {
|
|
|
|
| 2547 |
}
|
| 2548 |
|
| 2549 |
// Topic 14: Hyperparameter Tuning
|
| 2550 |
+
let gridSearchChart = null;
|
| 2551 |
+
|
| 2552 |
function initHyperparameterTuning() {
|
| 2553 |
const canvas1 = document.getElementById('gridsearch-heatmap');
|
| 2554 |
if (canvas1 && !canvas1.dataset.initialized) {
|
|
|
|
| 2574 |
const canvas = document.getElementById('gridsearch-heatmap');
|
| 2575 |
if (!canvas) return;
|
| 2576 |
|
| 2577 |
+
// Destroy existing chart
|
| 2578 |
+
if (gridSearchChart) {
|
| 2579 |
+
gridSearchChart.destroy();
|
| 2580 |
+
}
|
| 2581 |
+
|
| 2582 |
const ctx = canvas.getContext('2d');
|
| 2583 |
const width = canvas.width = canvas.offsetWidth;
|
| 2584 |
const height = canvas.height = 450;
|
|
|
|
| 2673 |
ctx.fillText('Gamma Parameter', 0, 0);
|
| 2674 |
ctx.restore();
|
| 2675 |
|
| 2676 |
+
// Best params - Use Chart.js for bar comparison instead
|
| 2677 |
+
const compareData = [];
|
| 2678 |
+
cValues.forEach((c, j) => {
|
| 2679 |
+
gammaValues.forEach((g, i) => {
|
| 2680 |
+
compareData.push({
|
| 2681 |
+
c: c,
|
| 2682 |
+
gamma: g,
|
| 2683 |
+
acc: accuracies[i][j],
|
| 2684 |
+
label: `C=${c}, γ=${g}`
|
| 2685 |
+
});
|
| 2686 |
+
});
|
| 2687 |
+
});
|
| 2688 |
+
|
| 2689 |
+
// Sort and get top 5
|
| 2690 |
+
compareData.sort((a, b) => b.acc - a.acc);
|
| 2691 |
+
const top5 = compareData.slice(0, 5);
|
| 2692 |
+
|
| 2693 |
+
// Add annotation for best
|
| 2694 |
ctx.fillStyle = '#7ef0d4';
|
| 2695 |
ctx.font = 'bold 14px sans-serif';
|
| 2696 |
ctx.textAlign = 'left';
|
|
|
|
| 2761 |
}
|
| 2762 |
|
| 2763 |
// Topic 15: Naive Bayes
|
| 2764 |
+
let bayesComparisonChart = null;
|
| 2765 |
+
let categoricalNBChart = null;
|
| 2766 |
+
let gaussianNBChart = null;
|
| 2767 |
+
|
| 2768 |
function initNaiveBayes() {
|
| 2769 |
const canvas1 = document.getElementById('bayes-theorem-viz');
|
| 2770 |
if (canvas1 && !canvas1.dataset.initialized) {
|
|
|
|
| 2777 |
canvas2.dataset.initialized = 'true';
|
| 2778 |
drawSpamClassification();
|
| 2779 |
}
|
| 2780 |
+
|
| 2781 |
+
const canvas3 = document.getElementById('categorical-nb-canvas');
|
| 2782 |
+
if (canvas3 && !canvas3.dataset.initialized) {
|
| 2783 |
+
canvas3.dataset.initialized = 'true';
|
| 2784 |
+
drawCategoricalNB();
|
| 2785 |
+
}
|
| 2786 |
+
|
| 2787 |
+
const canvas4 = document.getElementById('gaussian-nb-canvas');
|
| 2788 |
+
if (canvas4 && !canvas4.dataset.initialized) {
|
| 2789 |
+
canvas4.dataset.initialized = 'true';
|
| 2790 |
+
drawGaussianNB();
|
| 2791 |
+
}
|
| 2792 |
}
|
| 2793 |
|
| 2794 |
function drawBayesTheorem() {
|
|
|
|
| 2845 |
ctx.fillText("Bayes' Theorem Breakdown", centerX, 40);
|
| 2846 |
}
|
| 2847 |
|
| 2848 |
+
function drawCategoricalNB() {
|
| 2849 |
+
const canvas = document.getElementById('categorical-nb-canvas');
|
| 2850 |
+
if (!canvas) return;
|
| 2851 |
+
|
| 2852 |
+
if (categoricalNBChart) {
|
| 2853 |
+
categoricalNBChart.destroy();
|
| 2854 |
+
}
|
| 2855 |
+
|
| 2856 |
+
const ctx = canvas.getContext('2d');
|
| 2857 |
+
|
| 2858 |
+
categoricalNBChart = new Chart(ctx, {
|
| 2859 |
+
type: 'bar',
|
| 2860 |
+
data: {
|
| 2861 |
+
labels: ['P(Yes|Rainy,Hot)', 'P(No|Rainy,Hot)'],
|
| 2862 |
+
datasets: [{
|
| 2863 |
+
label: 'Without Smoothing',
|
| 2864 |
+
data: [0.0833, 0],
|
| 2865 |
+
backgroundColor: 'rgba(255, 140, 106, 0.6)',
|
| 2866 |
+
borderColor: '#ff8c6a',
|
| 2867 |
+
borderWidth: 2
|
| 2868 |
+
}, {
|
| 2869 |
+
label: 'With Laplace Smoothing',
|
| 2870 |
+
data: [0.0818, 0.0266],
|
| 2871 |
+
backgroundColor: 'rgba(126, 240, 212, 0.6)',
|
| 2872 |
+
borderColor: '#7ef0d4',
|
| 2873 |
+
borderWidth: 2
|
| 2874 |
+
}, {
|
| 2875 |
+
label: 'Normalized Probability',
|
| 2876 |
+
data: [0.755, 0.245],
|
| 2877 |
+
backgroundColor: 'rgba(106, 169, 255, 0.8)',
|
| 2878 |
+
borderColor: '#6aa9ff',
|
| 2879 |
+
borderWidth: 2
|
| 2880 |
+
}]
|
| 2881 |
+
},
|
| 2882 |
+
options: {
|
| 2883 |
+
responsive: true,
|
| 2884 |
+
maintainAspectRatio: false,
|
| 2885 |
+
plugins: {
|
| 2886 |
+
title: {
|
| 2887 |
+
display: true,
|
| 2888 |
+
text: 'Categorical Naive Bayes: Probability Comparison',
|
| 2889 |
+
color: '#e8eef6',
|
| 2890 |
+
font: { size: 16, weight: 'bold' }
|
| 2891 |
+
},
|
| 2892 |
+
legend: {
|
| 2893 |
+
labels: { color: '#a9b4c2' }
|
| 2894 |
+
}
|
| 2895 |
+
},
|
| 2896 |
+
scales: {
|
| 2897 |
+
x: {
|
| 2898 |
+
grid: { color: '#2a3544' },
|
| 2899 |
+
ticks: { color: '#a9b4c2' }
|
| 2900 |
+
},
|
| 2901 |
+
y: {
|
| 2902 |
+
title: { display: true, text: 'Probability', color: '#a9b4c2' },
|
| 2903 |
+
grid: { color: '#2a3544' },
|
| 2904 |
+
ticks: { color: '#a9b4c2' },
|
| 2905 |
+
min: 0,
|
| 2906 |
+
max: 1
|
| 2907 |
+
}
|
| 2908 |
+
}
|
| 2909 |
+
}
|
| 2910 |
+
});
|
| 2911 |
+
}
|
| 2912 |
+
|
| 2913 |
+
function drawGaussianNB() {
|
| 2914 |
+
const canvas = document.getElementById('gaussian-nb-canvas');
|
| 2915 |
+
if (!canvas) return;
|
| 2916 |
+
|
| 2917 |
+
const ctx = canvas.getContext('2d');
|
| 2918 |
+
const width = canvas.width = canvas.offsetWidth;
|
| 2919 |
+
const height = canvas.height = 400;
|
| 2920 |
+
|
| 2921 |
+
ctx.clearRect(0, 0, width, height);
|
| 2922 |
+
ctx.fillStyle = '#1a2332';
|
| 2923 |
+
ctx.fillRect(0, 0, width, height);
|
| 2924 |
+
|
| 2925 |
+
const padding = 60;
|
| 2926 |
+
const chartWidth = width - 2 * padding;
|
| 2927 |
+
const chartHeight = height - 2 * padding;
|
| 2928 |
+
|
| 2929 |
+
const xMin = 0, xMax = 5, yMin = 0, yMax = 4;
|
| 2930 |
+
const scaleX = (x) => padding + (x / xMax) * chartWidth;
|
| 2931 |
+
const scaleY = (y) => height - padding - (y / yMax) * chartHeight;
|
| 2932 |
+
|
| 2933 |
+
// Draw decision boundary (approximate)
|
| 2934 |
+
ctx.strokeStyle = '#6aa9ff';
|
| 2935 |
+
ctx.lineWidth = 3;
|
| 2936 |
+
ctx.setLineDash([5, 5]);
|
| 2937 |
+
ctx.beginPath();
|
| 2938 |
+
ctx.moveTo(scaleX(2.5), scaleY(0));
|
| 2939 |
+
ctx.lineTo(scaleX(2.5), scaleY(4));
|
| 2940 |
+
ctx.stroke();
|
| 2941 |
+
ctx.setLineDash([]);
|
| 2942 |
+
|
| 2943 |
+
// Draw "Yes" points
|
| 2944 |
+
const yesPoints = [{x: 1.0, y: 2.0}, {x: 2.0, y: 1.0}, {x: 1.5, y: 1.8}];
|
| 2945 |
+
yesPoints.forEach(p => {
|
| 2946 |
+
ctx.fillStyle = '#7ef0d4';
|
| 2947 |
+
ctx.beginPath();
|
| 2948 |
+
ctx.arc(scaleX(p.x), scaleY(p.y), 8, 0, 2 * Math.PI);
|
| 2949 |
+
ctx.fill();
|
| 2950 |
+
ctx.strokeStyle = '#1a2332';
|
| 2951 |
+
ctx.lineWidth = 2;
|
| 2952 |
+
ctx.stroke();
|
| 2953 |
+
});
|
| 2954 |
+
|
| 2955 |
+
// Draw "No" points
|
| 2956 |
+
const noPoints = [{x: 3.0, y: 3.0}, {x: 3.5, y: 2.8}, {x: 2.9, y: 3.2}];
|
| 2957 |
+
noPoints.forEach(p => {
|
| 2958 |
+
ctx.fillStyle = '#ff8c6a';
|
| 2959 |
+
ctx.beginPath();
|
| 2960 |
+
ctx.arc(scaleX(p.x), scaleY(p.y), 8, 0, 2 * Math.PI);
|
| 2961 |
+
ctx.fill();
|
| 2962 |
+
ctx.strokeStyle = '#1a2332';
|
| 2963 |
+
ctx.lineWidth = 2;
|
| 2964 |
+
ctx.stroke();
|
| 2965 |
+
});
|
| 2966 |
+
|
| 2967 |
+
// Draw test point
|
| 2968 |
+
ctx.fillStyle = '#ffeb3b';
|
| 2969 |
+
ctx.beginPath();
|
| 2970 |
+
ctx.arc(scaleX(2.0), scaleY(2.0), 12, 0, 2 * Math.PI);
|
| 2971 |
+
ctx.fill();
|
| 2972 |
+
ctx.strokeStyle = '#6aa9ff';
|
| 2973 |
+
ctx.lineWidth = 3;
|
| 2974 |
+
ctx.stroke();
|
| 2975 |
+
|
| 2976 |
+
// Label test point
|
| 2977 |
+
ctx.fillStyle = '#e8eef6';
|
| 2978 |
+
ctx.font = 'bold 12px sans-serif';
|
| 2979 |
+
ctx.textAlign = 'center';
|
| 2980 |
+
ctx.fillText('Test [2.0, 2.0]', scaleX(2.0), scaleY(2.0) - 20);
|
| 2981 |
+
ctx.fillStyle = '#7ef0d4';
|
| 2982 |
+
ctx.fillText('→ YES', scaleX(2.0), scaleY(2.0) + 30);
|
| 2983 |
+
|
| 2984 |
+
// Axes
|
| 2985 |
+
ctx.strokeStyle = '#2a3544';
|
| 2986 |
+
ctx.lineWidth = 2;
|
| 2987 |
+
ctx.beginPath();
|
| 2988 |
+
ctx.moveTo(padding, padding);
|
| 2989 |
+
ctx.lineTo(padding, height - padding);
|
| 2990 |
+
ctx.lineTo(width - padding, height - padding);
|
| 2991 |
+
ctx.stroke();
|
| 2992 |
+
|
| 2993 |
+
// Labels
|
| 2994 |
+
ctx.fillStyle = '#a9b4c2';
|
| 2995 |
+
ctx.font = '12px sans-serif';
|
| 2996 |
+
ctx.textAlign = 'center';
|
| 2997 |
+
ctx.fillText('X₁', width / 2, height - 20);
|
| 2998 |
+
ctx.save();
|
| 2999 |
+
ctx.translate(20, height / 2);
|
| 3000 |
+
ctx.rotate(-Math.PI / 2);
|
| 3001 |
+
ctx.fillText('X₂', 0, 0);
|
| 3002 |
+
ctx.restore();
|
| 3003 |
+
|
| 3004 |
+
// Legend
|
| 3005 |
+
ctx.fillStyle = '#7ef0d4';
|
| 3006 |
+
ctx.beginPath();
|
| 3007 |
+
ctx.arc(padding + 20, 30, 6, 0, 2 * Math.PI);
|
| 3008 |
+
ctx.fill();
|
| 3009 |
+
ctx.fillStyle = '#e8eef6';
|
| 3010 |
+
ctx.font = '11px sans-serif';
|
| 3011 |
+
ctx.textAlign = 'left';
|
| 3012 |
+
ctx.fillText('Class: Yes', padding + 30, 35);
|
| 3013 |
+
|
| 3014 |
+
ctx.fillStyle = '#ff8c6a';
|
| 3015 |
+
ctx.beginPath();
|
| 3016 |
+
ctx.arc(padding + 120, 30, 6, 0, 2 * Math.PI);
|
| 3017 |
+
ctx.fill();
|
| 3018 |
+
ctx.fillStyle = '#e8eef6';
|
| 3019 |
+
ctx.fillText('Class: No', padding + 130, 35);
|
| 3020 |
+
|
| 3021 |
+
ctx.fillStyle = '#6aa9ff';
|
| 3022 |
+
ctx.fillText('| Decision Boundary', padding + 210, 35);
|
| 3023 |
+
}
|
| 3024 |
+
|
| 3025 |
function drawSpamClassification() {
|
| 3026 |
const canvas = document.getElementById('spam-classification');
|
| 3027 |
if (!canvas) return;
|
|
|
|
| 3082 |
ctx.font = 'bold 18px sans-serif';
|
| 3083 |
ctx.fillText('→ SPAM! 📧❌', padding, y4 + 30);
|
| 3084 |
|
| 3085 |
+
// Create comparison chart at bottom
|
| 3086 |
+
if (!bayesComparisonChart) {
|
| 3087 |
+
const compCanvas = document.createElement('canvas');
|
| 3088 |
+
compCanvas.id = 'bayes-comparison-chart';
|
| 3089 |
+
compCanvas.style.marginTop = '20px';
|
| 3090 |
+
canvas.parentElement.appendChild(compCanvas);
|
| 3091 |
+
|
| 3092 |
+
bayesComparisonChart = new Chart(compCanvas.getContext('2d'), {
|
| 3093 |
+
type: 'bar',
|
| 3094 |
+
data: {
|
| 3095 |
+
labels: ['Spam Probability', 'Not-Spam Probability'],
|
| 3096 |
+
datasets: [{
|
| 3097 |
+
label: 'Probability',
|
| 3098 |
+
data: [0.1008, 0.0007],
|
| 3099 |
+
backgroundColor: ['#7ef0d4', '#ff8c6a'],
|
| 3100 |
+
borderColor: ['#7ef0d4', '#ff8c6a'],
|
| 3101 |
+
borderWidth: 2
|
| 3102 |
+
}]
|
| 3103 |
+
},
|
| 3104 |
+
options: {
|
| 3105 |
+
responsive: true,
|
| 3106 |
+
maintainAspectRatio: false,
|
| 3107 |
+
indexAxis: 'y',
|
| 3108 |
+
plugins: {
|
| 3109 |
+
title: {
|
| 3110 |
+
display: true,
|
| 3111 |
+
text: 'Probability Comparison',
|
| 3112 |
+
color: '#e8eef6',
|
| 3113 |
+
font: { size: 14 }
|
| 3114 |
+
},
|
| 3115 |
+
legend: { display: false }
|
| 3116 |
+
},
|
| 3117 |
+
scales: {
|
| 3118 |
+
x: {
|
| 3119 |
+
grid: { color: '#2a3544' },
|
| 3120 |
+
ticks: { color: '#a9b4c2' }
|
| 3121 |
+
},
|
| 3122 |
+
y: {
|
| 3123 |
+
grid: { display: false },
|
| 3124 |
+
ticks: { color: '#a9b4c2' }
|
| 3125 |
+
}
|
| 3126 |
+
}
|
| 3127 |
+
}
|
| 3128 |
+
});
|
| 3129 |
+
compCanvas.style.height = '150px';
|
| 3130 |
+
}
|
| 3131 |
}
|
| 3132 |
|
| 3133 |
// Topic 16: Decision Trees
|
|
|
|
| 3807 |
ctx.fillText('Random Forest: Ensemble of Decision Trees', width / 2, 25);
|
| 3808 |
}
|
| 3809 |
|
| 3810 |
+
// Topic 16: K-means Clustering
|
| 3811 |
+
let kmeansVizChart = null;
|
| 3812 |
+
let kmeansElbowChart = null;
|
| 3813 |
+
|
| 3814 |
+
function initKMeans() {
|
| 3815 |
+
const canvas1 = document.getElementById('kmeans-viz-canvas');
|
| 3816 |
+
if (canvas1 && !canvas1.dataset.initialized) {
|
| 3817 |
+
canvas1.dataset.initialized = 'true';
|
| 3818 |
+
drawKMeansVisualization();
|
| 3819 |
+
}
|
| 3820 |
+
|
| 3821 |
+
const canvas2 = document.getElementById('kmeans-elbow-canvas');
|
| 3822 |
+
if (canvas2 && !canvas2.dataset.initialized) {
|
| 3823 |
+
canvas2.dataset.initialized = 'true';
|
| 3824 |
+
drawKMeansElbow();
|
| 3825 |
+
}
|
| 3826 |
+
}
|
| 3827 |
+
|
| 3828 |
+
function drawKMeansVisualization() {
|
| 3829 |
+
const canvas = document.getElementById('kmeans-viz-canvas');
|
| 3830 |
+
if (!canvas) return;
|
| 3831 |
+
|
| 3832 |
+
const ctx = canvas.getContext('2d');
|
| 3833 |
+
const width = canvas.width = canvas.offsetWidth;
|
| 3834 |
+
const height = canvas.height = 450;
|
| 3835 |
+
|
| 3836 |
+
ctx.clearRect(0, 0, width, height);
|
| 3837 |
+
ctx.fillStyle = '#1a2332';
|
| 3838 |
+
ctx.fillRect(0, 0, width, height);
|
| 3839 |
+
|
| 3840 |
+
const padding = 60;
|
| 3841 |
+
const chartWidth = width - 2 * padding;
|
| 3842 |
+
const chartHeight = height - 2 * padding;
|
| 3843 |
+
|
| 3844 |
+
const xMin = 0, xMax = 10, yMin = 0, yMax = 12;
|
| 3845 |
+
const scaleX = (x) => padding + (x / xMax) * chartWidth;
|
| 3846 |
+
const scaleY = (y) => height - padding - (y / yMax) * chartHeight;
|
| 3847 |
+
|
| 3848 |
+
// Data points
|
| 3849 |
+
const points = [
|
| 3850 |
+
{id: 'A', x: 1, y: 2, cluster: 1},
|
| 3851 |
+
{id: 'B', x: 1.5, y: 1.8, cluster: 1},
|
| 3852 |
+
{id: 'C', x: 5, y: 8, cluster: 2},
|
| 3853 |
+
{id: 'D', x: 8, y: 8, cluster: 2},
|
| 3854 |
+
{id: 'E', x: 1, y: 0.6, cluster: 1},
|
| 3855 |
+
{id: 'F', x: 9, y: 11, cluster: 2}
|
| 3856 |
+
];
|
| 3857 |
+
|
| 3858 |
+
// Final centroids
|
| 3859 |
+
const centroids = [
|
| 3860 |
+
{x: 1.17, y: 1.47, color: '#7ef0d4'},
|
| 3861 |
+
{x: 7.33, y: 9.0, color: '#ff8c6a'}
|
| 3862 |
+
];
|
| 3863 |
+
|
| 3864 |
+
// Draw lines from points to centroids
|
| 3865 |
+
points.forEach(p => {
|
| 3866 |
+
const c = centroids[p.cluster - 1];
|
| 3867 |
+
ctx.strokeStyle = p.cluster === 1 ? 'rgba(126, 240, 212, 0.3)' : 'rgba(255, 140, 106, 0.3)';
|
| 3868 |
+
ctx.lineWidth = 1;
|
| 3869 |
+
ctx.beginPath();
|
| 3870 |
+
ctx.moveTo(scaleX(p.x), scaleY(p.y));
|
| 3871 |
+
ctx.lineTo(scaleX(c.x), scaleY(c.y));
|
| 3872 |
+
ctx.stroke();
|
| 3873 |
+
});
|
| 3874 |
+
|
| 3875 |
+
// Draw points
|
| 3876 |
+
points.forEach(p => {
|
| 3877 |
+
ctx.fillStyle = p.cluster === 1 ? '#7ef0d4' : '#ff8c6a';
|
| 3878 |
+
ctx.beginPath();
|
| 3879 |
+
ctx.arc(scaleX(p.x), scaleY(p.y), 8, 0, 2 * Math.PI);
|
| 3880 |
+
ctx.fill();
|
| 3881 |
+
ctx.strokeStyle = '#1a2332';
|
| 3882 |
+
ctx.lineWidth = 2;
|
| 3883 |
+
ctx.stroke();
|
| 3884 |
+
|
| 3885 |
+
// Label
|
| 3886 |
+
ctx.fillStyle = '#e8eef6';
|
| 3887 |
+
ctx.font = 'bold 12px sans-serif';
|
| 3888 |
+
ctx.textAlign = 'center';
|
| 3889 |
+
ctx.fillText(p.id, scaleX(p.x), scaleY(p.y) - 15);
|
| 3890 |
+
});
|
| 3891 |
+
|
| 3892 |
+
// Draw centroids
|
| 3893 |
+
centroids.forEach((c, i) => {
|
| 3894 |
+
ctx.fillStyle = c.color;
|
| 3895 |
+
ctx.beginPath();
|
| 3896 |
+
ctx.arc(scaleX(c.x), scaleY(c.y), 12, 0, 2 * Math.PI);
|
| 3897 |
+
ctx.fill();
|
| 3898 |
+
ctx.strokeStyle = '#e8eef6';
|
| 3899 |
+
ctx.lineWidth = 3;
|
| 3900 |
+
ctx.stroke();
|
| 3901 |
+
|
| 3902 |
+
// Draw X
|
| 3903 |
+
ctx.strokeStyle = '#1a2332';
|
| 3904 |
+
ctx.lineWidth = 2;
|
| 3905 |
+
ctx.beginPath();
|
| 3906 |
+
ctx.moveTo(scaleX(c.x) - 6, scaleY(c.y) - 6);
|
| 3907 |
+
ctx.lineTo(scaleX(c.x) + 6, scaleY(c.y) + 6);
|
| 3908 |
+
ctx.moveTo(scaleX(c.x) + 6, scaleY(c.y) - 6);
|
| 3909 |
+
ctx.lineTo(scaleX(c.x) - 6, scaleY(c.y) + 6);
|
| 3910 |
+
ctx.stroke();
|
| 3911 |
+
|
| 3912 |
+
// Label
|
| 3913 |
+
ctx.fillStyle = '#e8eef6';
|
| 3914 |
+
ctx.font = 'bold 13px sans-serif';
|
| 3915 |
+
ctx.textAlign = 'center';
|
| 3916 |
+
ctx.fillText(`c${i+1}`, scaleX(c.x), scaleY(c.y) + 25);
|
| 3917 |
+
});
|
| 3918 |
+
|
| 3919 |
+
// Axes
|
| 3920 |
+
ctx.strokeStyle = '#2a3544';
|
| 3921 |
+
ctx.lineWidth = 2;
|
| 3922 |
+
ctx.beginPath();
|
| 3923 |
+
ctx.moveTo(padding, padding);
|
| 3924 |
+
ctx.lineTo(padding, height - padding);
|
| 3925 |
+
ctx.lineTo(width - padding, height - padding);
|
| 3926 |
+
ctx.stroke();
|
| 3927 |
+
|
| 3928 |
+
// Labels
|
| 3929 |
+
ctx.fillStyle = '#a9b4c2';
|
| 3930 |
+
ctx.font = '12px sans-serif';
|
| 3931 |
+
ctx.textAlign = 'center';
|
| 3932 |
+
ctx.fillText('X', width / 2, height - 20);
|
| 3933 |
+
ctx.save();
|
| 3934 |
+
ctx.translate(20, height / 2);
|
| 3935 |
+
ctx.rotate(-Math.PI / 2);
|
| 3936 |
+
ctx.fillText('Y', 0, 0);
|
| 3937 |
+
ctx.restore();
|
| 3938 |
+
|
| 3939 |
+
// Title
|
| 3940 |
+
ctx.fillStyle = '#7ef0d4';
|
| 3941 |
+
ctx.font = 'bold 16px sans-serif';
|
| 3942 |
+
ctx.textAlign = 'center';
|
| 3943 |
+
ctx.fillText('K-means Clustering (K=2) - Final State', width / 2, 30);
|
| 3944 |
+
|
| 3945 |
+
// WCSS
|
| 3946 |
+
ctx.fillStyle = '#6aa9ff';
|
| 3947 |
+
ctx.font = '14px sans-serif';
|
| 3948 |
+
ctx.textAlign = 'left';
|
| 3949 |
+
ctx.fillText('WCSS = 15.984', padding, height - padding + 30);
|
| 3950 |
+
}
|
| 3951 |
+
|
| 3952 |
+
function drawKMeansElbow() {
|
| 3953 |
+
const canvas = document.getElementById('kmeans-elbow-canvas');
|
| 3954 |
+
if (!canvas) return;
|
| 3955 |
+
|
| 3956 |
+
if (kmeansElbowChart) {
|
| 3957 |
+
kmeansElbowChart.destroy();
|
| 3958 |
+
}
|
| 3959 |
+
|
| 3960 |
+
const ctx = canvas.getContext('2d');
|
| 3961 |
+
|
| 3962 |
+
const kValues = [1, 2, 3, 4, 5];
|
| 3963 |
+
const wcssValues = [50, 18, 10, 8, 7];
|
| 3964 |
+
|
| 3965 |
+
kmeansElbowChart = new Chart(ctx, {
|
| 3966 |
+
type: 'line',
|
| 3967 |
+
data: {
|
| 3968 |
+
labels: kValues,
|
| 3969 |
+
datasets: [{
|
| 3970 |
+
label: 'WCSS',
|
| 3971 |
+
data: wcssValues,
|
| 3972 |
+
borderColor: '#6aa9ff',
|
| 3973 |
+
backgroundColor: 'rgba(106, 169, 255, 0.1)',
|
| 3974 |
+
borderWidth: 3,
|
| 3975 |
+
fill: true,
|
| 3976 |
+
tension: 0.4,
|
| 3977 |
+
pointRadius: kValues.map(k => k === 3 ? 10 : 6),
|
| 3978 |
+
pointBackgroundColor: kValues.map(k => k === 3 ? '#7ef0d4' : '#6aa9ff'),
|
| 3979 |
+
pointBorderColor: kValues.map(k => k === 3 ? '#7ef0d4' : '#6aa9ff'),
|
| 3980 |
+
pointBorderWidth: kValues.map(k => k === 3 ? 3 : 2)
|
| 3981 |
+
}]
|
| 3982 |
+
},
|
| 3983 |
+
options: {
|
| 3984 |
+
responsive: true,
|
| 3985 |
+
maintainAspectRatio: false,
|
| 3986 |
+
plugins: {
|
| 3987 |
+
title: {
|
| 3988 |
+
display: true,
|
| 3989 |
+
text: 'Elbow Method: Optimal K = 3 (Elbow Point)',
|
| 3990 |
+
color: '#7ef0d4',
|
| 3991 |
+
font: { size: 16, weight: 'bold' }
|
| 3992 |
+
},
|
| 3993 |
+
legend: {
|
| 3994 |
+
labels: { color: '#a9b4c2' }
|
| 3995 |
+
},
|
| 3996 |
+
annotation: {
|
| 3997 |
+
annotations: {
|
| 3998 |
+
line1: {
|
| 3999 |
+
type: 'line',
|
| 4000 |
+
xMin: 3,
|
| 4001 |
+
xMax: 3,
|
| 4002 |
+
borderColor: '#7ef0d4',
|
| 4003 |
+
borderWidth: 2,
|
| 4004 |
+
borderDash: [5, 5],
|
| 4005 |
+
label: {
|
| 4006 |
+
display: true,
|
| 4007 |
+
content: 'Elbow!',
|
| 4008 |
+
position: 'start'
|
| 4009 |
+
}
|
| 4010 |
+
}
|
| 4011 |
+
}
|
| 4012 |
+
}
|
| 4013 |
+
},
|
| 4014 |
+
scales: {
|
| 4015 |
+
x: {
|
| 4016 |
+
title: { display: true, text: 'Number of Clusters (K)', color: '#a9b4c2' },
|
| 4017 |
+
grid: { color: '#2a3544' },
|
| 4018 |
+
ticks: { color: '#a9b4c2', stepSize: 1 }
|
| 4019 |
+
},
|
| 4020 |
+
y: {
|
| 4021 |
+
title: { display: true, text: 'Within-Cluster Sum of Squares (WCSS)', color: '#a9b4c2' },
|
| 4022 |
+
grid: { color: '#2a3544' },
|
| 4023 |
+
ticks: { color: '#a9b4c2' },
|
| 4024 |
+
min: 0
|
| 4025 |
+
}
|
| 4026 |
+
}
|
| 4027 |
+
}
|
| 4028 |
+
});
|
| 4029 |
+
}
|
| 4030 |
+
|
| 4031 |
+
// Topic 19: Algorithm Comparison
|
| 4032 |
+
function initAlgorithmComparison() {
|
| 4033 |
+
const canvas = document.getElementById('decision-flowchart');
|
| 4034 |
+
if (!canvas || canvas.dataset.initialized) return;
|
| 4035 |
+
canvas.dataset.initialized = 'true';
|
| 4036 |
+
drawDecisionFlowchart();
|
| 4037 |
+
}
|
| 4038 |
+
|
| 4039 |
+
function drawDecisionFlowchart() {
|
| 4040 |
+
const canvas = document.getElementById('decision-flowchart');
|
| 4041 |
+
if (!canvas) return;
|
| 4042 |
+
|
| 4043 |
+
const ctx = canvas.getContext('2d');
|
| 4044 |
+
const width = canvas.width = canvas.offsetWidth;
|
| 4045 |
+
const height = canvas.height = 500;
|
| 4046 |
+
|
| 4047 |
+
ctx.clearRect(0, 0, width, height);
|
| 4048 |
+
ctx.fillStyle = '#1a2332';
|
| 4049 |
+
ctx.fillRect(0, 0, width, height);
|
| 4050 |
+
|
| 4051 |
+
const nodes = [
|
| 4052 |
+
{ x: width/2, y: 50, text: 'Start:\nWhat problem?', w: 140, h: 60, color: '#7ef0d4', type: 'start' },
|
| 4053 |
+
{ x: width/4, y: 160, text: 'Classification', w: 120, h: 50, color: '#6aa9ff', type: 'decision' },
|
| 4054 |
+
{ x: width/2, y: 160, text: 'Regression', w: 120, h: 50, color: '#6aa9ff', type: 'decision' },
|
| 4055 |
+
{ x: 3*width/4, y: 160, text: 'Clustering', w: 120, h: 50, color: '#6aa9ff', type: 'decision' },
|
| 4056 |
+
{ x: width/8, y: 270, text: 'Linear?', w: 100, h: 50, color: '#ffb490', type: 'question' },
|
| 4057 |
+
{ x: 3*width/8, y: 270, text: 'Fast?', w: 100, h: 50, color: '#ffb490', type: 'question' },
|
| 4058 |
+
{ x: width/2, y: 270, text: 'Linear?', w: 100, h: 50, color: '#ffb490', type: 'question' },
|
| 4059 |
+
{ x: 3*width/4, y: 270, text: 'Known K?', w: 100, h: 50, color: '#ffb490', type: 'question' },
|
| 4060 |
+
{ x: width/16, y: 380, text: 'Logistic\nRegression', w: 90, h: 50, color: '#7ef0d4', type: 'result' },
|
| 4061 |
+
{ x: 3*width/16, y: 380, text: 'SVM', w: 90, h: 50, color: '#7ef0d4', type: 'result' },
|
| 4062 |
+
{ x: 5*width/16, y: 380, text: 'Naive\nBayes', w: 90, h: 50, color: '#7ef0d4', type: 'result' },
|
| 4063 |
+
{ x: 7*width/16, y: 380, text: 'Random\nForest', w: 90, h: 50, color: '#7ef0d4', type: 'result' },
|
| 4064 |
+
{ x: 9*width/16, y: 380, text: 'Linear\nRegression', w: 90, h: 50, color: '#7ef0d4', type: 'result' },
|
| 4065 |
+
{ x: 11*width/16, y: 380, text: 'XGBoost', w: 90, h: 50, color: '#7ef0d4', type: 'result' },
|
| 4066 |
+
{ x: 13*width/16, y: 380, text: 'K-means', w: 90, h: 50, color: '#7ef0d4', type: 'result' },
|
| 4067 |
+
{ x: 15*width/16, y: 380, text: 'DBSCAN', w: 90, h: 50, color: '#7ef0d4', type: 'result' }
|
| 4068 |
+
];
|
| 4069 |
+
|
| 4070 |
+
const edges = [
|
| 4071 |
+
{ from: 0, to: 1 }, { from: 0, to: 2 }, { from: 0, to: 3 },
|
| 4072 |
+
{ from: 1, to: 4 }, { from: 1, to: 5 },
|
| 4073 |
+
{ from: 2, to: 6 },
|
| 4074 |
+
{ from: 3, to: 7 },
|
| 4075 |
+
{ from: 4, to: 8, label: 'Yes' }, { from: 4, to: 9, label: 'No' },
|
| 4076 |
+
{ from: 5, to: 10, label: 'Yes' }, { from: 5, to: 11, label: 'No' },
|
| 4077 |
+
{ from: 6, to: 12, label: 'Yes' }, { from: 6, to: 13, label: 'No' },
|
| 4078 |
+
{ from: 7, to: 14, label: 'Yes' }, { from: 7, to: 15, label: 'No' }
|
| 4079 |
+
];
|
| 4080 |
+
|
| 4081 |
+
// Draw edges
|
| 4082 |
+
ctx.strokeStyle = '#6aa9ff';
|
| 4083 |
+
ctx.lineWidth = 2;
|
| 4084 |
+
edges.forEach(edge => {
|
| 4085 |
+
const from = nodes[edge.from];
|
| 4086 |
+
const to = nodes[edge.to];
|
| 4087 |
+
|
| 4088 |
+
ctx.beginPath();
|
| 4089 |
+
ctx.moveTo(from.x, from.y + from.h/2);
|
| 4090 |
+
ctx.lineTo(to.x, to.y - to.h/2);
|
| 4091 |
+
ctx.stroke();
|
| 4092 |
+
|
| 4093 |
+
if (edge.label) {
|
| 4094 |
+
ctx.fillStyle = '#7ef0d4';
|
| 4095 |
+
ctx.font = '10px sans-serif';
|
| 4096 |
+
ctx.textAlign = 'center';
|
| 4097 |
+
const midX = (from.x + to.x) / 2;
|
| 4098 |
+
const midY = (from.y + to.y) / 2;
|
| 4099 |
+
ctx.fillText(edge.label, midX + 12, midY);
|
| 4100 |
+
}
|
| 4101 |
+
});
|
| 4102 |
+
|
| 4103 |
+
// Draw nodes
|
| 4104 |
+
nodes.forEach(node => {
|
| 4105 |
+
const x = node.x - node.w/2;
|
| 4106 |
+
const y = node.y - node.h/2;
|
| 4107 |
+
|
| 4108 |
+
ctx.fillStyle = node.color + '33';
|
| 4109 |
+
ctx.fillRect(x, y, node.w, node.h);
|
| 4110 |
+
ctx.strokeStyle = node.color;
|
| 4111 |
+
ctx.lineWidth = 2;
|
| 4112 |
+
ctx.strokeRect(x, y, node.w, node.h);
|
| 4113 |
+
|
| 4114 |
+
ctx.fillStyle = '#e8eef6';
|
| 4115 |
+
ctx.font = node.type === 'result' ? 'bold 11px sans-serif' : '11px sans-serif';
|
| 4116 |
+
ctx.textAlign = 'center';
|
| 4117 |
+
const lines = node.text.split('\n');
|
| 4118 |
+
lines.forEach((line, i) => {
|
| 4119 |
+
ctx.fillText(line, node.x, node.y - (lines.length - 1) * 6 + i * 12);
|
| 4120 |
+
});
|
| 4121 |
+
});
|
| 4122 |
+
|
| 4123 |
+
// Title
|
| 4124 |
+
ctx.fillStyle = '#7ef0d4';
|
| 4125 |
+
ctx.font = 'bold 16px sans-serif';
|
| 4126 |
+
ctx.textAlign = 'center';
|
| 4127 |
+
ctx.fillText('Algorithm Selection Flowchart', width/2, 25);
|
| 4128 |
+
}
|
| 4129 |
+
|
| 4130 |
// Handle window resize
|
| 4131 |
let resizeTimer;
|
| 4132 |
window.addEventListener('resize', () => {
|
|
|
|
| 4154 |
drawSVMTraining();
|
| 4155 |
drawSVMKernel();
|
| 4156 |
// New topics
|
| 4157 |
+
if (document.getElementById('elbow-canvas')) drawElbowCurve();
|
| 4158 |
+
if (document.getElementById('cv-k-canvas')) drawCVKHeatmap();
|
| 4159 |
+
if (document.getElementById('gridsearch-heatmap')) drawGridSearchHeatmap();
|
| 4160 |
+
if (document.getElementById('param-surface')) drawParamSurface();
|
| 4161 |
+
if (document.getElementById('bayes-theorem-viz')) drawBayesTheorem();
|
| 4162 |
+
if (document.getElementById('spam-classification')) drawSpamClassification();
|
| 4163 |
+
if (document.getElementById('decision-tree-viz')) drawDecisionTree();
|
| 4164 |
+
if (document.getElementById('entropy-viz')) drawEntropyViz();
|
| 4165 |
+
if (document.getElementById('split-comparison')) drawSplitComparison();
|
| 4166 |
+
if (document.getElementById('tree-boundary')) drawTreeBoundary();
|
| 4167 |
+
if (document.getElementById('bagging-viz')) drawBaggingViz();
|
| 4168 |
+
if (document.getElementById('boosting-viz')) drawBoostingViz();
|
| 4169 |
+
if (document.getElementById('random-forest-viz')) drawRandomForestViz();
|
| 4170 |
+
if (document.getElementById('categorical-nb-canvas')) drawCategoricalNB();
|
| 4171 |
+
if (document.getElementById('gaussian-nb-canvas')) drawGaussianNB();
|
| 4172 |
+
if (document.getElementById('kmeans-viz-canvas')) drawKMeansVisualization();
|
| 4173 |
+
if (document.getElementById('kmeans-elbow-canvas')) drawKMeansElbow();
|
| 4174 |
+
if (document.getElementById('decision-flowchart')) drawDecisionFlowchart();
|
| 4175 |
}, 250);
|
| 4176 |
});
|
ml_complete-all-topics/index.html
CHANGED
|
@@ -4,6 +4,7 @@
|
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<title>Machine Learning: Complete Educational Guide</title>
|
|
|
|
| 7 |
<style>
|
| 8 |
@font-face {
|
| 9 |
font-family: 'FKGroteskNeue';
|
|
@@ -499,8 +500,10 @@ canvas {
|
|
| 499 |
<a href="#optimal-k" class="toc-link">13. Finding Optimal K in KNN</a>
|
| 500 |
<a href="#hyperparameter-tuning" class="toc-link">14. Hyperparameter Tuning</a>
|
| 501 |
<a href="#naive-bayes" class="toc-link">15. Naive Bayes</a>
|
| 502 |
-
<a href="#
|
| 503 |
-
<a href="#
|
|
|
|
|
|
|
| 504 |
</nav>
|
| 505 |
</aside>
|
| 506 |
|
|
@@ -616,8 +619,8 @@ canvas {
|
|
| 616 |
<p>We can find a line (y = 7.5x + 32) that predicts: Someone with 7 years experience will earn approximately $84.5k.</p>
|
| 617 |
|
| 618 |
<div class="figure">
|
| 619 |
-
<div class="figure-placeholder" style="height: 400px">
|
| 620 |
-
<canvas id="lr-canvas"></canvas>
|
| 621 |
</div>
|
| 622 |
<p class="figure-caption"><strong>Figure 1:</strong> Scatter plot showing experience vs. salary with the best fit line</p>
|
| 623 |
</div>
|
|
@@ -710,8 +713,8 @@ canvas {
|
|
| 710 |
</ul>
|
| 711 |
|
| 712 |
<div class="figure">
|
| 713 |
-
<div class="figure-placeholder" style="height: 400px">
|
| 714 |
-
<canvas id="gd-canvas"></canvas>
|
| 715 |
</div>
|
| 716 |
<p class="figure-caption"><strong>Figure 2:</strong> Loss surface showing gradient descent path to minimum</p>
|
| 717 |
</div>
|
|
@@ -2402,8 +2405,8 @@ Actual Pos TP FN
|
|
| 2402 |
<p>Test different K values and plot performance. Look for the "elbow" where adding more neighbors doesn't help much.</p>
|
| 2403 |
|
| 2404 |
<div class="figure">
|
| 2405 |
-
<div class="figure-placeholder" style="height: 400px">
|
| 2406 |
-
<canvas id="elbow-canvas"></canvas>
|
| 2407 |
</div>
|
| 2408 |
<p class="figure-caption"><strong>Figure 1:</strong> Elbow curve showing optimal K at the bend</p>
|
| 2409 |
</div>
|
|
@@ -2550,14 +2553,14 @@ Actual Pos TP FN
|
|
| 2550 |
</div>
|
| 2551 |
</div>
|
| 2552 |
|
| 2553 |
-
<!-- Section 15: Naive Bayes -->
|
| 2554 |
<div class="section" id="naive-bayes">
|
| 2555 |
<div class="section-header">
|
| 2556 |
<h2>15. Naive Bayes Classification</h2>
|
| 2557 |
<button class="section-toggle">▼</button>
|
| 2558 |
</div>
|
| 2559 |
<div class="section-body">
|
| 2560 |
-
<p>Naive Bayes is a probabilistic classifier based on Bayes' Theorem. Despite its "naive" independence assumption, it works surprisingly well for text classification and other tasks!</p>
|
| 2561 |
|
| 2562 |
<div class="info-card">
|
| 2563 |
<div class="info-card-title">Key Concepts</div>
|
|
@@ -2668,9 +2671,271 @@ Actual Pos TP FN
|
|
| 2668 |
</tbody>
|
| 2669 |
</table>
|
| 2670 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2671 |
<div class="callout success">
|
| 2672 |
<div class="callout-title">✅ When to Use Naive Bayes</div>
|
| 2673 |
<div class="callout-content">
|
|
|
|
|
|
|
|
|
|
| 2674 |
<strong>Perfect for:</strong><br>
|
| 2675 |
• Text classification (spam detection, sentiment analysis)<br>
|
| 2676 |
• Document categorization<br>
|
|
@@ -2687,7 +2952,187 @@ Actual Pos TP FN
|
|
| 2687 |
</div>
|
| 2688 |
</div>
|
| 2689 |
|
| 2690 |
-
<!-- Section 16:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2691 |
<div class="section" id="decision-trees">
|
| 2692 |
<div class="section-header">
|
| 2693 |
<h2>16. Decision Trees</h2>
|
|
@@ -2845,10 +3290,10 @@ Actual Pos TP FN
|
|
| 2845 |
</div>
|
| 2846 |
</div>
|
| 2847 |
|
| 2848 |
-
<!-- Section
|
| 2849 |
<div class="section" id="ensemble-methods">
|
| 2850 |
<div class="section-header">
|
| 2851 |
-
<h2>
|
| 2852 |
<button class="section-toggle">▼</button>
|
| 2853 |
</div>
|
| 2854 |
<div class="section-body">
|
|
|
|
| 4 |
<meta charset="UTF-8">
|
| 5 |
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 6 |
<title>Machine Learning: Complete Educational Guide</title>
|
| 7 |
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
| 8 |
<style>
|
| 9 |
@font-face {
|
| 10 |
font-family: 'FKGroteskNeue';
|
|
|
|
| 500 |
<a href="#optimal-k" class="toc-link">13. Finding Optimal K in KNN</a>
|
| 501 |
<a href="#hyperparameter-tuning" class="toc-link">14. Hyperparameter Tuning</a>
|
| 502 |
<a href="#naive-bayes" class="toc-link">15. Naive Bayes</a>
|
| 503 |
+
<a href="#kmeans" class="toc-link">16. K-means Clustering</a>
|
| 504 |
+
<a href="#decision-trees" class="toc-link">17. Decision Trees</a>
|
| 505 |
+
<a href="#ensemble-methods" class="toc-link">18. Ensemble Methods</a>
|
| 506 |
+
<a href="#algorithm-comparison" class="toc-link">19. Algorithm Comparison</a>
|
| 507 |
</nav>
|
| 508 |
</aside>
|
| 509 |
|
|
|
|
| 619 |
<p>We can find a line (y = 7.5x + 32) that predicts: Someone with 7 years experience will earn approximately $84.5k.</p>
|
| 620 |
|
| 621 |
<div class="figure">
|
| 622 |
+
<div class="figure-placeholder" style="height: 400px; position: relative;">
|
| 623 |
+
<canvas id="lr-canvas" style="width: 100%; height: 100%;"></canvas>
|
| 624 |
</div>
|
| 625 |
<p class="figure-caption"><strong>Figure 1:</strong> Scatter plot showing experience vs. salary with the best fit line</p>
|
| 626 |
</div>
|
|
|
|
| 713 |
</ul>
|
| 714 |
|
| 715 |
<div class="figure">
|
| 716 |
+
<div class="figure-placeholder" style="height: 400px; position: relative;">
|
| 717 |
+
<canvas id="gd-canvas" style="width: 100%; height: 100%;"></canvas>
|
| 718 |
</div>
|
| 719 |
<p class="figure-caption"><strong>Figure 2:</strong> Loss surface showing gradient descent path to minimum</p>
|
| 720 |
</div>
|
|
|
|
| 2405 |
<p>Test different K values and plot performance. Look for the "elbow" where adding more neighbors doesn't help much.</p>
|
| 2406 |
|
| 2407 |
<div class="figure">
|
| 2408 |
+
<div class="figure-placeholder" style="height: 400px; position: relative;">
|
| 2409 |
+
<canvas id="elbow-canvas" style="width: 100%; height: 100%;"></canvas>
|
| 2410 |
</div>
|
| 2411 |
<p class="figure-caption"><strong>Figure 1:</strong> Elbow curve showing optimal K at the bend</p>
|
| 2412 |
</div>
|
|
|
|
| 2553 |
</div>
|
| 2554 |
</div>
|
| 2555 |
|
| 2556 |
+
<!-- Section 15: Naive Bayes (COMPREHENSIVE WITH MATH) -->
|
| 2557 |
<div class="section" id="naive-bayes">
|
| 2558 |
<div class="section-header">
|
| 2559 |
<h2>15. Naive Bayes Classification</h2>
|
| 2560 |
<button class="section-toggle">▼</button>
|
| 2561 |
</div>
|
| 2562 |
<div class="section-body">
|
| 2563 |
+
<p>Naive Bayes is a probabilistic classifier based on Bayes' Theorem. Despite its "naive" independence assumption, it works surprisingly well for text classification and other tasks! We'll cover both Categorical and Gaussian Naive Bayes with complete mathematical solutions.</p>
|
| 2564 |
|
| 2565 |
<div class="info-card">
|
| 2566 |
<div class="info-card-title">Key Concepts</div>
|
|
|
|
| 2671 |
</tbody>
|
| 2672 |
</table>
|
| 2673 |
|
| 2674 |
+
<h3>🎯 PART A: Categorical Naive Bayes (Step-by-Step from PDF)</h3>
|
| 2675 |
+
|
| 2676 |
+
<h4>Dataset: Tennis Play Prediction</h4>
|
| 2677 |
+
<table class="data-table">
|
| 2678 |
+
<thead>
|
| 2679 |
+
<tr><th>Outlook</th><th>Temperature</th><th>Play</th></tr>
|
| 2680 |
+
</thead>
|
| 2681 |
+
<tbody>
|
| 2682 |
+
<tr><td>Sunny</td><td>Hot</td><td>No</td></tr>
|
| 2683 |
+
<tr><td>Sunny</td><td>Mild</td><td>No</td></tr>
|
| 2684 |
+
<tr><td>Cloudy</td><td>Hot</td><td>Yes</td></tr>
|
| 2685 |
+
<tr><td>Rainy</td><td>Mild</td><td>Yes</td></tr>
|
| 2686 |
+
<tr><td>Rainy</td><td>Cool</td><td>Yes</td></tr>
|
| 2687 |
+
<tr><td>Cloudy</td><td>Cool</td><td>Yes</td></tr>
|
| 2688 |
+
</tbody>
|
| 2689 |
+
</table>
|
| 2690 |
+
|
| 2691 |
+
<p><strong>Problem:</strong> Predict whether to play tennis when Outlook=Rainy and Temperature=Hot</p>
|
| 2692 |
+
|
| 2693 |
+
<div class="step">
|
| 2694 |
+
<div class="step-title">STEP 1: Calculate Prior Probabilities</div>
|
| 2695 |
+
<div class="step-calculation">
|
| 2696 |
+
Count occurrences in training data:<br>
|
| 2697 |
+
• Play=Yes appears 4 times out of 6 total<br>
|
| 2698 |
+
• Play=No appears 2 times out of 6 total<br>
|
| 2699 |
+
<br>
|
| 2700 |
+
<strong>Calculation:</strong><br>
|
| 2701 |
+
P(Yes) = 4/6 = <strong>0.667 (66.7%)</strong><br>
|
| 2702 |
+
P(No) = 2/6 = <strong>0.333 (33.3%)</strong>
|
| 2703 |
+
</div>
|
| 2704 |
+
</div>
|
| 2705 |
+
|
| 2706 |
+
<div class="step">
|
| 2707 |
+
<div class="step-title">STEP 2: Calculate Conditional Probabilities (Before Smoothing)</div>
|
| 2708 |
+
<div class="step-calculation">
|
| 2709 |
+
<strong>For Outlook = "Rainy":</strong><br>
|
| 2710 |
+
• Count (Rainy AND Yes) = 2 examples<br>
|
| 2711 |
+
• Count (Yes) = 4 total<br>
|
| 2712 |
+
• P(Rainy|Yes) = 2/4 = <strong>0.5</strong><br>
|
| 2713 |
+
<br>
|
| 2714 |
+
• Count (Rainy AND No) = 0 examples ❌<br>
|
| 2715 |
+
• Count (No) = 2 total<br>
|
| 2716 |
+
• P(Rainy|No) = 0/2 = <strong>0</strong> ⚠️ <span style="color: #ff8c6a;">ZERO PROBABILITY PROBLEM!</span><br>
|
| 2717 |
+
<br>
|
| 2718 |
+
<strong>For Temperature = "Hot":</strong><br>
|
| 2719 |
+
• P(Hot|Yes) = 1/4 = <strong>0.25</strong><br>
|
| 2720 |
+
• P(Hot|No) = 1/2 = <strong>0.5</strong>
|
| 2721 |
+
</div>
|
| 2722 |
+
</div>
|
| 2723 |
+
|
| 2724 |
+
<div class="formula">
|
| 2725 |
+
<strong>Step 3: Apply Bayes' Theorem (Initial)</strong><br>
|
| 2726 |
+
<br>
|
| 2727 |
+
P(Yes|Rainy,Hot) = P(Yes) × P(Rainy|Yes) × P(Hot|Yes)<br>
|
| 2728 |
+
= 0.667 × 0.5 × 0.25<br>
|
| 2729 |
+
= 0.0833<br>
|
| 2730 |
+
<br>
|
| 2731 |
+
P(No|Rainy,Hot) = P(No) × P(Rainy|No) × P(Hot|No)<br>
|
| 2732 |
+
= 0.333 × 0 × 0.5<br>
|
| 2733 |
+
= 0 ❌ Problem!
|
| 2734 |
+
</div>
|
| 2735 |
+
|
| 2736 |
+
<div class="callout warning">
|
| 2737 |
+
<div class="callout-title">⚠️ Zero Probability Problem</div>
|
| 2738 |
+
<div class="callout-content">
|
| 2739 |
+
When P(Rainy|No) = 0, the entire probability becomes 0! This is unrealistic - just because we haven't seen "Rainy" with "No" in our training data doesn't mean it's impossible. We need <strong>Laplace Smoothing</strong>!
|
| 2740 |
+
</div>
|
| 2741 |
+
</div>
|
| 2742 |
+
|
| 2743 |
+
<div class="step">
|
| 2744 |
+
<div class="step-title">STEP 4: Apply Laplace Smoothing (α = 1)</div>
|
| 2745 |
+
<div class="step-calculation">
|
| 2746 |
+
<strong>Smoothed formula:</strong><br>
|
| 2747 |
+
P(x|c) = (count(x,c) + α) / (count(c) + α × num_categories)<br>
|
| 2748 |
+
<br>
|
| 2749 |
+
<strong>For Outlook</strong> (3 categories: Sunny, Cloudy, Rainy):<br>
|
| 2750 |
+
P(Rainy|Yes) = (2 + 1) / (4 + 1×3)<br>
|
| 2751 |
+
= 3/7<br>
|
| 2752 |
+
= <strong>0.429</strong> ✓<br>
|
| 2753 |
+
<br>
|
| 2754 |
+
P(Rainy|No) = (0 + 1) / (2 + 1×3)<br>
|
| 2755 |
+
= 1/5<br>
|
| 2756 |
+
= <strong>0.2</strong> ✓ <span style="color: #7ef0d4;">Fixed the zero!</span><br>
|
| 2757 |
+
<br>
|
| 2758 |
+
<strong>For Temperature</strong> (3 categories: Hot, Mild, Cool):<br>
|
| 2759 |
+
P(Hot|Yes) = (1 + 1) / (4 + 1×3) = 2/7 = <strong>0.286</strong><br>
|
| 2760 |
+
P(Hot|No) = (1 + 1) / (2 + 1×3) = 2/5 = <strong>0.4</strong>
|
| 2761 |
+
</div>
|
| 2762 |
+
</div>
|
| 2763 |
+
|
| 2764 |
+
<div class="step">
|
| 2765 |
+
<div class="step-title">STEP 5: Recalculate with Smoothing</div>
|
| 2766 |
+
<div class="step-calculation">
|
| 2767 |
+
<strong>P(Yes|Rainy,Hot):</strong><br>
|
| 2768 |
+
= P(Yes) × P(Rainy|Yes) × P(Hot|Yes)<br>
|
| 2769 |
+
= 0.667 × 0.429 × 0.286<br>
|
| 2770 |
+
= <strong>0.0818</strong><br>
|
| 2771 |
+
<br>
|
| 2772 |
+
<strong>P(No|Rainy,Hot):</strong><br>
|
| 2773 |
+
= P(No) × P(Rainy|No) × P(Hot|No)<br>
|
| 2774 |
+
= 0.333 × 0.2 × 0.4<br>
|
| 2775 |
+
= <strong>0.0266</strong>
|
| 2776 |
+
</div>
|
| 2777 |
+
</div>
|
| 2778 |
+
|
| 2779 |
+
<div class="step">
|
| 2780 |
+
<div class="step-title">STEP 6: Normalize to Get Final Probabilities</div>
|
| 2781 |
+
<div class="step-calculation">
|
| 2782 |
+
<strong>Sum of probabilities:</strong><br>
|
| 2783 |
+
Sum = 0.0818 + 0.0266 = <strong>0.1084</strong><br>
|
| 2784 |
+
<br>
|
| 2785 |
+
<strong>Normalize:</strong><br>
|
| 2786 |
+
P(Yes|Rainy,Hot) = 0.0818 / 0.1084<br>
|
| 2787 |
+
= <strong style="color: #7ef0d4;">0.755 (75.5%)</strong><br>
|
| 2788 |
+
<br>
|
| 2789 |
+
P(No|Rainy,Hot) = 0.0266 / 0.1084<br>
|
| 2790 |
+
= <strong style="color: #ff8c6a;">0.245 (24.5%)</strong><br>
|
| 2791 |
+
<br>
|
| 2792 |
+
<div style="background: rgba(126, 240, 212, 0.2); padding: 16px; border-radius: 8px; margin-top: 12px;">
|
| 2793 |
+
<strong style="color: #7ef0d4; font-size: 20px;">✅ FINAL PREDICTION: YES (Play Tennis!)</strong><br>
|
| 2794 |
+
<span style="color: #a9b4c2; font-size: 14px;">Confidence: 75.5%</span>
|
| 2795 |
+
</div>
|
| 2796 |
+
</div>
|
| 2797 |
+
</div>
|
| 2798 |
+
|
| 2799 |
+
<div class="figure">
|
| 2800 |
+
<div class="figure-placeholder" style="height: 400px">
|
| 2801 |
+
<canvas id="categorical-nb-canvas"></canvas>
|
| 2802 |
+
</div>
|
| 2803 |
+
<p class="figure-caption"><strong>Figure:</strong> Categorical Naive Bayes calculation visualization</p>
|
| 2804 |
+
</div>
|
| 2805 |
+
|
| 2806 |
+
<h3>🎯 PART B: Gaussian Naive Bayes (Step-by-Step from PDF)</h3>
|
| 2807 |
+
|
| 2808 |
+
<h4>Dataset: 2D Classification</h4>
|
| 2809 |
+
<table class="data-table">
|
| 2810 |
+
<thead>
|
| 2811 |
+
<tr><th>ID</th><th>X₁</th><th>X₂</th><th>Class</th></tr>
|
| 2812 |
+
</thead>
|
| 2813 |
+
<tbody>
|
| 2814 |
+
<tr><td>A</td><td>1.0</td><td>2.0</td><td>Yes</td></tr>
|
| 2815 |
+
<tr><td>B</td><td>2.0</td><td>1.0</td><td>Yes</td></tr>
|
| 2816 |
+
<tr><td>C</td><td>1.5</td><td>1.8</td><td>Yes</td></tr>
|
| 2817 |
+
<tr><td>D</td><td>3.0</td><td>3.0</td><td>No</td></tr>
|
| 2818 |
+
<tr><td>E</td><td>3.5</td><td>2.8</td><td>No</td></tr>
|
| 2819 |
+
<tr><td>F</td><td>2.9</td><td>3.2</td><td>No</td></tr>
|
| 2820 |
+
</tbody>
|
| 2821 |
+
</table>
|
| 2822 |
+
|
| 2823 |
+
<p><strong>Problem:</strong> Classify test point [X₁=2.0, X₂=2.0]</p>
|
| 2824 |
+
|
| 2825 |
+
<div class="step">
|
| 2826 |
+
<div class="step-title">STEP 1: Calculate Mean and Variance for Each Class</div>
|
| 2827 |
+
<div class="step-calculation">
|
| 2828 |
+
<strong>Class "Yes" (samples A, B, C):</strong><br>
|
| 2829 |
+
X₁ values: [1.0, 2.0, 1.5]<br>
|
| 2830 |
+
μ₁(Yes) = (1.0 + 2.0 + 1.5) / 3 = <strong>1.5</strong><br>
|
| 2831 |
+
σ₁²(Yes) = [(1-1.5)² + (2-1.5)² + (1.5-1.5)²] / 3<br>
|
| 2832 |
+
= [0.25 + 0.25 + 0] / 3<br>
|
| 2833 |
+
= <strong>0.166</strong><br>
|
| 2834 |
+
<br>
|
| 2835 |
+
X₂ values: [2.0, 1.0, 1.8]<br>
|
| 2836 |
+
μ₂(Yes) = (2.0 + 1.0 + 1.8) / 3 = <strong>1.6</strong><br>
|
| 2837 |
+
σ₂²(Yes) = [(2-1.6)² + (1-1.6)² + (1.8-1.6)²] / 3<br>
|
| 2838 |
+
= [0.16 + 0.36 + 0.04] / 3<br>
|
| 2839 |
+
= <strong>0.186</strong><br>
|
| 2840 |
+
<br>
|
| 2841 |
+
<strong>Class "No" (samples D, E, F):</strong><br>
|
| 2842 |
+
X₁ values: [3.0, 3.5, 2.9]<br>
|
| 2843 |
+
μ₁(No) = (3.0 + 3.5 + 2.9) / 3 = <strong>3.133</strong><br>
|
| 2844 |
+
σ₁²(No) = <strong>0.0688</strong><br>
|
| 2845 |
+
<br>
|
| 2846 |
+
X₂ values: [3.0, 2.8, 3.2]<br>
|
| 2847 |
+
μ₂(No) = (3.0 + 2.8 + 3.2) / 3 = <strong>3.0</strong><br>
|
| 2848 |
+
σ₂²(No) = <strong>0.0266</strong>
|
| 2849 |
+
</div>
|
| 2850 |
+
</div>
|
| 2851 |
+
|
| 2852 |
+
<div class="formula">
|
| 2853 |
+
<strong>Step 2: Gaussian Probability Density Function</strong><br>
|
| 2854 |
+
<br>
|
| 2855 |
+
P(x|μ,σ²) = (1/√(2πσ²)) × exp(-(x-μ)²/(2σ²))<br>
|
| 2856 |
+
<br>
|
| 2857 |
+
This gives us the probability density at point x given mean μ and variance σ²
|
| 2858 |
+
</div>
|
| 2859 |
+
|
| 2860 |
+
<div class="step">
|
| 2861 |
+
<div class="step-title">STEP 3: Calculate P(X₁=2.0 | Class) using Gaussian PDF</div>
|
| 2862 |
+
<div class="step-calculation">
|
| 2863 |
+
<strong>For Class "Yes" (μ=1.5, σ²=0.166):</strong><br>
|
| 2864 |
+
P(2.0|Yes) = (1/√(2π × 0.166)) × exp(-(2.0-1.5)²/(2 × 0.166))<br>
|
| 2865 |
+
<br>
|
| 2866 |
+
Step-by-step:<br>
|
| 2867 |
+
• Normalization: 1/√(2π × 0.166) = 1/√1.043 = 1/1.021 = <strong>0.9772</strong><br>
|
| 2868 |
+
• Exponent: -(2.0-1.5)²/(2 × 0.166) = -(0.5)²/0.332 = -0.25/0.332 = <strong>-0.753</strong><br>
|
| 2869 |
+
• e^(-0.753) = <strong>0.471</strong><br>
|
| 2870 |
+
• Final: 0.9772 × 0.471 = <strong style="color: #7ef0d4;">0.460</strong><br>
|
| 2871 |
+
<br>
|
| 2872 |
+
<strong>For Class "No" (μ=3.133, σ²=0.0688):</strong><br>
|
| 2873 |
+
P(2.0|No) = (1/√(2π × 0.0688)) × exp(-(2.0-3.133)²/(2 × 0.0688))<br>
|
| 2874 |
+
<br>
|
| 2875 |
+
Step-by-step:<br>
|
| 2876 |
+
• Normalization: 1/√(2π × 0.0688) = <strong>1.523</strong><br>
|
| 2877 |
+
• Exponent: -(2.0-3.133)²/(2 × 0.0688) = -(-1.133)²/0.1376 = -1.283/0.1376 = <strong>-9.333</strong><br>
|
| 2878 |
+
• e^(-9.333) = <strong>0.000088</strong><br>
|
| 2879 |
+
• Final: 1.523 × 0.000088 = <strong style="color: #ff8c6a;">0.000134</strong><br>
|
| 2880 |
+
<br>
|
| 2881 |
+
<span style="color: #7ef0d4;">• Point (2.0, ?) is MUCH more likely to be "Yes"!</span>
|
| 2882 |
+
</div>
|
| 2883 |
+
</div>
|
| 2884 |
+
|
| 2885 |
+
<div class="formula">
|
| 2886 |
+
<strong>Step 4: Calculate P(X₂=2.0 | Class)</strong><br>
|
| 2887 |
+
<br>
|
| 2888 |
+
<strong>For "Yes":</strong><br>
|
| 2889 |
+
P(2.0|Yes) = (1/√(2π×0.186)) × exp(-(2.0-1.6)²/(2×0.186))<br>
|
| 2890 |
+
= 0.923 × exp(-0.430)<br>
|
| 2891 |
+
= 0.923 × 0.651<br>
|
| 2892 |
+
= 0.601<br>
|
| 2893 |
+
<br>
|
| 2894 |
+
<strong>For "No":</strong><br>
|
| 2895 |
+
P(2.0|No) = (1/√(2π×0.0266)) × exp(-(2.0-3.0)²/(2×0.0266))<br>
|
| 2896 |
+
= 2.449 × exp(-18.797)<br>
|
| 2897 |
+
= 2.449 × 0.0000000614<br>
|
| 2898 |
+
= 0.00000015
|
| 2899 |
+
</div>
|
| 2900 |
+
|
| 2901 |
+
<div class="formula">
|
| 2902 |
+
<strong>Step 5: Combine with Prior (assume equal priors)</strong><br>
|
| 2903 |
+
<br>
|
| 2904 |
+
P(Yes) = P(No) = 0.5<br>
|
| 2905 |
+
<br>
|
| 2906 |
+
P(Yes|X) ∝ P(Yes) × P(X₁=2.0|Yes) × P(X₂=2.0|Yes)<br>
|
| 2907 |
+
= 0.5 × 0.460 × 0.601<br>
|
| 2908 |
+
= 0.138<br>
|
| 2909 |
+
<br>
|
| 2910 |
+
P(No|X) ∝ P(No) × P(X₁=2.0|No) × P(X₂=2.0|No)<br>
|
| 2911 |
+
= 0.5 × 0.000134 × 0.00000015<br>
|
| 2912 |
+
= 0.00000000001
|
| 2913 |
+
</div>
|
| 2914 |
+
|
| 2915 |
+
<div class="formula">
|
| 2916 |
+
<strong>Step 6: Normalize</strong><br>
|
| 2917 |
+
<br>
|
| 2918 |
+
Sum = 0.138 + 0.00000000001 ≈ 0.138<br>
|
| 2919 |
+
<br>
|
| 2920 |
+
P(Yes|X) = 0.138 / 0.138 ≈ 1.0 (99.99%)<br>
|
| 2921 |
+
P(No|X) ≈ 0.0 (0.01%)<br>
|
| 2922 |
+
<br>
|
| 2923 |
+
<strong style="color: #7ef0d4; font-size: 18px;">Prediction: YES ✅</strong>
|
| 2924 |
+
</div>
|
| 2925 |
+
|
| 2926 |
+
<div class="figure">
|
| 2927 |
+
<div class="figure-placeholder" style="height: 400px">
|
| 2928 |
+
<canvas id="gaussian-nb-canvas"></canvas>
|
| 2929 |
+
</div>
|
| 2930 |
+
<p class="figure-caption"><strong>Figure:</strong> Gaussian Naive Bayes with decision boundary</p>
|
| 2931 |
+
</div>
|
| 2932 |
+
|
| 2933 |
<div class="callout success">
|
| 2934 |
<div class="callout-title">✅ When to Use Naive Bayes</div>
|
| 2935 |
<div class="callout-content">
|
| 2936 |
+
<strong>Categorical NB:</strong> Discrete features (text, categories)<br>
|
| 2937 |
+
<strong>Gaussian NB:</strong> Continuous features (measurements, coordinates)<br>
|
| 2938 |
+
<br>
|
| 2939 |
<strong>Perfect for:</strong><br>
|
| 2940 |
• Text classification (spam detection, sentiment analysis)<br>
|
| 2941 |
• Document categorization<br>
|
|
|
|
| 2952 |
</div>
|
| 2953 |
</div>
|
| 2954 |
|
| 2955 |
+
<!-- Section 16: K-means Clustering -->
|
| 2956 |
+
<div class="section" id="kmeans">
|
| 2957 |
+
<div class="section-header">
|
| 2958 |
+
<h2>16. K-means Clustering</h2>
|
| 2959 |
+
<button class="section-toggle">▼</button>
|
| 2960 |
+
</div>
|
| 2961 |
+
<div class="section-body">
|
| 2962 |
+
<p>K-means is an unsupervised learning algorithm that groups data into K clusters. Each cluster has a centroid (center point), and points are assigned to the nearest centroid. Perfect for customer segmentation, image compression, and pattern discovery!</p>
|
| 2963 |
+
|
| 2964 |
+
<div class="info-card">
|
| 2965 |
+
<div class="info-card-title">Key Concepts</div>
|
| 2966 |
+
<ul class="info-card-list">
|
| 2967 |
+
<li>Unsupervised: No labels needed!</li>
|
| 2968 |
+
<li>K = number of clusters (you choose)</li>
|
| 2969 |
+
<li>Minimizes Within-Cluster Sum of Squares (WCSS)</li>
|
| 2970 |
+
<li>Iterative: Updates centroids until convergence</li>
|
| 2971 |
+
</ul>
|
| 2972 |
+
</div>
|
| 2973 |
+
|
| 2974 |
+
<h3>🎯 Step-by-Step K-means Algorithm (from PDF)</h3>
|
| 2975 |
+
|
| 2976 |
+
<h4>Dataset: 6 Points in 2D Space</h4>
|
| 2977 |
+
<table class="data-table">
|
| 2978 |
+
<thead>
|
| 2979 |
+
<tr><th>Point</th><th>X</th><th>Y</th></tr>
|
| 2980 |
+
</thead>
|
| 2981 |
+
<tbody>
|
| 2982 |
+
<tr><td>A</td><td>1</td><td>2</td></tr>
|
| 2983 |
+
<tr><td>B</td><td>1.5</td><td>1.8</td></tr>
|
| 2984 |
+
<tr><td>C</td><td>5</td><td>8</td></tr>
|
| 2985 |
+
<tr><td>D</td><td>8</td><td>8</td></tr>
|
| 2986 |
+
<tr><td>E</td><td>1</td><td>0.6</td></tr>
|
| 2987 |
+
<tr><td>F</td><td>9</td><td>11</td></tr>
|
| 2988 |
+
</tbody>
|
| 2989 |
+
</table>
|
| 2990 |
+
|
| 2991 |
+
<p><strong>Goal:</strong> Group into K=2 clusters</p>
|
| 2992 |
+
<p><strong>Initial Centroids:</strong> c₁ = [3, 4], c₂ = [5, 1]</p>
|
| 2993 |
+
|
| 2994 |
+
<div class="formula">
|
| 2995 |
+
<strong>Distance Formula (Euclidean):</strong><br>
|
| 2996 |
+
d(point, centroid) = √[(x₁-x₂)² + (y₁-y₂)²]
|
| 2997 |
+
</div>
|
| 2998 |
+
|
| 2999 |
+
<h4>Iteration 1</h4>
|
| 3000 |
+
|
| 3001 |
+
<div class="formula">
|
| 3002 |
+
<strong>Step 1: Calculate Distances to All Centroids</strong><br>
|
| 3003 |
+
<br>
|
| 3004 |
+
<strong>Point A (1, 2):</strong><br>
|
| 3005 |
+
d(A, c₁) = √[(1-3)² + (2-4)²] = √[4+4] = √8 = 2.83<br>
|
| 3006 |
+
d(A, c₂) = √[(1-5)² + (2-1)²] = √[16+1] = √17 = 4.12<br>
|
| 3007 |
+
→ Assign to c₁ (closer)<br>
|
| 3008 |
+
<br>
|
| 3009 |
+
<strong>Point B (1.5, 1.8):</strong><br>
|
| 3010 |
+
d(B, c₁) = √[(1.5-3)² + (1.8-4)²] = √[2.25+4.84] = 2.66<br>
|
| 3011 |
+
d(B, c₂) = √[(1.5-5)² + (1.8-1)²] = √[12.25+0.64] = 3.59<br>
|
| 3012 |
+
→ Assign to c₁<br>
|
| 3013 |
+
<br>
|
| 3014 |
+
<strong>Point C (5, 8):</strong><br>
|
| 3015 |
+
d(C, c₁) = √[(5-3)² + (8-4)²] = √[4+16] = 4.47<br>
|
| 3016 |
+
d(C, c₂) = √[(5-5)² + (8-1)²] = √[0+49] = 7.0<br>
|
| 3017 |
+
→ Assign to c₁<br>
|
| 3018 |
+
<br>
|
| 3019 |
+
<strong>Point D (8, 8):</strong><br>
|
| 3020 |
+
d(D, c₁) = √[(8-3)² + (8-4)²] = √[25+16] = 6.40<br>
|
| 3021 |
+
d(D, c₂) = √[(8-5)² + (8-1)²] = √[9+49] = 7.62<br>
|
| 3022 |
+
→ Assign to c₁<br>
|
| 3023 |
+
<br>
|
| 3024 |
+
<strong>Point E (1, 0.6):</strong><br>
|
| 3025 |
+
d(E, c₁) = √[(1-3)² + (0.6-4)²] = √[4+11.56] = 3.94<br>
|
| 3026 |
+
d(E, c₂) = √[(1-5)² + (0.6-1)²] = √[16+0.16] = 4.02<br>
|
| 3027 |
+
→ Assign to c₁<br>
|
| 3028 |
+
<br>
|
| 3029 |
+
<strong>Point F (9, 11):</strong><br>
|
| 3030 |
+
d(F, c₁) = √[(9-3)² + (11-4)²] = √[36+49] = 9.22<br>
|
| 3031 |
+
d(F, c₂) = √[(9-5)² + (11-1)²] = √[16+100] = 10.77<br>
|
| 3032 |
+
→ Assign to c₁<br>
|
| 3033 |
+
<br>
|
| 3034 |
+
<strong>Result:</strong> Cluster 1 = {A, B, C, D, E, F}, Cluster 2 = {}
|
| 3035 |
+
</div>
|
| 3036 |
+
|
| 3037 |
+
<div class="callout warning">
|
| 3038 |
+
<div class="callout-title">⚠️ Poor Initial Centroids!</div>
|
| 3039 |
+
<div class="callout-content">
|
| 3040 |
+
All points assigned to c₁! This happens with bad initialization. Let's try better initial centroids for the algorithm to work properly.
|
| 3041 |
+
</div>
|
| 3042 |
+
</div>
|
| 3043 |
+
|
| 3044 |
+
<p><strong>Better Initial Centroids:</strong> c₁ = [1, 1], c₂ = [8, 9]</p>
|
| 3045 |
+
|
| 3046 |
+
<div class="formula">
|
| 3047 |
+
<strong>Iteration 1 (Revised):</strong><br>
|
| 3048 |
+
<br>
|
| 3049 |
+
Cluster 1: {A, B, E} → c₁_new = mean = [(1+1.5+1)/3, (2+1.8+0.6)/3] = [1.17, 1.47]<br>
|
| 3050 |
+
Cluster 2: {C, D, F} → c₂_new = mean = [(5+8+9)/3, (8+8+11)/3] = [7.33, 9.00]<br>
|
| 3051 |
+
<br>
|
| 3052 |
+
<strong>WCSS Calculation:</strong><br>
|
| 3053 |
+
WCSS₁ = d²(A,c₁) + d²(B,c₁) + d²(E,c₁)<br>
|
| 3054 |
+
= (1-1.17)²+(2-1.47)² + (1.5-1.17)²+(1.8-1.47)² + (1-1.17)²+(0.6-1.47)²<br>
|
| 3055 |
+
= 0.311 + 0.218 + 0.786 = 1.315<br>
|
| 3056 |
+
<br>
|
| 3057 |
+
WCSS₂ = d²(C,c₂) + d²(D,c₂) + d²(F,c₂)<br>
|
| 3058 |
+
= (5-7.33)²+(8-9)² + (8-7.33)²+(8-9)² + (9-7.33)²+(11-9)²<br>
|
| 3059 |
+
= 6.433 + 1.447 + 6.789 = 14.669<br>
|
| 3060 |
+
<br>
|
| 3061 |
+
<strong>Total WCSS = 1.315 + 14.669 = 15.984</strong>
|
| 3062 |
+
</div>
|
| 3063 |
+
|
| 3064 |
+
<div class="formula">
|
| 3065 |
+
<strong>Iteration 2:</strong><br>
|
| 3066 |
+
<br>
|
| 3067 |
+
Using c₁ = [1.17, 1.47] and c₂ = [7.33, 9.00], recalculate distances...<br>
|
| 3068 |
+
<br>
|
| 3069 |
+
Result: Same assignments! Centroids don't change.<br>
|
| 3070 |
+
<strong>✓ Converged!</strong>
|
| 3071 |
+
</div>
|
| 3072 |
+
|
| 3073 |
+
<div class="figure">
|
| 3074 |
+
<div class="figure-placeholder" style="height: 450px">
|
| 3075 |
+
<canvas id="kmeans-viz-canvas"></canvas>
|
| 3076 |
+
</div>
|
| 3077 |
+
<p class="figure-caption"><strong>Figure:</strong> K-means clustering visualization with centroid movement</p>
|
| 3078 |
+
</div>
|
| 3079 |
+
|
| 3080 |
+
<h3>Finding Optimal K: The Elbow Method</h3>
|
| 3081 |
+
|
| 3082 |
+
<p>How do we choose K? Try different values and plot WCSS!</p>
|
| 3083 |
+
|
| 3084 |
+
<div class="formula">
|
| 3085 |
+
<strong>WCSS for Different K Values:</strong><br>
|
| 3086 |
+
<br>
|
| 3087 |
+
K=1: WCSS = 50.0 (all in one cluster)<br>
|
| 3088 |
+
K=2: WCSS = 18.0<br>
|
| 3089 |
+
K=3: WCSS = 10.0 ← Elbow point!<br>
|
| 3090 |
+
K=4: WCSS = 8.0<br>
|
| 3091 |
+
K=5: WCSS = 7.0<br>
|
| 3092 |
+
<br>
|
| 3093 |
+
<strong>Rule:</strong> Choose K at the "elbow" where WCSS stops decreasing rapidly
|
| 3094 |
+
</div>
|
| 3095 |
+
|
| 3096 |
+
<div class="figure">
|
| 3097 |
+
<div class="figure-placeholder" style="height: 400px">
|
| 3098 |
+
<canvas id="kmeans-elbow-canvas"></canvas>
|
| 3099 |
+
</div>
|
| 3100 |
+
<p class="figure-caption"><strong>Figure:</strong> Elbow method - optimal K is where the curve bends</p>
|
| 3101 |
+
</div>
|
| 3102 |
+
|
| 3103 |
+
<div class="callout info">
|
| 3104 |
+
<div class="callout-title">💡 K-means Tips</div>
|
| 3105 |
+
<div class="callout-content">
|
| 3106 |
+
<strong>Advantages:</strong><br>
|
| 3107 |
+
✓ Simple and fast<br>
|
| 3108 |
+
✓ Works well with spherical clusters<br>
|
| 3109 |
+
✓ Scales to large datasets<br>
|
| 3110 |
+
<br>
|
| 3111 |
+
<strong>Disadvantages:</strong><br>
|
| 3112 |
+
✗ Need to specify K in advance<br>
|
| 3113 |
+
✗ Sensitive to initial centroids (use K-means++!)<br>
|
| 3114 |
+
✗ Assumes spherical clusters<br>
|
| 3115 |
+
✗ Sensitive to outliers<br>
|
| 3116 |
+
<br>
|
| 3117 |
+
<strong>Solutions:</strong><br>
|
| 3118 |
+
• Use elbow method for K<br>
|
| 3119 |
+
• Use K-means++ initialization<br>
|
| 3120 |
+
• Run multiple times with different initializations
|
| 3121 |
+
</div>
|
| 3122 |
+
</div>
|
| 3123 |
+
|
| 3124 |
+
<h3>Real-World Applications</h3>
|
| 3125 |
+
<ul>
|
| 3126 |
+
<li><strong>Customer Segmentation:</strong> Group customers by behavior</li>
|
| 3127 |
+
<li><strong>Image Compression:</strong> Reduce colors in images</li>
|
| 3128 |
+
<li><strong>Document Clustering:</strong> Group similar articles</li>
|
| 3129 |
+
<li><strong>Anomaly Detection:</strong> Points far from centroids are outliers</li>
|
| 3130 |
+
<li><strong>Feature Learning:</strong> Learn representations for neural networks</li>
|
| 3131 |
+
</ul>
|
| 3132 |
+
</div>
|
| 3133 |
+
</div>
|
| 3134 |
+
|
| 3135 |
+
<!-- Section 17: Decision Trees -->
|
| 3136 |
<div class="section" id="decision-trees">
|
| 3137 |
<div class="section-header">
|
| 3138 |
<h2>16. Decision Trees</h2>
|
|
|
|
| 3290 |
</div>
|
| 3291 |
</div>
|
| 3292 |
|
| 3293 |
+
<!-- Section 18: Ensemble Methods -->
|
| 3294 |
<div class="section" id="ensemble-methods">
|
| 3295 |
<div class="section-header">
|
| 3296 |
+
<h2>18. Ensemble Methods</h2>
|
| 3297 |
<button class="section-toggle">▼</button>
|
| 3298 |
</div>
|
| 3299 |
<div class="section-body">
|