A data scientist extracts insights from data, builds predictive models, and translates findings into business decisions. This roadmap shows you exactly what to learn, in what order, and realistic timelines to go from zero to job-ready in 2025.
At a glance
| Phase |
Topics |
Time estimate |
| 1 |
Math & statistics foundations |
6–8 weeks |
| 2 |
Python for data science |
6–8 weeks |
| 3 |
Data manipulation and SQL |
4–6 weeks |
| 4 |
Data visualization |
2–3 weeks |
| 5 |
Machine learning |
8–12 weeks |
| 6 |
Deep learning and NLP |
6–10 weeks |
| 7 |
Data engineering basics |
4–6 weeks |
| 8 |
MLOps and deployment |
4–6 weeks |
| 9 |
Specialization (one area) |
4–8 weeks |
| 10 |
Portfolio + job search |
6–10 weeks |
| Total to first job |
|
~14–20 months |
Phase 1 — Math & statistics foundations (Weeks 1–8)
Data science runs on math. You don't need a PhD, but you need enough to understand what your models are actually doing.
Linear algebra
| Concept |
Why it matters |
| Vectors and matrices |
Features, weights, transformations |
| Matrix multiplication |
Neural network layers, PCA |
| Eigenvalues/eigenvectors |
PCA, Google PageRank |
| Dot product |
Similarity, cosine distance |
Calculus
- Derivatives — how loss functions change with weights
- Chain rule — backpropagation in neural networks
- Partial derivatives — gradient descent optimization
- You need the concept, not the manual computation (libraries handle the math)
Statistics (most important)
| Topic |
Practical use |
| Mean, median, mode, variance |
EDA, summarizing distributions |
| Normal distribution + 68-95-99.7 rule |
Understanding residuals, z-scores |
| Probability (Bayes' theorem) |
Naive Bayes, priors, A/B testing |
| Hypothesis testing (p-value, t-test, chi-square) |
A/B testing, feature significance |
| Confidence intervals |
Communicating uncertainty |
| Correlation vs causation |
Avoiding analysis mistakes |
| Central Limit Theorem |
Why we can use normal approximations |
| Type I / Type II errors |
False positives vs false negatives |
Resources: StatQuest with Josh Starmer (YouTube), Khan Academy Statistics.
Phase 2 — Python for data science (Weeks 9–16)
Python is the primary language of data science. Learn the language itself first, then the ecosystem.
Core Python
# List comprehensions
squares = [x**2 for x in range(10) if x % 2 == 0]
# Dictionary comprehension
word_count = {word: len(word) for word in ["hello", "world"]}
# Unpacking, *args, **kwargs
def summarize(data, *, decimals=2):
return round(sum(data) / len(data), decimals)
# Context managers
with open("data.csv") as f:
lines = f.readlines()
NumPy
import numpy as np
# Array operations (vectorized — no loops)
arr = np.array([1, 2, 3, 4, 5])
print(arr.mean(), arr.std(), arr.reshape(5, 1))
# Broadcasting
matrix = np.random.randn(100, 10)
normalized = (matrix - matrix.mean(axis=0)) / matrix.std(axis=0)
# Boolean indexing
positive = arr[arr > 2] # [3, 4, 5]
Pandas
import pandas as pd
df = pd.read_csv("data.csv")
print(df.info()) # dtypes, nulls
print(df.describe()) # stats per column
# Filtering
high_value = df[df["revenue"] > 10000]
# GroupBy aggregation
summary = df.groupby("region").agg(
total=("revenue", "sum"),
avg=("revenue", "mean"),
count=("revenue", "count")
).reset_index()
# Missing value handling
df["age"].fillna(df["age"].median(), inplace=True)
df.dropna(subset=["target"], inplace=True)
# Merging (like SQL JOIN)
merged = pd.merge(df_orders, df_customers, on="customer_id", how="left")
Essential Python data science stack
| Library |
Purpose |
| NumPy |
Fast array math |
| Pandas |
Data manipulation (tabular data) |
| Matplotlib |
Base plotting library |
| Seaborn |
Statistical visualizations |
| Scikit-learn |
Machine learning |
| Jupyter |
Interactive notebooks |
| SciPy |
Scientific computing, statistics |
| Statsmodels |
Statistical models (regression, time series) |
Phase 3 — Data manipulation and SQL (Weeks 17–22)
Every data scientist writes SQL daily. It's non-negotiable.
Core SQL
-- Aggregation + GROUP BY
SELECT
region,
COUNT(*) AS orders,
SUM(revenue) AS total_revenue,
AVG(revenue) AS avg_revenue
FROM orders
WHERE created_at >= '2025-01-01'
GROUP BY region
HAVING COUNT(*) > 100
ORDER BY total_revenue DESC;
-- JOINs
SELECT u.name, COUNT(o.id) AS order_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
GROUP BY u.id, u.name;
-- Window functions (essential for analytics)
SELECT
user_id,
revenue,
SUM(revenue) OVER (PARTITION BY user_id ORDER BY date) AS running_total,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY revenue DESC) AS rank
FROM orders;
-- CTE for readability
WITH monthly_revenue AS (
SELECT
DATE_TRUNC('month', created_at) AS month,
SUM(revenue) AS total
FROM orders
GROUP BY 1
)
SELECT
month,
total,
LAG(total) OVER (ORDER BY month) AS prev_month,
ROUND((total - LAG(total) OVER (ORDER BY month)) / LAG(total) OVER (ORDER BY month) * 100, 2) AS mom_growth
FROM monthly_revenue;
SQL window functions (data scientist must-knows)
| Function |
Use case |
ROW_NUMBER() |
Deduplicate, rank rows |
RANK() / DENSE_RANK() |
Leaderboards, ties |
LAG() / LEAD() |
Period-over-period comparison |
SUM() OVER |
Running totals, cumulative metrics |
AVG() OVER |
Moving averages |
NTILE(n) |
Quartile / percentile segmentation |
FIRST_VALUE() |
Cohort analysis, first event |
Data cleaning (the 70% of the job)
| Problem |
Pandas approach |
| Missing values |
fillna(), interpolate(), dropna() |
| Duplicates |
drop_duplicates() |
| Wrong types |
astype(), pd.to_datetime() |
| Outliers |
IQR filter, z-score filter, clip() |
| Inconsistent categories |
str.strip(), str.lower(), map() |
| Skewed distribution |
np.log1p() transform |
Phase 4 — Data visualization (Weeks 23–25)
Communicate insights clearly. Bad charts cost jobs.
import matplotlib.pyplot as plt
import seaborn as sns
# Seaborn statistical plots
sns.histplot(df["age"], bins=30, kde=True)
sns.boxplot(x="segment", y="revenue", data=df)
sns.heatmap(df.corr(), annot=True, cmap="coolwarm")
sns.pairplot(df[["feature1", "feature2", "target"]], hue="target")
# Matplotlib for custom plots
fig, axes = plt.subplots(1, 2, figsize=(12, 5))
axes[0].plot(dates, revenue, marker="o")
axes[0].set_title("Monthly Revenue")
axes[1].bar(categories, counts)
axes[1].set_title("Count by Category")
plt.tight_layout()
plt.savefig("report.png", dpi=150)
Chart type selection guide
| Situation |
Chart type |
| Distribution of one variable |
Histogram, KDE plot, box plot |
| Two continuous variables |
Scatter plot |
| Category comparison |
Bar chart, box plot |
| Time series |
Line chart |
| Part-to-whole |
Pie chart (use sparingly) or stacked bar |
| Correlation matrix |
Heatmap |
| Feature relationships |
Pair plot |
| Geographic data |
Choropleth map |
Dashboard tools
| Tool |
When to use |
| Matplotlib/Seaborn |
Static reports, publications |
| Plotly |
Interactive web charts |
| Streamlit |
Quick data apps / demos |
| Tableau / Power BI |
Business stakeholder dashboards |
| Looker / Metabase |
SQL-driven BI |
Phase 5 — Machine learning (Weeks 26–37)
Scikit-learn is the workhorse. Understand the math behind each algorithm, not just the API.
Supervised learning
from sklearn.ensemble import RandomForestClassifier, GradientBoostingRegressor
from sklearn.model_selection import train_test_split, cross_val_score
from sklearn.preprocessing import StandardScaler
from sklearn.pipeline import Pipeline
from sklearn.metrics import classification_report, mean_squared_error
import numpy as np
# Build a pipeline (preprocessing + model)
pipe = Pipeline([
("scaler", StandardScaler()),
("clf", RandomForestClassifier(n_estimators=100, random_state=42))
])
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
pipe.fit(X_train, y_train)
# Evaluate
print(classification_report(y_test, pipe.predict(X_test)))
scores = cross_val_score(pipe, X, y, cv=5, scoring="f1_macro")
print(f"CV F1: {scores.mean():.3f} ± {scores.std():.3f}")
ML algorithms you must know
| Algorithm |
Type |
When to use |
| Linear / Logistic Regression |
Supervised |
Baseline, interpretability |
| Decision Tree |
Supervised |
Explainable rules |
| Random Forest |
Supervised |
Tabular data, robust baseline |
| Gradient Boosting (XGBoost, LightGBM) |
Supervised |
Best tabular performance |
| SVM |
Supervised |
Small-medium datasets, high-dim |
| KNN |
Supervised |
Simple, non-parametric |
| K-Means |
Unsupervised |
Clustering |
| DBSCAN |
Unsupervised |
Density-based clusters, outliers |
| PCA |
Dimensionality reduction |
Feature reduction, visualization |
| t-SNE / UMAP |
Dimensionality reduction |
Visualization of high-dim data |
Model evaluation metrics
| Task |
Metrics |
| Binary classification |
Accuracy, Precision, Recall, F1, AUC-ROC |
| Multi-class |
Macro/Micro F1, Confusion Matrix |
| Regression |
RMSE, MAE, R², MAPE |
| Ranking |
NDCG, MAP |
| Clustering |
Silhouette score, Elbow method |
| Anomaly detection |
Precision@k, F1 at threshold |
Hyperparameter tuning
from sklearn.model_selection import RandomizedSearchCV
from scipy.stats import randint
param_dist = {
"clf__n_estimators": randint(50, 300),
"clf__max_depth": [None, 5, 10, 20],
"clf__min_samples_split": randint(2, 20),
}
search = RandomizedSearchCV(pipe, param_dist, n_iter=30, cv=5, scoring="f1", n_jobs=-1)
search.fit(X_train, y_train)
print(search.best_params_)
Phase 6 — Deep learning and NLP (Weeks 38–47)
Deep learning is now essential for NLP, computer vision, and many tabular tasks.
PyTorch basics
import torch
import torch.nn as nn
from torch.utils.data import DataLoader, TensorDataset
# Build a neural network
class MLP(nn.Module):
def __init__(self, in_features, hidden, out_features):
super().__init__()
self.net = nn.Sequential(
nn.Linear(in_features, hidden),
nn.ReLU(),
nn.Dropout(0.3),
nn.Linear(hidden, hidden // 2),
nn.ReLU(),
nn.Linear(hidden // 2, out_features)
)
def forward(self, x):
return self.net(x)
model = MLP(in_features=20, hidden=128, out_features=1)
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)
criterion = nn.BCEWithLogitsLoss()
# Training loop
for epoch in range(50):
for X_batch, y_batch in dataloader:
optimizer.zero_grad()
logits = model(X_batch).squeeze()
loss = criterion(logits, y_batch.float())
loss.backward()
optimizer.step()
NLP with Hugging Face Transformers
from transformers import AutoTokenizer, AutoModelForSequenceClassification
import torch
tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")
model = AutoModelForSequenceClassification.from_pretrained(
"distilbert-base-uncased", num_labels=2
)
inputs = tokenizer("This product is amazing!", return_tensors="pt", truncation=True)
with torch.no_grad():
logits = model(**inputs).logits
probs = torch.softmax(logits, dim=-1)
print(probs) # [negative, positive]
Deep learning concepts to know
| Concept |
Description |
| Backpropagation |
How gradients flow through layers |
| Activation functions |
ReLU, GELU, Sigmoid, Softmax |
| Batch normalization |
Stabilizes training, faster convergence |
| Dropout |
Regularization via random neuron deactivation |
| Learning rate schedulers |
CosineAnnealing, ReduceLROnPlateau |
| Transfer learning |
Fine-tune pre-trained models on new tasks |
| Transformers / Attention |
Foundation of modern NLP and vision |
| CNNs |
Image classification, feature extraction |
| RNNs / LSTMs |
Sequential data (mostly replaced by Transformers) |
Phase 7 — Data engineering basics (Weeks 48–53)
Data scientists who understand how data pipelines work get hired faster and promoted sooner.
Core concepts
# ETL with Pandas
import pandas as pd
def extract(source_path: str) -> pd.DataFrame:
return pd.read_csv(source_path)
def transform(df: pd.DataFrame) -> pd.DataFrame:
df = df.dropna(subset=["user_id", "revenue"])
df["revenue"] = df["revenue"].clip(lower=0)
df["date"] = pd.to_datetime(df["date"])
df["month"] = df["date"].dt.to_period("M")
return df
def load(df: pd.DataFrame, dest_path: str) -> None:
df.to_parquet(dest_path, index=False)
# Run pipeline
df = extract("raw/orders.csv")
df = transform(df)
load(df, "processed/orders.parquet")
Data engineering tools to know
| Tool |
Purpose |
Priority |
| Apache Spark / PySpark |
Distributed data processing |
High |
| Apache Airflow |
Workflow orchestration (DAGs) |
High |
| dbt |
SQL transformation layer |
High |
| Kafka |
Real-time data streaming |
Medium |
| Snowflake / BigQuery / Redshift |
Cloud data warehouses |
High |
| Delta Lake / Apache Iceberg |
ACID transactions on data lakes |
Medium |
| Prefect / Dagster |
Modern Airflow alternatives |
Medium |
File formats
| Format |
Best for |
| CSV |
Simple interchange, small data |
| Parquet |
Columnar, compressed, fast analytics |
| JSON / JSONL |
Semi-structured, API data |
| Avro |
Schema evolution, Kafka |
| ORC |
Hive/Spark analytics workloads |
Phase 8 — MLOps and deployment (Weeks 54–59)
A model that lives in a notebook isn't useful. Learn to ship and monitor models.
# Save and load a model with MLflow
import mlflow
import mlflow.sklearn
with mlflow.start_run():
mlflow.log_params({"n_estimators": 100, "max_depth": 10})
mlflow.log_metric("f1_score", 0.87)
mlflow.sklearn.log_model(pipe, "model")
# Serve a model with FastAPI
from fastapi import FastAPI
import joblib
import numpy as np
app = FastAPI()
model = joblib.load("model.pkl")
@app.post("/predict")
def predict(features: list[float]):
X = np.array(features).reshape(1, -1)
prediction = model.predict(X)[0]
probability = model.predict_proba(X)[0, 1]
return {"prediction": int(prediction), "probability": float(probability)}
MLOps stack overview
| Component |
Tools |
| Experiment tracking |
MLflow, Weights & Biases, Neptune |
| Model registry |
MLflow Model Registry, HuggingFace Hub |
| Feature store |
Feast, Hopsworks, Tecton |
| Model serving |
FastAPI, BentoML, Triton, SageMaker |
| Monitoring |
Evidently AI, WhyLabs, Grafana |
| Pipelines / orchestration |
Kubeflow, ZenML, Metaflow |
| CI/CD for ML |
GitHub Actions + DVC |
Model drift types
| Type |
Description |
Detection |
| Data drift |
Input distribution changes |
KS test, PSI |
| Concept drift |
Relationship between X and y changes |
Accuracy drop, ADWIN |
| Prediction drift |
Output distribution changes |
Monitor prediction histograms |
| Label drift |
Target distribution changes |
Monitor ground truth when available |
Phase 9 — Specialization (Weeks 60–67)
Pick one area and go deep. Generalists struggle; specialists get hired.
Common specializations
| Specialization |
Focus |
Key skills |
| NLP / LLMs |
Text, language models |
Transformers, RAG, fine-tuning, LangChain |
| Computer Vision |
Images, video |
CNNs, object detection (YOLO), segmentation |
| Time Series |
Forecasting, anomaly detection |
ARIMA, Prophet, LSTM, N-BEATS |
| Recommendation Systems |
Personalization |
Collaborative filtering, matrix factorization, two-tower models |
| Causal Inference / A/B Testing |
Experimentation |
DiD, propensity scoring, uplift modeling |
| Reinforcement Learning |
Sequential decisions |
PPO, DQN, multi-armed bandits |
| Tabular / XGBoost |
Competition-style tabular ML |
Feature engineering, stacking, LightGBM, CatBoost |
Full technology map
Math & Stats
├── Linear algebra (NumPy)
├── Calculus (concept only)
└── Statistics (scipy.stats, statsmodels)
Python ecosystem
├── NumPy → fast array ops
├── Pandas → data manipulation
├── Matplotlib + Seaborn → viz
├── Scikit-learn → classical ML
├── PyTorch → deep learning
└── Hugging Face → LLMs, NLP
Data Engineering
├── SQL (PostgreSQL, BigQuery, Snowflake)
├── Spark / PySpark
├── Airflow / Prefect
├── dbt
└── Parquet / Delta Lake
MLOps
├── MLflow / W&B → experiment tracking
├── FastAPI → model serving
├── Docker → containerization
├── GitHub Actions → CI/CD
└── Evidently → monitoring
Specialization (pick one)
├── NLP/LLMs → Transformers, RAG
├── CV → YOLO, diffusion models
├── Time Series → Prophet, N-BEATS
└── A/B Testing → causal inference
Realistic 18-month timeline
| Month |
Focus |
| 1–2 |
Math & statistics (StatQuest, Khan Academy) |
| 3–4 |
Python basics + NumPy + Pandas |
| 5–6 |
SQL, data cleaning, EDA |
| 7–8 |
Matplotlib, Seaborn, Plotly basics |
| 9–11 |
Machine learning (scikit-learn, Kaggle competitions) |
| 12–13 |
Deep learning (PyTorch, fast.ai) |
| 14 |
Data engineering (Spark, Airflow, dbt basics) |
| 15 |
MLOps (MLflow, FastAPI deployment, Docker) |
| 16 |
Specialization deep-dive |
| 17–18 |
Portfolio projects + job applications |
Portfolio project ideas
| Project |
Skills demonstrated |
| Churn prediction (Telco dataset) |
EDA, feature eng, classification, scikit-learn |
| House price prediction (Kaggle) |
Regression, gradient boosting, feature selection |
| Sentiment analysis API |
NLP, Transformers, FastAPI, Docker |
| Movie recommendation system |
Collaborative filtering, matrix factorization |
| Sales forecasting dashboard |
Time series, Prophet/LSTM, Streamlit |
| Customer segmentation |
Clustering, K-Means, visualization |
| End-to-end ML pipeline |
Airflow + MLflow + FastAPI + monitoring |
A strong portfolio has 3–4 projects, each with:
- Clean Jupyter notebook with clear explanations
- GitHub repo with README, requirements.txt, and reproducible instructions
- Business context ("This model reduced churn by X%")
- Deployed demo (Streamlit Cloud, HuggingFace Spaces, or a live API)
Data scientist vs related roles
| Role |
Focus |
Python |
ML |
SQL |
Stats |
Salary (US) |
| Data Analyst |
Reporting, dashboards |
Medium |
Low |
High |
Medium |
$70k–$110k |
| Data Scientist |
Modeling, prediction |
High |
High |
Medium |
High |
$100k–$160k |
| ML Engineer |
Production ML systems |
High |
High |
Low |
Medium |
$130k–$200k |
| Data Engineer |
Pipelines, warehouses |
High |
Low |
High |
Low |
$110k–$170k |
| Research Scientist |
Novel algorithms, papers |
High |
Expert |
Low |
Expert |
$150k–$300k |
| MLOps Engineer |
Model deployment, monitoring |
High |
Medium |
Low |
Low |
$130k–$190k |
Common mistakes
| Mistake |
Fix |
| Starting with deep learning before knowing statistics |
Learn stats first — they apply everywhere |
| Using accuracy on imbalanced datasets |
Use F1, AUC-ROC, or precision@recall |
| Not doing EDA before modeling |
Always explore data before fitting |
| Leaking future data into training |
Strict train/test split by time for time series |
| Overfitting to the validation set |
Use a separate held-out test set |
| Skipping cross-validation |
Use k-fold, not a single 80/20 split |
| Building models without understanding features |
Domain knowledge drives feature engineering |
| Deploying without monitoring |
Set up drift detection from day one |
Frequently asked questions
Do I need a degree in data science?
No. Many working data scientists have backgrounds in physics, engineering, economics, or computer science. What matters is a strong portfolio, SQL skills, and solid statistics knowledge. Bootcamps and self-study are viable paths — they just take discipline.
Python or R for data science in 2025?
Python. R is still used in academia and certain statistical niches, but Python dominates industry roles, has a larger ecosystem (PyTorch, scikit-learn, PySpark), and overlaps with software engineering. See our Python vs R comparison.
Do I need to know deep learning to get a data science job?
Not for most roles. The majority of production data science is classical ML (gradient boosting, logistic regression) applied to tabular data. Deep learning skills are required for NLP/CV specializations, but a junior DS role rarely requires them.
What Kaggle ranking do I need?
Don't chase rankings. Complete 3–4 Kaggle competitions to learn practical techniques, then move to real-world projects. Employers value a deployed project + a clear GitHub portfolio over a competition rank.
Should I learn TensorFlow or PyTorch?
PyTorch. It has overtaken TensorFlow in research and is growing in industry. The dynamic computation graph is more Pythonic and easier to debug. Most new papers ship PyTorch code.
How long does it take to land a first data science job?
With full-time effort: 14–20 months from zero. If you already code in Python and know some statistics, cut that to 8–12 months. The biggest bottleneck is usually portfolio projects and demonstrating business communication skills, not technical knowledge.