| <!DOCTYPE html>
|
| <html lang="en">
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>Random Forest Regression Demo</title>
|
| <script src="https://cdn.tailwindcss.com"></script>
|
| <style>
|
| .tree-path {
|
| stroke-dasharray: 1000;
|
| stroke-dashoffset: 1000;
|
| animation: dash 2s linear forwards;
|
| }
|
| @keyframes dash {
|
| to { stroke-dashoffset: 0; }
|
| }
|
| .bounce { animation: bounce 0.5s infinite alternate; }
|
| @keyframes bounce {
|
| from { transform: translateY(0); }
|
| to { transform: translateY(-10px); }
|
| }
|
| </style>
|
| </head>
|
| <body class="bg-gray-50 min-h-screen">
|
| <div class="container mx-auto px-4 py-8 max-w-4xl">
|
| <h1 class="text-3xl font-bold text-center text-gray-800 mb-2">🌲 Random Forest Prediction Flow 🌲</h1>
|
| <p class="text-center text-gray-600 mb-8">See how your input travels through each decision tree</p>
|
|
|
|
|
| <div class="bg-white p-6 rounded-lg shadow-md mb-8">
|
| <h2 class="text-xl font-semibold mb-4 flex items-center">
|
| <span class="bg-blue-100 text-blue-800 rounded-full p-2 mr-2">1</span>
|
| User Input
|
| </h2>
|
| <div class="flex items-center justify-center gap-4">
|
| <input type="number" id="hoursInput" step="0.1" placeholder="Enter hours (e.g. 5.5)"
|
| class="border px-4 py-2 rounded-lg w-48 border-gray-300 focus:outline-blue-500">
|
| <button id="predictBtn"
|
| class="bg-green-600 text-white px-6 py-2 rounded-lg hover:bg-green-700 transition">
|
| Predict Score
|
| </button>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="bg-white p-6 rounded-lg shadow-md mb-8 hidden" id="trainTestSection">
|
| <h2 class="text-xl font-semibold mb-4 flex items-center">
|
| <span class="bg-purple-100 text-purple-800 rounded-full p-2 mr-2">2</span>
|
| Data Preparation (Train/Test Split)
|
| </h2>
|
| <div class="grid grid-cols-2 gap-4">
|
| <div class="border-2 border-green-400 p-4 rounded-lg">
|
| <h3 class="font-bold text-green-700 mb-2">Training Data (80%)</h3>
|
| <div class="grid grid-cols-3 gap-2" id="trainingData"></div>
|
| </div>
|
| <div class="border-2 border-red-400 p-4 rounded-lg">
|
| <h3 class="font-bold text-red-700 mb-2">Test Data (20%)</h3>
|
| <div class="grid grid-cols-3 gap-2" id="testData"></div>
|
| </div>
|
| </div>
|
| <div class="mt-4">
|
| <canvas id="dataPlot" width="400" height="300"></canvas>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="bg-white p-6 rounded-lg shadow-md hidden" id="treePredictionsSection">
|
| <h2 class="text-xl font-semibold mb-4 flex items-center">
|
| <span class="bg-yellow-100 text-yellow-800 rounded-full p-2 mr-2">3</span>
|
| Tree Predictions (3 Example Trees)
|
| </h2>
|
| <div class="flex justify-between mb-6">
|
| <div class="text-center">
|
| <svg width="120" height="200" class="tree-animation mx-auto" id="tree1"></svg>
|
| <p class="mt-2">Tree 1 Prediction: <span id="tree1Pred" class="font-bold">?</span></p>
|
| <p id="tree1Explanation" class="text-sm text-gray-600"></p>
|
| </div>
|
| <div class="text-center">
|
| <svg width="120" height="200" class="tree-animation mx-auto" id="tree2"></svg>
|
| <p class="mt-2">Tree 2 Prediction: <span id="tree2Pred" class="font-bold">?</span></p>
|
| <p id="tree2Explanation" class="text-sm text-gray-600"></p>
|
| </div>
|
| <div class="text-center">
|
| <svg width="120" height="200" class="tree-animation mx-auto" id="tree3"></svg>
|
| <p class="mt-2">Tree 3 Prediction: <span id="tree3Pred" class="font-bold">?</span></p>
|
| <p id="tree3Explanation" class="text-sm text-gray-600"></p>
|
| </div>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="bg-white p-6 rounded-lg shadow-md hidden text-center" id="finalPredictionSection">
|
| <h2 class="text-xl font-semibold mb-4 flex items-center justify-center">
|
| <span class="bg-green-100 text-green-800 rounded-full p-2 mr-2">4</span>
|
| Final Prediction
|
| </h2>
|
| <div class="bg-green-50 border-2 border-green-200 rounded-lg p-8 inline-block">
|
| <p class="text-gray-700">Based on <span id="finalHours" class="font-bold">X</span> hours studied:</p>
|
| <p class="text-5xl font-bold text-green-700 my-4" id="finalPrediction">?</p>
|
| <p class="text-gray-600">(Average of all tree predictions)</p>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="text-center mt-8 hidden" id="restartSection">
|
| <button id="restartBtn" class="bg-blue-600 text-white px-6 py-2 rounded-lg hover:bg-blue-700 transition">
|
| Start Over
|
| </button>
|
| </div>
|
| </div>
|
|
|
| <script>
|
|
|
| const trainingData = [
|
| { hours: 1, score: 35 }, { hours: 2, score: 45 }, { hours: 3, score: 55 },
|
| { hours: 4, score: 65 }, { hours: 5, score: 75 }, { hours: 6, score: 80 },
|
| { hours: 7, score: 82 }, { hours: 8, score: 88 }, { hours: 9, score: 92 },
|
| { hours: 10, score: 95 }
|
| ];
|
|
|
|
|
| const testData = [];
|
| const shuffled = [...trainingData].sort(() => Math.random() - 0.5);
|
| trainingData.length = 8;
|
| testData.push(...shuffled.slice(8));
|
|
|
|
|
| function predictByTree(hours, treeType) {
|
| if (treeType === 1) {
|
| if (hours <= 5) {
|
| document.getElementById('tree1Explanation').textContent = "If hours <= 5, predict 65.";
|
| return 65;
|
| }
|
| if (hours <= 7) {
|
| document.getElementById('tree1Explanation').textContent = "If hours <= 7, predict 81.";
|
| return 81;
|
| }
|
| document.getElementById('tree1Explanation').textContent = "If hours > 7, predict 90.";
|
| return 90;
|
| } else if (treeType === 2) {
|
| if (hours <= 4) {
|
| document.getElementById('tree2Explanation').textContent = "If hours <= 4, predict 55.";
|
| return 55;
|
| }
|
| if (hours <= 8) {
|
| document.getElementById('tree2Explanation').textContent = "If hours <= 8, predict 75.";
|
| return 75;
|
| }
|
| document.getElementById('tree2Explanation').textContent = "If hours > 8, predict 92.";
|
| return 92;
|
| } else {
|
| if (hours <= 3) {
|
| document.getElementById('tree3Explanation').textContent = "If hours <= 3, predict 45.";
|
| return 45;
|
| }
|
| if (hours <= 6) {
|
| document.getElementById('tree3Explanation').textContent = "If hours <= 6, predict 72.";
|
| return 72;
|
| }
|
| document.getElementById('tree3Explanation').textContent = "If hours > 6, predict 88.";
|
| return 88;
|
| }
|
| }
|
|
|
| function drawTree(containerId, paths) {
|
| const svg = document.getElementById(containerId);
|
| svg.innerHTML = '';
|
|
|
|
|
| const pathsToDraw = [
|
|
|
| "M60,20 L60,60",
|
|
|
| "M60,60 L30,100",
|
| "M60,60 L90,100",
|
|
|
| "M30,100 L15,140",
|
| "M30,100 L45,140",
|
| "M90,100 L75,140",
|
| "M90,100 L105,140"
|
| ];
|
|
|
| pathsToDraw.forEach((path, i) => {
|
| const pathEl = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
| pathEl.setAttribute("d", path);
|
| pathEl.setAttribute("stroke", "#4B5563");
|
| pathEl.setAttribute("stroke-width", "2");
|
| pathEl.setAttribute("fill", "none");
|
| if (paths.includes(i)) pathEl.classList.add("tree-path");
|
| svg.appendChild(pathEl);
|
| });
|
| }
|
|
|
|
|
| function plotData() {
|
| const ctx = document.getElementById('dataPlot').getContext('2d');
|
| const trainingHours = trainingData.map(data => data.hours);
|
| const trainingScores = trainingData.map(data => data.score);
|
| const testHours = testData.map(data => data.hours);
|
| const testScores = testData.map(data => data.score);
|
|
|
| const data = {
|
| labels: trainingHours.concat(testHours),
|
| datasets: [
|
| {
|
| label: 'Training Data',
|
| data: trainingScores,
|
| backgroundColor: 'rgba(75, 192, 192, 0.6)',
|
| borderColor: 'rgba(75, 192, 192, 1)',
|
| borderWidth: 1,
|
| pointRadius: 5,
|
| pointHoverRadius: 7,
|
| },
|
| {
|
| label: 'Test Data',
|
| data: testScores,
|
| backgroundColor: 'rgba(255, 99, 132, 0.6)',
|
| borderColor: 'rgba(255, 99, 132, 1)',
|
| borderWidth: 1,
|
| pointRadius: 5,
|
| pointHoverRadius: 7,
|
| }
|
| ]
|
| };
|
|
|
| const config = {
|
| type: 'scatter',
|
| data: data,
|
| options: {
|
| responsive: true,
|
| scales: {
|
| x: {
|
| title: {
|
| display: true,
|
| text: 'Hours Studied'
|
| }
|
| },
|
| y: {
|
| title: {
|
| display: true,
|
| text: 'Exam Score'
|
| }
|
| }
|
| }
|
| }
|
| };
|
|
|
| const myChart = new Chart(ctx, config);
|
| }
|
|
|
|
|
| document.getElementById('predictBtn').addEventListener('click', () => {
|
| const hours = parseFloat(document.getElementById('hoursInput').value);
|
| if (isNaN(hours)) {
|
| alert("Please enter a valid number");
|
| return;
|
| }
|
|
|
|
|
| document.getElementById('trainTestSection').classList.remove('hidden');
|
|
|
|
|
| const trainingDiv = document.getElementById('trainingData');
|
| const testDiv = document.getElementById('testData');
|
|
|
| trainingData.forEach(item => {
|
| const div = document.createElement('div');
|
| div.className = 'bg-blue-100 p-1 rounded text-center text-xs';
|
| div.textContent = `${item.hours}h→${item.score}`;
|
| trainingDiv.appendChild(div);
|
| });
|
|
|
| testData.forEach(item => {
|
| const div = document.createElement('div');
|
| div.className = 'bg-red-100 p-1 rounded text-center text-xs';
|
| div.textContent = `${item.hours}h→${item.score}`;
|
| testDiv.appendChild(div);
|
| });
|
|
|
|
|
| plotData();
|
|
|
|
|
| setTimeout(() => {
|
| document.getElementById('treePredictionsSection').classList.remove('hidden');
|
|
|
|
|
| const pred1 = predictByTree(hours, 1);
|
| const pred2 = predictByTree(hours, 2);
|
| const pred3 = predictByTree(hours, 3);
|
|
|
|
|
| drawTree('tree1', [0, 1, 3]);
|
| drawTree('tree2', [0, 2, 5]);
|
| drawTree('tree3', [0, 1, 4]);
|
|
|
|
|
| setTimeout(() => {
|
| document.getElementById('tree1Pred').textContent = pred1;
|
| document.getElementById('tree2Pred').textContent = pred2;
|
| document.getElementById('tree3Pred').textContent = pred3;
|
|
|
|
|
| setTimeout(() => {
|
| document.getElementById('finalPredictionSection').classList.remove('hidden');
|
| document.getElementById('finalHours').textContent = hours;
|
| const finalPred = Math.round((pred1 + pred2 + pred3) / 3 * 10) / 10;
|
| document.getElementById('finalPrediction').textContent = finalPred;
|
| document.getElementById('restartSection').classList.remove('hidden');
|
| }, 1000);
|
| }, 2000);
|
| }, 1000);
|
| });
|
|
|
| document.getElementById('restartBtn').addEventListener('click', () => {
|
| location.reload();
|
| });
|
| </script>
|
| <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
| <a href="/random_forest" class="inline-block bg-gray-200 hover:bg-gray-300 text-gray-800 px-4 py-2 rounded shadow">
|
| ← Back to Random Forest Regression
|
| </a>
|
| </body>
|
| </html>
|
|
|