🚀 Stage 2 of 13
←
→
← Previous — Stage 1
Meet the dataset — 4 questions you always ask
3 plots that tell you if ML is even possible
Scatter plot of each feature vs the target. If there's no visible relationship, ML can't magically find one.
🧠 The intuition
Before training, plot each feature against the target. You're looking for ANY visible trend — a cloud is fine, but a flat horizontal line means that feature is useless.
Why this matters: ML can only learn what's in the data. If study_hours vs final_score is a flat cloud, no model in the world can use study_hours to predict final_score. You'd be wasting your time adding it as a feature.
3 plots, 3 questions:
1. study_hours vs final_score -> do studiers score higher?
2. attendance vs final_score -> do attendees score higher?
3. previous_score vs final_score -> is past performance predictive?
✏️ Tiny task — write this yourself
Make ONE scatter plot of study_hours vs final_score. Just one. Don't try to make it pretty.
import matplotlib.pyplot as plt
df.plot.scatter(x='study_hours', y='final_score')
plt.show()
✅ Check — what you should see
You should see a cloud that trends UP-AND-TO-THE-RIGHT. If you see a flat horizontal line, ML on this feature is hopeless. If you see a clean diagonal, ML will be easy.
🧮 Code files for this stage
📄
explore_plots.py
python
import pandas as pd
import matplotlib.pyplot as plt
df = pd.read_csv('data/students.csv')
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# Plot 1: study_hours vs final_score
df.plot.scatter(x='study_hours', y='final_score', ax=axes[0], alpha=0.5)
axes[0].set_title('Study hours vs Final score')
# Plot 2: attendance vs final_score
df.plot.scatter(x='attendance', y='final_score', ax=axes[1], alpha=0.5, color='green')
axes[1].set_title('Attendance vs Final score')
# Plot 3: previous_score vs final_score
df.plot.scatter(x='previous_score', y='final_score', ax=axes[2], alpha=0.5, color='orange')
axes[2].set_title('Previous score vs Final score')
plt.tight_layout()
plt.savefig('data/explore.png', dpi=100)
plt.show()
How it works
Each subplot answers one question. If plot 1 trends up, study time matters. If plot 3 is a tight diagonal, previous_score is the strongest predictor (it usually is — past performance is the best predictor of future performance). If a plot is a flat cloud, drop that feature. The point isn't to make pretty charts — it's to decide which features deserve to be in your model.
🚧 Routes — what's wired up at this stage
Still no routes. Visualization runs offline, in a notebook or script. The web app will surface these plots later (Stage 11) — but for now we're just exploring the data.
🧮 Is a response model necessary here?
NO — use response_class=HTMLResponse
Matplotlib returns a Figure object, not JSON. No response model needed.
⚠️ Common mistakes to avoid
- Plotting all 8 features at once in a correlation matrix and being overwhelmed. Plot 3, look, decide, move on.
- Skipping this step entirely and going straight to model.fit() — you'll have no idea why the model is bad.
- Making plots pretty (titles, colors, legends) before checking if they show a trend. Pretty but useless is still useless.
Next — Stage 3
Clean the data + split into X and y