Data analysts turn raw numbers into decisions. Every company — from a two-person startup to a Fortune 500 firm — needs someone who can wrangle messy data, spot patterns, and communicate findings clearly. This roadmap shows you exactly what to learn, in what order, and realistic timelines to go from zero to a job-ready data analyst.
At a glance
| Phase | Topics | Time estimate |
|---|---|---|
| 1 | Foundations — spreadsheets, business math, thinking analytically | 2–3 weeks |
| 2 | SQL — queries, joins, aggregations, window functions | 4–6 weeks |
| 3 | Excel / Google Sheets — advanced formulas, pivot tables | 2–3 weeks |
| 4 | Python for data analysis — pandas, NumPy, data cleaning | 5–7 weeks |
| 5 | Data visualisation — matplotlib, seaborn, chart selection | 2–3 weeks |
| 6 | Business Intelligence tools — Tableau or Power BI | 3–4 weeks |
| 7 | Statistics and probability — hypothesis testing, A/B tests | 3–4 weeks |
| 8 | Data storytelling and communication | 1–2 weeks |
| 9 | Advanced topics — databases, cloud, dashboards | 3–4 weeks |
| 10 | Portfolio projects and job search | 4–8 weeks |
| Total to first job | ~8–12 months |
Phase 1 — Analytical foundations (Weeks 1–3)
Before writing a single SQL query, build the mental frame that separates good analysts from great ones.
What analysts actually do
| Task | Frequency | Example |
|---|---|---|
| Data extraction | Daily | Pull last-week's sales from the database |
| Data cleaning | Daily | Fix nulls, duplicates, inconsistent categories |
| Exploratory analysis | Weekly | Find why churn spiked in March |
| Dashboard maintenance | Weekly | Refresh KPI board for leadership |
| Ad-hoc investigation | Ongoing | "Why did DAU drop 20% yesterday?" |
| Presenting findings | Monthly | Stakeholder readout with recommendations |
Analytical thinking fundamentals
You don't need calculus. You need:
- Proportions — ratios, percentages, growth rates, market share
- Averages vs medians — understanding skew and outliers
- Correlation vs causation — the most common mistake in data work
- Base rates — "10% conversion" means nothing without context
Practice by reading news articles and critiquing the statistics they cite. Ask: What is the denominator? Is this cherry-picked? What's the trend?
Business metrics you'll use constantly
| Metric | Formula | When it matters |
|---|---|---|
| Conversion rate | conversions / visitors | Marketing, funnels |
| Churn rate | churned users / starting users | SaaS, subscriptions |
| Customer lifetime value (LTV) | avg revenue × avg customer lifespan | Growth strategy |
| Retention rate | users at end / users at start | Product health |
| MoM / YoY growth | (new − old) / old × 100 | Business performance |
| CAC | marketing spend / new customers | Efficiency |
| Net Promoter Score (NPS) | %promoters − %detractors | Customer satisfaction |
Phase 2 — SQL (Weeks 4–9)
SQL is the single most important skill for data analysts. Master it before anything else.
SQL fundamentals
-- Select specific columns with filtering
SELECT
user_id,
country,
created_at::date AS signup_date
FROM users
WHERE country IN ('US', 'GB', 'DE')
AND created_at >= '2025-01-01'
ORDER BY created_at DESC
LIMIT 100;
Aggregations and GROUP BY
-- Revenue by country and month
SELECT
country,
DATE_TRUNC('month', created_at) AS month,
COUNT(DISTINCT user_id) AS users,
SUM(revenue_usd) AS revenue,
ROUND(AVG(revenue_usd), 2) AS avg_revenue_per_user
FROM orders
WHERE created_at >= '2025-01-01'
GROUP BY 1, 2
ORDER BY month, revenue DESC;
JOINs explained
| Join type | Returns | When to use |
|---|---|---|
INNER JOIN |
Matching rows in both tables | Most common — link facts to dimensions |
LEFT JOIN |
All left rows + matching right rows | Find users without orders (nulls on right) |
RIGHT JOIN |
All right rows + matching left rows | Rare — swap tables and use LEFT instead |
FULL OUTER JOIN |
All rows from both tables | Reconciliation, data quality checks |
CROSS JOIN |
Every row × every row | Calendar generation, combinatorics |
-- Users with their total order value (LEFT JOIN keeps users with 0 orders)
SELECT
u.user_id,
u.email,
COALESCE(SUM(o.amount), 0) AS lifetime_value
FROM users u
LEFT JOIN orders o USING (user_id)
GROUP BY u.user_id, u.email;
Window functions — the analyst superpower
-- Rank users by revenue within each country
SELECT
user_id,
country,
revenue,
RANK() OVER (PARTITION BY country ORDER BY revenue DESC) AS country_rank,
ROW_NUMBER() OVER (ORDER BY revenue DESC) AS global_rank,
LAG(revenue) OVER (PARTITION BY country ORDER BY created_at) AS prev_month_rev,
SUM(revenue) OVER (PARTITION BY country) AS country_total,
revenue / SUM(revenue) OVER (PARTITION BY country) AS pct_of_country
FROM user_monthly_revenue;
Cohort retention query
-- Classic D1/D7/D30 retention cohort
WITH cohorts AS (
SELECT
DATE_TRUNC('week', first_login) AS cohort_week,
user_id
FROM users
),
activity AS (
SELECT DISTINCT
user_id,
DATE_TRUNC('week', event_date) AS active_week
FROM events
)
SELECT
c.cohort_week,
COUNT(DISTINCT c.user_id) AS cohort_size,
COUNT(DISTINCT CASE WHEN a.active_week = c.cohort_week + INTERVAL '1 week' THEN a.user_id END) AS week_1,
COUNT(DISTINCT CASE WHEN a.active_week = c.cohort_week + INTERVAL '4 weeks' THEN a.user_id END) AS week_4,
COUNT(DISTINCT CASE WHEN a.active_week = c.cohort_week + INTERVAL '12 weeks' THEN a.user_id END) AS week_12
FROM cohorts c
LEFT JOIN activity a USING (user_id)
GROUP BY 1
ORDER BY 1;
SQL learning path
| Week | Topics |
|---|---|
| 1 | SELECT, WHERE, ORDER BY, LIMIT, data types |
| 2 | GROUP BY, HAVING, aggregate functions (SUM/COUNT/AVG/MIN/MAX) |
| 3 | JOINs — INNER, LEFT, practice with multiple tables |
| 4 | Subqueries, CTEs (WITH), UNION / UNION ALL |
| 5 | Window functions — ROW_NUMBER, RANK, LAG/LEAD, SUM OVER |
| 6 | Date functions, string functions, CASE WHEN, NULL handling |
Practice platforms: Mode Analytics, DataLemur, StrataScratch, LeetCode (SQL section), SQLZoo
Phase 3 — Excel and Google Sheets (Weeks 10–12)
Executives live in spreadsheets. Even in a Python-heavy shop, you'll share Excel files.
Essential functions every analyst must know
| Function | Purpose | Example |
|---|---|---|
VLOOKUP / XLOOKUP |
Lookup value in another table | Join price list to orders |
SUMIFS / COUNTIFS |
Conditional aggregation | Revenue for "US" and "2025" |
INDEX + MATCH |
Flexible two-way lookup | Better than VLOOKUP for large sheets |
IF / IFS |
Conditional logic | Classify customers as high/low value |
TEXT |
Format dates/numbers as text | Convert date to "Jan 2025" |
IFERROR |
Handle errors gracefully | Return 0 instead of #N/A |
ARRAYFORMULA |
Apply formula to whole column | Google Sheets power feature |
QUERY |
SQL-like queries in Sheets | Filter and aggregate without pivot tables |
Pivot tables
Pivot tables are the fastest way to go from raw data to insight:
- Select your data range
- Insert → Pivot Table
- Drag fields into Rows, Columns, Values, Filters
- Use calculated fields for custom metrics
- Add slicers to make it interactive
Golden rule: Your pivot table is only as good as your source data. Clean first, pivot second.
Phase 4 — Python for data analysis (Weeks 13–19)
Python lets you automate cleaning tasks that would take days in Excel, handle datasets too large for spreadsheets, and connect directly to databases and APIs.
Setup
python -m venv .venv && source .venv/bin/activate # macOS/Linux
# or .venv\Scripts\activate on Windows
pip install pandas numpy matplotlib seaborn openpyxl jupyter
jupyter lab # open interactive notebook
pandas fundamentals
import pandas as pd
import numpy as np
# Load data
df = pd.read_csv("orders.csv", parse_dates=["created_at"])
# Inspect
print(df.shape) # (rows, columns)
print(df.dtypes) # column types
print(df.head()) # first 5 rows
print(df.describe()) # summary statistics
print(df.isnull().sum()) # missing values per column
Data cleaning checklist
# 1. Drop pure duplicates
df = df.drop_duplicates()
# 2. Handle missing values
df["country"] = df["country"].fillna("Unknown")
df["revenue"] = df["revenue"].fillna(0)
df = df.dropna(subset=["user_id"]) # drop rows where user_id is null
# 3. Fix data types
df["created_at"] = pd.to_datetime(df["created_at"])
df["revenue"] = pd.to_numeric(df["revenue"], errors="coerce")
# 4. Normalise categories
df["status"] = df["status"].str.lower().str.strip()
df["country"] = df["country"].replace({"USA": "US", "United States": "US"})
# 5. Remove outliers (IQR method)
Q1, Q3 = df["revenue"].quantile([0.25, 0.75])
IQR = Q3 - Q1
df = df[df["revenue"].between(Q1 - 1.5 * IQR, Q3 + 1.5 * IQR)]
Aggregation and groupby
# Revenue by country and month
monthly = (
df
.assign(month=df["created_at"].dt.to_period("M"))
.groupby(["country", "month"])
.agg(
users = ("user_id", "nunique"),
revenue = ("revenue", "sum"),
orders = ("order_id", "count"),
)
.reset_index()
)
# Pivot to wide format
pivot = monthly.pivot_table(
index="country", columns="month", values="revenue", fill_value=0
)
Merging DataFrames
# LEFT JOIN: all orders + user info
result = orders.merge(users, on="user_id", how="left")
# Multiple keys
result = events.merge(
sessions, on=["session_id", "user_id"], how="inner"
)
Phase 5 — Data visualisation (Weeks 20–22)
The goal of a chart is to answer a question faster than a table would.
Chart selection guide
| Question | Chart type | Why |
|---|---|---|
| How does X compare across categories? | Bar chart | Easy ranking |
| How does X change over time? | Line chart | Trends visible |
| How are two variables related? | Scatter plot | Correlation |
| What's the distribution of X? | Histogram / box plot | Spread, outliers |
| What share of the whole is each part? | Pie / donut (≤5 slices) | Part-to-whole |
| How does X vary by two categories? | Heatmap | Pattern across matrix |
| Where are things located? | Map / choropleth | Geographic patterns |
Python visualisation
import matplotlib.pyplot as plt
import seaborn as sns
# Line chart: revenue over time
fig, ax = plt.subplots(figsize=(10, 4))
ax.plot(monthly["month"].astype(str), monthly["revenue"], marker="o")
ax.set_title("Monthly Revenue 2025", fontsize=14)
ax.set_xlabel("Month")
ax.set_ylabel("Revenue (USD)")
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig("revenue.png", dpi=150)
# Bar chart: top 10 countries
top10 = df.groupby("country")["revenue"].sum().nlargest(10)
sns.barplot(x=top10.values, y=top10.index, palette="Blues_r")
plt.title("Top 10 Countries by Revenue")
plt.tight_layout()
# Distribution of order values
sns.histplot(df["revenue"], bins=50, kde=True)
plt.axvline(df["revenue"].median(), color="red", linestyle="--", label="Median")
plt.legend()
Visualisation best practices
| Do | Don't |
|---|---|
| Start y-axis at zero for bar charts | Truncate y-axis to exaggerate differences |
| Label axes and units | Use chartjunk (3D, gradients, unnecessary gridlines) |
| Use colour purposefully (max 4–5) | Use rainbow palettes on continuous data |
| Include a clear title with the insight | Write generic titles like "Chart 1" |
| Show sample size (n=X) | Present 3 data points as a "trend" |
| Use direct labels when possible | Force users to cross-reference a legend |
Phase 6 — Business Intelligence tools (Weeks 23–26)
At most companies, you'll build dashboards in a BI tool — not Python scripts. Learn either Tableau or Power BI (pick one).
Tableau vs Power BI
| Dimension | Tableau | Power BI |
|---|---|---|
| Best for | Exploratory analysis, beautiful viz | Microsoft stack, scheduled reports |
| Learning curve | Easier drag-and-drop | Steeper (DAX formula language) |
| Price | From $70/user/month | Free desktop; $10/user/month for sharing |
| Data sources | Connects to everything | Native Microsoft (Excel, Azure, SQL Server) |
| Sharing | Tableau Server/Cloud | Power BI Service (requires Pro licence) |
| Calculations | Calculated fields + LOD expressions | DAX measures |
| Job market | Strong in enterprise, tech, consulting | Strong in finance, corporate IT |
Recommendation: If your target company uses Azure / Microsoft 365 → Power BI. Otherwise → Tableau (slightly more transferable skill set).
Core BI concepts to master
- Dimensions vs measures — qualitative (country, status) vs quantitative (revenue, count)
- Aggregation — SUM, AVG, COUNT at the right grain
- Filters — dimension filters, date filters, top N
- Calculated fields — extend your data with new metrics (e.g. profit margin)
- Parameters — give users control (switch between metrics, set date ranges)
- Dashboard actions — click a bar to filter other charts (filter actions)
- Performance — use extracts, aggregate before connecting, limit live queries
Phase 7 — Statistics and A/B testing (Weeks 27–30)
Knowing that something changed is useful. Knowing whether it's real or random is essential.
Descriptive statistics
| Statistic | Measures | When to use |
|---|---|---|
| Mean | Central tendency | Symmetric distributions |
| Median | Central tendency | Skewed distributions, income |
| Mode | Most frequent value | Categorical data |
| Std deviation | Spread | Normal-ish data |
| IQR | Spread (robust) | Outlier-heavy data |
| Percentiles | Relative position | P50/P90/P99 latency, LTV |
Distributions that matter
| Distribution | Where you'll see it | Key fact |
|---|---|---|
| Normal | Test scores, measurement errors | ~68% within 1σ, 95% within 2σ |
| Log-normal | Revenue, user LTV, page views | Take log first to normalise |
| Binomial | Conversion rates, click-through | Probability of k successes in n trials |
| Poisson | Events per time unit (orders/hour) | Mean = variance |
| Exponential | Time between events | Memoryless property |
A/B testing step by step
Step 1: Define your hypothesis
H₀ (null): New checkout flow has no effect on conversion rate
H₁ (alternative): New checkout flow increases conversion rate
Step 2: Choose your metric
Primary: Conversion rate (orders / sessions)
Guard: Average order value (should not decrease)
Step 3: Calculate sample size
Effect size = minimum detectable effect (e.g. +2% relative lift)
α = 0.05 (false positive rate)
Power = 0.80 (80% chance of detecting a true effect)
→ Use a sample size calculator or:
from scipy import stats
import math
def sample_size(baseline, mde, alpha=0.05, power=0.80):
"""Estimate required sample size per variant (two-proportion z-test)."""
p1 = baseline
p2 = baseline * (1 + mde)
z_alpha = stats.norm.ppf(1 - alpha / 2)
z_beta = stats.norm.ppf(power)
p_bar = (p1 + p2) / 2
n = (z_alpha + z_beta)**2 * (p1*(1-p1) + p2*(1-p2)) / (p1 - p2)**2
return math.ceil(n)
n = sample_size(baseline=0.03, mde=0.10) # 3% baseline, 10% relative lift
print(f"Require {n:,} users per variant") # → ~14,741
Step 4: Run the experiment
- Randomise cleanly (one unit = one user, not one session)
- Don't peek early — set a fixed duration upfront
- Check for SRM (Sample Ratio Mismatch) on day 1
Step 5: Analyse results
from scipy.stats import chi2_contingency
control_visitors, control_conversions = 14741, 441
treat_visitors, treat_conversions = 14741, 501
table = [[control_conversions, control_visitors - control_conversions],
[treat_conversions, treat_visitors - treat_conversions]]
chi2, p_value, dof, expected = chi2_contingency(table)
print(f"p-value: {p_value:.4f}")
if p_value < 0.05:
lift = (treat_conversions/treat_visitors) / (control_conversions/control_visitors) - 1
print(f"Significant! Lift = {lift:.1%}")
Step 6: Make a decision
- p < 0.05 + practical significance → ship the change
- p ≥ 0.05 → do not ship (null not rejected)
- Unexpected metric movements → investigate before deciding
Common A/B testing mistakes
| Mistake | Why it's wrong | Fix |
|---|---|---|
| Peeking and stopping early | Inflates false positive rate | Pre-register end date |
| Testing too many variants | Multiple comparison problem | Bonferroni correction or sequential testing |
| Using sessions instead of users | Same user in both groups | Randomise at user level |
| Ignoring novelty effect | Users try new things out of curiosity | Run for ≥2 full weeks |
| Not checking SRM | Randomisation bug invalidates results | Validate traffic split before analysis |
| Confusing statistical and practical significance | p=0.001 on a 0.01% lift | Set MDE ≥ business-meaningful threshold |
Phase 8 — Data storytelling (Weeks 31–32)
The best analysis is worthless if it's not communicated clearly. This is the skill that separates analysts who get promoted from those who don't.
The Pyramid Principle
Structure every analysis top-down:
- Recommendation / Insight first — "We should increase spend in Germany."
- Supporting argument — "Germany has the highest LTV/CAC ratio (4.2x)."
- Data evidence — chart showing LTV by country over last 12 months.
Don't walk your audience through your analysis journey. Tell them what they need to know, then show the evidence.
Dashboard design principles
| Principle | In practice |
|---|---|
| One screen tells one story | Don't cram 20 charts on a single dashboard |
| Most important KPI top-left | That's where eyes land first |
| Context every number | Show trend vs. last period, vs. target |
| Red/green only for good/bad | Don't use colour decoratively |
| Consistent scales | Changing scales across charts is misleading |
| Mobile check | ~30% of executives view on phone |
Slide structure for stakeholder readouts
Slide 1: Situation + Key Finding (1 sentence each)
Slide 2: Evidence (1 chart, annotated with insight)
Slide 3: So what? Implication for the business
Slide 4: Recommendation + next steps (owner + date)
Appendix: Methodology, assumptions, raw data
Phase 9 — Advanced topics (Weeks 33–36)
Once you're comfortable with the core stack, these skills will make you a stronger candidate.
Advanced SQL
-- Funnel analysis: track users through signup → activation → purchase
WITH funnel AS (
SELECT user_id,
MIN(CASE WHEN event = 'signup' THEN ts END) AS signed_up,
MIN(CASE WHEN event = 'activated' THEN ts END) AS activated,
MIN(CASE WHEN event = 'purchased' THEN ts END) AS purchased
FROM events
GROUP BY user_id
)
SELECT
COUNT(*) AS signups,
COUNT(activated) AS activations,
COUNT(purchased) AS purchases,
ROUND(100.0 * COUNT(activated) / COUNT(*), 1) AS activation_rate,
ROUND(100.0 * COUNT(purchased) / COUNT(*), 1) AS purchase_rate
FROM funnel;
Python automation
import pandas as pd
import smtplib
from email.mime.text import MIMEText
# Automated weekly report
def weekly_report():
df = pd.read_sql("SELECT ...", engine)
summary = df.groupby("region")["revenue"].sum().reset_index()
html_table = summary.to_html(index=False)
msg = MIMEText(f"<h2>Weekly Revenue</h2>{html_table}", "html")
msg["Subject"] = f"Weekly Revenue Report"
msg["From"] = "analytics@company.com"
msg["To"] = "leadership@company.com"
with smtplib.SMTP("smtp.gmail.com", 587) as s:
s.starttls()
s.login("user", "password")
s.send_message(msg)
Cloud basics every analyst should know
| Skill | Tool | Why |
|---|---|---|
| Cloud data warehouse | BigQuery, Redshift, Snowflake | Where your company's data lives |
| Query large tables | Partitioning, clustering | Avoid scanning 10TB tables |
| Scheduled queries | dbt, Airflow, cron | Automate your pipelines |
| Version control | Git + GitHub | Track query changes, collaborate |
| Notebooks | Jupyter, Google Colab | Share reproducible analysis |
dbt (data build tool) basics
-- models/revenue_by_country.sql
{{ config(materialized='table') }}
SELECT
country,
DATE_TRUNC('month', created_at) AS month,
SUM(revenue_usd) AS revenue,
COUNT(DISTINCT user_id) AS users
FROM {{ ref('stg_orders') }}
WHERE created_at >= '2025-01-01'
GROUP BY 1, 2
dbt transforms SQL into a full analytics engineering workflow: version control, testing, documentation, and lineage — all built in.
Phase 10 — Portfolio and job search (Weeks 37–44)
Hiring managers want to see that you can answer a real business question with data — not that you memorised SQL syntax.
Portfolio project ideas
| Project | Skills shown | Complexity |
|---|---|---|
| E-commerce sales dashboard (Tableau/Power BI) | BI tools, storytelling | ★★ |
| Customer churn prediction analysis (Python) | pandas, visualisation, statistics | ★★★ |
| A/B test analysis with real or simulated data | Hypothesis testing, Python | ★★★ |
| SQL analytics on public dataset (NYC taxi, Airbnb, COVID) | SQL, BigQuery | ★★ |
| YouTube channel growth analysis | Web scraping / API, pandas | ★★ |
| Personal finance tracker in Google Sheets | Excel/Sheets, clean design | ★ |
Make it real: Use public datasets from Kaggle, Google BigQuery public datasets, data.gov, or Reddit r/datasets.
Publish it: GitHub for code, Tableau Public for dashboards, Medium/Substack for write-ups.
The job search
- Target roles: Data Analyst, Business Analyst, Marketing Analyst, Product Analyst, Operations Analyst
- ATS keywords: SQL, Python, Tableau, Power BI, Excel, A/B testing, dashboards, ETL, pandas, statistics
- Companies hiring: All of them — retail, finance, health, tech, media, consulting
- Interview stages: SQL take-home → Python exercise → case study presentation → behavioural
What interviewers test
| Round | What they're testing | How to prepare |
|---|---|---|
| SQL screening | Basic to intermediate SQL | DataLemur, StrataScratch (30 problems) |
| Python / pandas | Data cleaning, GroupBy, merge | Kaggle competitions, take-home |
| Case study | Business judgement, structured thinking | Framework: Clarify → Hypothesis → Analysis → Recommendation |
| Dashboard review | Portfolio walk-through | Explain why you made each design decision |
| Behavioural | Communication, stakeholder management | STAR method stories |
Full technology map
DATA ANALYST SKILL MAP 2025
═══════════════════════════════════════════════════════
FOUNDATIONS
├─ Spreadsheets ── Excel, Google Sheets
└─ Business metrics ── KPIs, conversion, retention, LTV
DATABASES & SQL
├─ SQL ── SELECT, JOINs, GROUP BY, CTEs, window functions
├─ PostgreSQL / MySQL ── most common in job listings
└─ Cloud warehouses ── BigQuery, Snowflake, Redshift (read-only queries)
PYTHON
├─ pandas ── cleaning, filtering, aggregating, merging
├─ NumPy ── arrays, maths
├─ matplotlib / seaborn ── static charts
└─ Jupyter / Google Colab ── interactive notebooks
VISUALISATION & BI
├─ Tableau ── drag-and-drop dashboards, LOD expressions
├─ Power BI ── DAX, M, Microsoft stack
└─ Looker / Metabase ── SQL-first BI (company-specific)
STATISTICS
├─ Descriptive stats ── mean, median, std, percentiles
├─ Probability ── distributions, conditional probability
└─ Inferential stats ── hypothesis testing, A/B tests, confidence intervals
DATA ENGINEERING (NICE TO HAVE)
├─ dbt ── transform SQL in version-controlled pipelines
├─ Airflow ── schedule and orchestrate pipelines
└─ Git ── version control for queries and notebooks
COMMUNICATION
├─ Storytelling ── Pyramid Principle, insight-first slides
├─ Dashboard design ── clean, scannable, actionable
└─ Stakeholder management ── translating business ↔ data
Realistic 12-month timeline
| Month | Milestone | Activities |
|---|---|---|
| 1 | SQL basics solid | Complete SQLZoo + 20 DataLemur problems |
| 2 | Intermediate SQL | Window functions, CTEs, real queries on public data |
| 3 | Excel / Sheets | VLOOKUP, SUMIFS, pivot tables, 3 mini-projects |
| 4–5 | Python foundations | pandas, cleaning, EDA on a Kaggle dataset |
| 6 | Visualisation | matplotlib, seaborn + first Tableau dashboard |
| 7 | BI tool | Tableau or Power BI certification project |
| 8 | Statistics | Descriptive stats, hypothesis testing, A/B test simulation |
| 9 | Advanced SQL | Cohort analysis, funnel analysis, window functions |
| 10 | Portfolio project 1 | End-to-end analysis with SQL + Python + visualisation |
| 11 | Portfolio project 2 | Dashboard or A/B testing case study |
| 12 | Job applications | Target 5 applications/week, refine based on feedback |
Data analyst roles and salary (2025)
| Role | Focus | US Median | UK Median | Required stack |
|---|---|---|---|---|
| Junior Data Analyst | Dashboards, ad-hoc queries | $65k | £32k | SQL, Excel, BI tool |
| Data Analyst | Full analysis cycle | $85k | £45k | SQL, Python, BI tool |
| Senior Data Analyst | Strategy, mentoring | $110k | £60k | All above + statistics |
| Product Analyst | Feature analysis, A/B tests | $95k | £55k | SQL, Python, product thinking |
| Marketing Analyst | Campaign performance, attribution | $80k | £42k | SQL, Excel, Google Analytics |
| Business Analyst | Requirements, process improvement | $90k | £48k | SQL, Excel, stakeholder skills |
| Data Scientist | Modelling, ML | $125k | £70k | All above + ML (scikit-learn) |
| Analytics Engineer | Data pipelines | $120k | £65k | SQL, dbt, Python, warehouse |
Common mistakes
| Mistake | Why it hurts | Better approach |
|---|---|---|
| Learning Python before SQL | Python without SQL is slow for most analyst tasks | SQL first, Python second |
| Stopping after tutorials | Tutorial knowledge doesn't transfer to real problems | Build 2–3 real projects from day one |
| Visualisation before storytelling | Pretty charts with no insight | Ask "what decision does this inform?" before opening Tableau |
| Ignoring business context | Technically correct but irrelevant analysis | Always align analysis to a business question |
| Skipping statistics | Will be caught in interviews | Learn hypothesis testing — it's tested heavily |
| Over-engineering with ML | Adds complexity without business value | Linear regression or a pivot table is often enough |
| Not version-controlling queries | Lose work, can't reproduce results | Use GitHub for all SQL and Python files |
| Applying broadly, personalising nothing | Low response rate | Tailor each application to the company's data stack |
Data analyst vs related roles
| Dimension | Data Analyst | Business Analyst | Data Scientist | Analytics Engineer | Data Engineer |
|---|---|---|---|---|---|
| Primary tool | SQL + BI | Excel + Jira | Python + ML | dbt + SQL | Spark + Python |
| Main output | Dashboards, ad-hoc reports | Requirements, process docs | Models, predictions | Data models, pipelines | Pipelines, warehouses |
| Stats depth | Descriptive + A/B tests | Minimal | Inferential + ML | Minimal | Minimal |
| Coding depth | Moderate (pandas) | Low (VBA/formulas) | High (sklearn, TF) | High (SQL + Python) | High (PySpark) |
| Business proximity | High | Very high | Medium | Low | Low |
| Avg US salary | $85k | $90k | $125k | $120k | $115k |
Frequently asked questions
Do I need a degree to become a data analyst? No. A growing number of companies — including many tech firms — have removed degree requirements. What matters: a portfolio of real projects, demonstrable SQL and Python skills, and ability to communicate findings clearly. A relevant bootcamp or self-taught path with a strong portfolio beats a generic business degree.
How long does it realistically take to get hired? For someone starting from zero: 8–12 months of dedicated learning (15–20 hours/week) plus 1–3 months of job searching. If you already have domain expertise (finance, marketing, healthcare), the timeline shortens because you can target analysts in your field who value your business context.
Should I learn Tableau or Power BI? Check job listings in your target city/industry. Finance and corporate IT → Power BI dominates. Tech, media, consulting → Tableau is more common. Learning either to an intermediate level first, then picking up the other is straightforward — the concepts transfer.
Is Python mandatory, or can I get a job with just SQL and Excel? You can get a junior analyst role with SQL + Excel + a BI tool. Python becomes important for senior roles, large datasets, automation, and companies where the data team expects scripted analysis. It's worth learning — start after you're solid on SQL.
What's the fastest path from analyst to data scientist? Build up statistics knowledge (inferential stats, regression, classification), learn scikit-learn, and take on ML projects at work or as side projects. The fastest path is usually an internal move — become the most valuable analyst on your team, then ask to own prediction projects.
Which public datasets should I use for portfolio projects?
- Kaggle: E-commerce, healthcare, finance competition datasets
- Google BigQuery public datasets: NYC taxi, Wikipedia, GitHub, Stack Overflow
- data.gov / data.europa.eu: Government spending, healthcare, transportation
- Reddit r/datasets: Curated real-world datasets
- Our World in Data: Long-run macro trends (health, energy, economics)