| |
| const workflowData = { |
| "title": "Робочий процес науки про дані", |
| "introduction": "Кожен проект з науки про дані включає кілька важливих етапів. Ця інтерактивна панель допоможе вам зрозуміти кожен етап робочого процесу та його важливість.", |
| "steps": [ |
| { |
| "id": 1, |
| "title": "Формулювання проблеми", |
| "shortTitle": "Проблема", |
| "description": "Кожен проект з науки про дані починається з визначення проблеми. Незалежно від того, чи це прогнозування результатів пацієнтів або оптимізація бізнес-операцій, переклад реальної проблеми у питання, що базується на даних, є вирішальним.", |
| "keyPoints": [ |
| "Визначення конкретної проблеми, яку потрібно вирішити", |
| "Формулювання питань, на які потрібно відповісти за допомогою даних", |
| "Вибір підходу до вирішення (машинне навчання, статистичний аналіз тощо)" |
| ], |
| "example": "У галузі охорони здоров'я, прогнозування часу відновлення пацієнта на основі медичної історії. Формулювання проблеми: лікарям потрібен інструмент для прогнозування тривалості відновлення пацієнта після лікування.", |
| "tips": [ |
| "Завжди консультуйтеся з експертами в предметній області", |
| "Переконайтеся, що проблема може бути вирішена за допомогою даних", |
| "Визначте чіткі критерії успіху" |
| ], |
| "quiz": [ |
| { |
| "question": "Що є першим кроком у проекті науки про дані?", |
| "options": [ |
| "Збір даних", |
| "Визначення проблеми", |
| "Побудова моделі", |
| "Оцінка результатів" |
| ], |
| "answer": 1 |
| } |
| ] |
| }, |
| { |
| "id": 2, |
| "title": "Збір даних", |
| "shortTitle": "Дані", |
| "description": "Наступним кроком є збір відповідних даних з надійних джерел. Це може включати бази даних, публічні набори даних або дані, зібрані через сенсори та додатки.", |
| "keyPoints": [ |
| "Визначення потрібних даних для вирішення проблеми", |
| "Ідентифікація джерел даних", |
| "Розуміння регуляторних вимог та етичних міркувань" |
| ], |
| "example": "Збір клінічних записів з баз даних охорони здоров'я для аналізу часу відновлення пацієнтів.", |
| "tips": [ |
| "Переконайтеся, що ви маєте дозвіл на використання даних", |
| "Перевірте якість та надійність джерел даних", |
| "Зберігайте дані безпечно та відповідно до норм" |
| ], |
| "quiz": [ |
| { |
| "question": "Що Ендрю Нг назвав 'їжею для ШІ'?", |
| "options": [ |
| "Алгоритми", |
| "Дані", |
| "Обчислювальні потужності", |
| "Програмний код" |
| ], |
| "answer": 1 |
| } |
| ] |
| }, |
| { |
| "id": 3, |
| "title": "Підготовка даних", |
| "shortTitle": "Підготовка", |
| "description": "Сирі дані часто містять невідповідності, відсутні значення або викиди. Підготовка даних забезпечує, що дані чисті та стандартизовані.", |
| "keyPoints": [ |
| "Очищення даних від невідповідностей", |
| "Обробка відсутніх значень", |
| "Нормалізація та стандартизація даних" |
| ], |
| "example": "Очищення клінічних даних для забезпечення послідовності в аналізі.", |
| "tips": [ |
| "Документуйте всі зміни, внесені до вихідних даних", |
| "Використовуйте автоматизовані інструменти для очищення великих наборів даних", |
| "Перевірте дані після очищення, щоб переконатися, що вони все ще відображають реальність" |
| ], |
| "quiz": [ |
| { |
| "question": "Які проблеми вирішує етап підготовки даних?", |
| "options": [ |
| "Невідповідності, відсутні значення, викиди", |
| "Формулювання проблеми та вибір алгоритму", |
| "Вибір метрик оцінки", |
| "Розгортання моделі в виробництво" |
| ], |
| "answer": 0 |
| } |
| ] |
| }, |
| { |
| "id": 4, |
| "title": "Моделювання", |
| "shortTitle": "Модель", |
| "description": "Вибір правильного алгоритму є критичним. В залежності від проблеми, ми можемо використовувати регресію, класифікацію або кластеризацію, тощо.", |
| "keyPoints": [ |
| "Вибір алгоритму на основі типу проблеми", |
| "Оцінка доступних даних (кількість та якість)", |
| "Врахування обчислювальних ресурсів та часу навчання" |
| ], |
| "example": "Вибір алгоритму машинного навчання для прогнозування часу відновлення пацієнта на основі історичних даних.", |
| "tips": [ |
| "Почніть з простих моделей перед переходом до складніших", |
| "Розділіть дані на тренувальні та тестові набори", |
| "Експериментуйте з різними алгоритмами для порівняння результатів" |
| ], |
| "quiz": [ |
| { |
| "question": "Які фактори слід враховувати при виборі алгоритму?", |
| "options": [ |
| "Тільки тип проблеми", |
| "Тільки обчислювальні ресурси", |
| "Тип проблеми, доступні дані та обчислювальні ресурси", |
| "Тільки розмір набору даних" |
| ], |
| "answer": 2 |
| } |
| ] |
| }, |
| { |
| "id": 5, |
| "title": "Оцінювання", |
| "shortTitle": "Оцінка", |
| "description": "Після навчання, оцінка моделі є важливою для забезпечення точності та надійності.", |
| "keyPoints": [ |
| "Вибір відповідних метрик для оцінки моделі", |
| "Порівняння результатів з бізнес-цілями", |
| "Виявлення областей для покращення" |
| ], |
| "example": "Оцінка моделі для виявлення ранніх симптомів захворювання за допомогою метрик точності, чутливості та специфічності.", |
| "tips": [ |
| "Використовуйте метрики, що відповідають бізнес-цілям", |
| "Проведіть крос-валідацію для надійності оцінки", |
| "Порівняйте результати з базовими моделями" |
| ], |
| "quiz": [ |
| { |
| "question": "Які метрики можуть використовуватися для оцінки моделі?", |
| "options": [ |
| "Тільки точність (accuracy)", |
| "Точність, повнота, F1-оцінка та інші", |
| "Тільки час навчання", |
| "Тільки розмір моделі" |
| ], |
| "answer": 1 |
| } |
| ] |
| }, |
| { |
| "id": 6, |
| "title": "Розгортання", |
| "shortTitle": "Розгортання", |
| "description": "Розгортання — це процес інтеграції навченої моделі в виробниче середовище, роблячи її доступною для реального використання. Цей крок є вирішальним для забезпечення того, щоб прогнози моделі були постійно доступні та надійні для кінцевих користувачів або автоматизованих систем.", |
| "keyPoints": [ |
| "Контейнеризація моделі для портативності", |
| "Створення API для доступу до моделі", |
| "Налаштування безперервної інтеграції та доставки (CI/CD)", |
| "Забезпечення масштабованості та доступності" |
| ], |
| "example": "Розгортання моделі прогнозування часу відновлення пацієнта в хмарній платформі (AWS, Azure) та інтеграція з системою електронних медичних карт через API.", |
| "tips": [ |
| "Тестуйте модель в середовищі, подібному до виробничого", |
| "Впровадіть моніторинг для відстеження продуктивності", |
| "Плануйте для масштабування від початку" |
| ], |
| "quiz": [ |
| { |
| "question": "Що таке контейнеризація в контексті розгортання моделі?", |
| "options": [ |
| "Упаковка моделі в фізичний контейнер для транспортування", |
| "Упаковка моделі, залежностей і середовища в програмний контейнер (як Docker)", |
| "Обмеження доступу до моделі", |
| "Зменшення розміру моделі" |
| ], |
| "answer": 1 |
| } |
| ] |
| }, |
| { |
| "id": 7, |
| "title": "Моніторинг та підтримка", |
| "shortTitle": "Моніторинг", |
| "description": "Моделі потребують постійного моніторингу, щоб залишатися точними та ефективними. Зміни в розподілі даних можуть погіршити продуктивність з часом.", |
| "keyPoints": [ |
| "Відстеження продуктивності моделі в реальному часі", |
| "Виявлення зміщення даних (data drift)", |
| "Регулярне перенавчання моделі з новими даними", |
| "Автоматизація розгортання оновлених моделей" |
| ], |
| "example": "Використання інструментів моніторингу, таких як Prometheus і Grafana, для відстеження точності моделі прогнозування часу відновлення пацієнта та виявлення будь-яких змін у розподілі даних.", |
| "tips": [ |
| "Встановіть сповіщення для виявлення зниження продуктивності", |
| "Плануйте регулярні огляди моделі", |
| "Документуйте всі зміни та оновлення" |
| ], |
| "quiz": [ |
| { |
| "question": "Чому важливий моніторинг моделі після розгортання?", |
| "options": [ |
| "Він не важливий, якщо модель добре навчена", |
| "Тільки для задоволення регуляторних вимог", |
| "Для виявлення зміщення даних та підтримки продуктивності моделі", |
| "Тільки для економії обчислювальних ресурсів" |
| ], |
| "answer": 2 |
| } |
| ] |
| } |
| ] |
| }; |
|
|
| |
| let currentStepId = null; |
| let visitedSteps = new Set(); |
| let selectedQuizOption = null; |
| let quizAnswered = false; |
|
|
| |
| const stepIcons = { |
| 1: '❓', |
| 2: '📊', |
| 3: '🔧', |
| 4: '🤖', |
| 5: '📈', |
| 6: '🚀', |
| 7: '👁️' |
| }; |
|
|
| |
| document.addEventListener('DOMContentLoaded', function() { |
| initializeApp(); |
| setupEventListeners(); |
| }); |
|
|
| function initializeApp() { |
| |
| document.getElementById('introText').textContent = workflowData.introduction; |
| |
| |
| renderSidebar(); |
| |
| |
| renderWorkflowDiagram(); |
| |
| |
| updateProgress(); |
| |
| |
| document.getElementById('stepDetailsSection').classList.remove('active'); |
| } |
|
|
| function setupEventListeners() { |
| |
| document.getElementById('nextStepBtn').addEventListener('click', () => navigateStep(1)); |
| document.getElementById('prevStepBtn').addEventListener('click', () => navigateStep(-1)); |
| |
| |
| document.getElementById('resetProgressBtn').addEventListener('click', resetProgress); |
| |
| |
| document.getElementById('checkAnswerBtn').addEventListener('click', checkQuizAnswer); |
| } |
|
|
| function renderSidebar() { |
| const sidebarList = document.getElementById('sidebarStepsList'); |
| sidebarList.innerHTML = ''; |
| |
| workflowData.steps.forEach(step => { |
| const listItem = document.createElement('li'); |
| |
| const link = document.createElement('a'); |
| link.href = '#'; |
| link.className = 'step-link'; |
| link.dataset.stepId = step.id; |
| |
| const stepNumber = document.createElement('span'); |
| stepNumber.className = 'step-number'; |
| stepNumber.textContent = step.id; |
| |
| const stepTitle = document.createElement('span'); |
| stepTitle.textContent = step.shortTitle; |
| |
| link.appendChild(stepNumber); |
| link.appendChild(stepTitle); |
| |
| link.addEventListener('click', (e) => { |
| e.preventDefault(); |
| showStepDetails(step.id); |
| }); |
| |
| listItem.appendChild(link); |
| sidebarList.appendChild(listItem); |
| }); |
| } |
|
|
| function renderWorkflowDiagram() { |
| const diagram = document.getElementById('workflowDiagram'); |
| diagram.innerHTML = ''; |
| |
| workflowData.steps.forEach(step => { |
| const stepElement = document.createElement('div'); |
| stepElement.className = 'workflow-step'; |
| stepElement.dataset.stepId = step.id; |
| |
| const icon = document.createElement('div'); |
| icon.className = 'step-icon'; |
| icon.textContent = stepIcons[step.id] || '⚡'; |
| |
| const title = document.createElement('h3'); |
| title.textContent = step.shortTitle; |
| |
| stepElement.appendChild(icon); |
| stepElement.appendChild(title); |
| |
| stepElement.addEventListener('click', () => { |
| showStepDetails(step.id); |
| }); |
| |
| diagram.appendChild(stepElement); |
| }); |
| } |
|
|
| function showStepDetails(stepId) { |
| const step = workflowData.steps.find(s => s.id === stepId); |
| if (!step) return; |
| |
| currentStepId = stepId; |
| visitedSteps.add(stepId); |
| |
| |
| updateActiveStates(); |
| |
| |
| document.getElementById('stepTitle').textContent = step.title; |
| document.getElementById('stepDescription').textContent = step.description; |
| |
| |
| const keyPointsList = document.getElementById('stepKeyPoints'); |
| keyPointsList.innerHTML = ''; |
| step.keyPoints.forEach(point => { |
| const li = document.createElement('li'); |
| li.textContent = point; |
| keyPointsList.appendChild(li); |
| }); |
| |
| |
| document.getElementById('stepExample').textContent = step.example; |
| |
| |
| const tipsList = document.getElementById('stepTips'); |
| tipsList.innerHTML = ''; |
| step.tips.forEach(tip => { |
| const li = document.createElement('li'); |
| li.textContent = tip; |
| tipsList.appendChild(li); |
| }); |
| |
| |
| setupQuiz(step.quiz[0]); |
| |
| |
| document.getElementById('introSection').style.display = 'none'; |
| document.getElementById('stepDetailsSection').classList.add('active'); |
| |
| |
| updateNavigationButtons(); |
| |
| |
| updateProgress(); |
| |
| |
| document.getElementById('stepDetailsSection').scrollIntoView({ behavior: 'smooth' }); |
| } |
|
|
| function updateActiveStates() { |
| |
| document.querySelectorAll('.step-link').forEach(link => { |
| const stepId = parseInt(link.dataset.stepId); |
| link.classList.remove('active'); |
| if (visitedSteps.has(stepId)) { |
| link.classList.add('visited'); |
| } |
| if (stepId === currentStepId) { |
| link.classList.add('active'); |
| } |
| }); |
| |
| |
| document.querySelectorAll('.workflow-step').forEach(step => { |
| const stepId = parseInt(step.dataset.stepId); |
| step.classList.remove('active'); |
| if (visitedSteps.has(stepId)) { |
| step.classList.add('visited'); |
| } |
| if (stepId === currentStepId) { |
| step.classList.add('active'); |
| } |
| }); |
| } |
|
|
| function setupQuiz(quiz) { |
| document.getElementById('quizQuestion').textContent = quiz.question; |
| |
| const optionsContainer = document.getElementById('quizOptions'); |
| optionsContainer.innerHTML = ''; |
| |
| quiz.options.forEach((option, index) => { |
| const optionElement = document.createElement('div'); |
| optionElement.className = 'quiz-option'; |
| optionElement.textContent = option; |
| optionElement.dataset.index = index; |
| |
| optionElement.addEventListener('click', () => { |
| if (quizAnswered) return; |
| |
| document.querySelectorAll('.quiz-option').forEach(opt => { |
| opt.classList.remove('selected'); |
| }); |
| optionElement.classList.add('selected'); |
| selectedQuizOption = index; |
| }); |
| |
| optionsContainer.appendChild(optionElement); |
| }); |
| |
| |
| selectedQuizOption = null; |
| quizAnswered = false; |
| document.getElementById('quizResult').classList.remove('show', 'correct', 'incorrect'); |
| document.getElementById('checkAnswerBtn').style.display = 'block'; |
| } |
|
|
| function checkQuizAnswer() { |
| if (selectedQuizOption === null) { |
| alert('Будь ласка, оберіть відповідь'); |
| return; |
| } |
| |
| const step = workflowData.steps.find(s => s.id === currentStepId); |
| const quiz = step.quiz[0]; |
| const isCorrect = selectedQuizOption === quiz.answer; |
| |
| |
| const resultElement = document.getElementById('quizResult'); |
| resultElement.classList.add('show'); |
| |
| if (isCorrect) { |
| resultElement.classList.add('correct'); |
| resultElement.textContent = '✅ Правильно! Відмінна робота!'; |
| } else { |
| resultElement.classList.add('incorrect'); |
| resultElement.textContent = `❌ Неправильно. Правильна відповідь: ${quiz.options[quiz.answer]}`; |
| } |
| |
| |
| document.querySelectorAll('.quiz-option').forEach((option, index) => { |
| if (index === quiz.answer) { |
| option.classList.add('correct'); |
| } else if (index === selectedQuizOption && !isCorrect) { |
| option.classList.add('incorrect'); |
| } |
| }); |
| |
| quizAnswered = true; |
| document.getElementById('checkAnswerBtn').style.display = 'none'; |
| } |
|
|
| function navigateStep(direction) { |
| if (!currentStepId) return; |
| |
| const currentIndex = workflowData.steps.findIndex(s => s.id === currentStepId); |
| const newIndex = currentIndex + direction; |
| |
| if (newIndex >= 0 && newIndex < workflowData.steps.length) { |
| showStepDetails(workflowData.steps[newIndex].id); |
| } |
| } |
|
|
| function updateNavigationButtons() { |
| const currentIndex = workflowData.steps.findIndex(s => s.id === currentStepId); |
| |
| document.getElementById('prevStepBtn').disabled = currentIndex === 0; |
| document.getElementById('nextStepBtn').disabled = currentIndex === workflowData.steps.length - 1; |
| } |
|
|
| function updateProgress() { |
| const totalSteps = workflowData.steps.length; |
| const completedSteps = visitedSteps.size; |
| const percentage = (completedSteps / totalSteps) * 100; |
| |
| document.getElementById('progressFill').style.width = `${percentage}%`; |
| document.getElementById('progressText').textContent = `${completedSteps}/${totalSteps} етапів вивчено`; |
| } |
|
|
| function resetProgress() { |
| if (confirm('Ви впевнені, що хочете скинути свій прогрес?')) { |
| visitedSteps.clear(); |
| currentStepId = null; |
| |
| |
| document.getElementById('stepDetailsSection').classList.remove('active'); |
| document.getElementById('introSection').style.display = 'block'; |
| |
| |
| updateActiveStates(); |
| updateProgress(); |
| |
| |
| window.scrollTo({ top: 0, behavior: 'smooth' }); |
| } |
| } |