๐Ÿ Python for Data Analysis
๐Ÿ‘‹ WELCOME

Stop rebuilding the same report by hand.

Every module below runs on the same Northside Bike Works repair-jobs dataset โ€” the same one from the Data Analyst course, if you've taken it. Work through them in order: load and inspect the data, clean it, group and summarise it, understand it statistically, chart it, then automate the whole routine.

Your 3-month path

Month 1

Read and trust the data

pandas foundations and cleaning โ€” the two skills every later step depends on.

Month 2

Summarise and measure

groupby, aggregation, and enough statistics to know whether a number is meaningful.

Month 3

Show it, then automate it

Charts worth sharing, then a script that runs the whole routine on its own.

Month 1 ยท Module 1
๐Ÿ

Pandas Foundations

Reading data into Python and actually looking at it first.

Why this matters: every mistake in a later step traces back to skipping this one โ€” knowing what your data actually looks like before you do anything to it.

1 Series vs. DataFrame

A Series is one labeled column of data. A DataFrame is a full table โ€” many Series sharing the same row index. jobs["Price"] hands you back a Series; jobs itself is the DataFrame.

2 Reading data in

import pandas as pd

jobs = pd.read_csv("jobs.csv")

One line replaces "open the file, find the delimiter, guess the header row" โ€” pandas handles all of it and hands you a DataFrame.

3 First look: head(), info(), dtypes

jobs.head()    # first 5 rows โ€” a quick sanity check
jobs.info()    # row count, columns, non-null counts, dtypes
jobs.dtypes    # just the column types

Three commands, thirty seconds, and you already know how many rows you have, which columns might have missing values, and whether anything got loaded as the wrong type.

Live dashboard โ€” inspect the Jobs DataFrame

In [1]: jobs.head()


        

In [2]: jobs.info()


      

Exercises

  • Load the Jobs export into pandas with pd.read_csv().
  • Run jobs.head() and jobs.tail() and compare.
  • Run jobs.info() and identify every column's dtype.
  • Check jobs.shape โ€” how many rows and columns is that?
  • List one thing you'd want to fix before analysing this data further.
๐Ÿ“ฆ Capstone โ€” Data Profile Notes

A short written profile of the Jobs dataset: row/column count, each column's dtype, and a one-line note on anything that looks off before you clean it.

Recap quiz

Month 1 ยท Module 2
๐Ÿงน

Data Cleaning & Wrangling

Fixing missing values, types, and messy text before you trust a single number.

Why this matters: a groupby on an uncleaned text column silently splits one real category into three. Clean first, analyse second.

1 Finding and handling missing values

jobs["JobType"].isna()          # True/False mask of missing cells
jobs.dropna(subset=["JobType"]) # remove rows with a missing JobType
jobs.fillna({"Notes": "None"})  # or fill missing values instead

isna() never changes your data โ€” it just tells you where the gaps are, so you can decide: drop the row, or fill it with something sensible.

2 Fixing types

jobs["Price"] = jobs["Price"].str.replace("$", "").astype(float)

A stray "$" in a CSV export turns a numeric column into text. Strip it, then astype() converts it back into something you can actually do math on.

3 Cleaning text columns

jobs["JobType"] = jobs["JobType"].str.strip().str.title()
jobs = jobs[jobs["JobType"] != ""]

.str.strip() removes stray whitespace, .str.title() normalises capitalisation, and a boolean filter drops blank rows โ€” the pandas equivalent of Power Query's Applied Steps.

Live dashboard โ€” clean this export
RAW SOURCE FILE
JobTypeCostPrice
" flat repair ""$8""$25"
"FULL TUNE-UP""35""90"
"Puncture Repair""5.0""20"
"""10""30"
"Brake Adjustment""$10""$30"
โ†’
AFTER PANDAS CLEANING
JobTypeCostPrice
Flat Repair825
Full Tune-Up3590
Puncture Repair520
Brake Adjustment1030
  • โœ“ jobs["JobType"].str.strip()
  • โœ“ jobs["JobType"].str.title()
  • โœ“ jobs[["Cost","Price"]].str.replace("$","").astype(float)
  • โœ“ jobs.dropna(subset=["JobType"])

Exercises

  • Check every column for missing values with .isna().sum().
  • Strip and title-case the JobType column.
  • Convert Cost and Price to float, stripping any "$".
  • Drop rows with a blank JobType and note how many were removed.
  • Re-run jobs.info() and confirm the dtypes are now correct.
๐Ÿ“ฆ Capstone โ€” Reusable Cleaning Function

A function clean_jobs(df) that takes a raw DataFrame and returns a cleaned one โ€” every fix from this module, in one callable place.

Recap quiz

Month 2 ยท Module 3
๐Ÿงฎ

GroupBy & Aggregation

pandas' answer to the Excel PivotTable and the SQL GROUP BY.

Why this matters: almost every real analysis question is "totals or averages, broken down by something" โ€” groupby is how you answer that in one line.

1 The basic pattern

jobs.groupby("JobType")["Price"].sum()

Split the table into buckets by JobType, then sum Price within each bucket. Swap .sum() for .mean(), .count(), or .median() for a different summary of the same groups.

2 Multiple aggregations at once

jobs.groupby("JobType").agg(
    TotalRevenue=("Price", "sum"),
    AvgMargin=("Margin", "mean"),
    JobCount=("JobID", "count"),
)

.agg() with named arguments computes several summaries in one pass and hands back clearly labeled columns โ€” the exact shape of a report table.

3 Combining tables with merge()

jobs_with_city = pd.merge(jobs, customers, on="CustomerID")
jobs_with_city.groupby("City")["Price"].sum()

merge() is pandas' join โ€” line up rows from two tables on a shared key, same idea as a SQL JOIN or a Power BI relationship, so you can group Jobs by a Customer attribute like City.

Live dashboard โ€” GroupBy Playground

        

      

Exercises

  • Group Jobs by JobType and sum Price.
  • Group Jobs by Status and count rows in each group.
  • Merge Jobs with Customers and group the result by City.
  • Write one .agg() call that returns TotalRevenue, AvgMargin, and JobCount together.
๐Ÿ“ฆ Capstone โ€” Summary Table

One .agg() call producing a report-ready summary table: revenue, average margin, and job count, grouped by JobType and sorted by revenue descending.

Recap quiz

Month 2 ยท Module 4
๐Ÿ“

NumPy & Statistics

Knowing whether a number is meaningful, not just calculating it.

Why this matters: "average job value is $65" means very little without also knowing how spread out the actual jobs are around that average.

1 Vectorized operations

import numpy as np

prices = jobs["Price"].to_numpy()
prices_with_tax = prices * 1.08   # applied to every element at once

NumPy applies math to a whole array in one step instead of a manual loop โ€” the engine pandas itself is built on, and dramatically faster on large data.

2 describe() โ€” the five-second summary

jobs["Price"].describe()

One call returns count, mean, standard deviation, min, the quartiles, and max โ€” the fastest way to understand a column's spread before you chart it.

3 Correlation

jobs["Price"].corr(jobs["Cost"])

A single number from -1 to 1 summarising how strongly two numeric columns move together. Useful for spotting relationships โ€” but correlation never proves one causes the other.

Live dashboard โ€” describe() by column
โ€”
mean
โ€”
50% (median)
โ€”
std
โ€”
min
โ€”
max

        
โ€”
Price.corr(Cost) โ€” fixed, doesn't change with the chips above

Exercises

  • Run .describe() on Price, Cost, and Margin.
  • Compute the standard deviation of Margin using NumPy directly.
  • Compute the correlation between Price and Cost and interpret it in one sentence.
  • Identify any job whose Price sits more than 2 standard deviations from the mean.
๐Ÿ“ฆ Capstone โ€” Stats Summary

A one-page stats summary of Price, Cost, and Margin โ€” mean, median, std, and one sentence interpreting the Price/Cost correlation for a non-technical reader.

Recap quiz

Month 3 ยท Module 5
๐Ÿ“Š

Data Visualization

matplotlib and seaborn โ€” turning a DataFrame into something someone else can read.

Why this matters: the right chart for the wrong question is still the wrong chart. Choosing well matters more than making it pretty.

1 Choosing the right chart

Comparing separate categories โ†’ bar chart. A trend over time โ†’ line chart. The relationship between two numeric columns โ†’ scatter plot. Matching the chart to the question is the actual skill โ€” matplotlib syntax is just the mechanics.

2 matplotlib basics

import matplotlib.pyplot as plt

plt.bar(jobs_by_type.index, jobs_by_type["Price"])
plt.title("Revenue by Job Type")
plt.xlabel("Job Type"); plt.ylabel("Revenue")
plt.show()

Build the chart, label the axes, give it a title, then show it. Skipping the labels is how a perfectly good chart becomes unreadable to anyone but you.

3 seaborn: matplotlib with better defaults

import seaborn as sns

sns.scatterplot(data=jobs, x="Cost", y="Price", hue="Status")

seaborn is built directly on top of matplotlib โ€” same engine, nicer default styling, and higher-level statistical chart types like this one, which colours points by an extra category for free.

Live dashboard โ€” same data, three chart types

        

Exercises

  • Build a bar chart of revenue by JobType, with axis labels and a title.
  • Build a line chart of revenue by month.
  • Build a scatter plot of Cost vs. Price and describe the relationship in one sentence.
  • Recreate one of the three using seaborn instead of plain matplotlib.
๐Ÿ“ฆ Capstone โ€” Chart Trio

Three finished, labeled charts โ€” one bar, one line, one scatter โ€” each choosing the right chart type for its question, ready to paste into a report.

Recap quiz

Month 3 ยท Module 6
โš™๏ธ

Automation & Real-World Workflows

Write the routine once, run it every month for free.

Why this matters: everything from Modules 1-5 is worth automating the moment you have to repeat it โ€” that's the entire case for learning Python over rebuilding a spreadsheet by hand.

1 Packaging the routine into a function

def summarise_jobs(csv_path):
    jobs = pd.read_csv(csv_path)
    jobs = clean_jobs(jobs)
    jobs["Margin"] = jobs["Price"] - jobs["Cost"]
    return jobs.groupby("JobType").agg(
        TotalRevenue=("Price", "sum"),
        AvgMargin=("Margin", "mean"),
        JobCount=("JobID", "count"),
    ).sort_values("TotalRevenue", ascending=False)

Every step from Modules 1-3, in one callable function. Run it on any month's export and get the same trustworthy summary, instantly.

2 Exporting the result

summary = summarise_jobs("march.csv")
summary.to_excel("march_report.xlsx")

.to_excel() writes the DataFrame straight to a real file โ€” the step that turns a script's output into something you can actually email to someone.

3 Running it as a script

if __name__ == "__main__":
    summarise_jobs("jobs.csv").to_excel("report.xlsx")
    print("Report generated.")

This guard keeps reusable functions reusable โ€” the file can be imported elsewhere without re-running itself, or run directly to generate a report on demand (or on a schedule, via cron or Task Scheduler).

Live dashboard โ€” build the automated pipeline
1
Define clean_and_summarise() as a reusable function
2
Run it against this month's export
3
Export the result to report.xlsx

Exercises

  • Combine your Module 2 cleaning function and Module 3 groupby into one summarise_jobs() function.
  • Export its result to an .xlsx file.
  • Add the if __name__ == "__main__": guard so the file can be safely imported elsewhere.
  • Write one sentence on how you'd schedule this to run automatically every month.
๐Ÿ“ฆ Capstone โ€” End-to-End Script

A single Python file that reads a raw export, cleans it, summarises it, and writes a finished .xlsx report โ€” runnable with one command.

Recap quiz

Final Capstone
๐Ÿ

Ship one full Python analysis script

Every module, tied into one real deliverable.

Take a dataset โ€” the Northside Bike Works set you've used throughout, or your own โ€” and carry it through all six stages, end to end, in a single script:

StageWhat "done" looks like
1. Pandas FoundationsData loaded with pd.read_csv(), inspected with head()/info()
2. Data CleaningA clean_jobs(df) function fixing types, text, and missing values
3. GroupBy & AggregationA .agg() summary table: revenue, avg margin, job count by JobType
4. NumPy & Statisticsdescribe() output plus one interpreted correlation
5. Data VisualizationAt least one bar, one line, and one scatter chart, all labeled
6. AutomationOne function that runs the whole pipeline and exports report.xlsx
๐ŸŽ“ You're done when...
  • All six stages are complete for the same dataset, in one script.
  • You can explain, out loud, one design decision you made at each stage and why.
  • Someone with no Python experience could open report.xlsx and understand the numbers without you in the room.