A Taste of Python
print, arithmetic, NumPy, pandas, and charts — then publish your notebook and commit the finished project.
Module 8B · OverviewBy the end of this deck you can…
- Format output with
print()and f-strings - Use Python as a financial calculator
- Use NumPy for vectors, matrices, and solving linear systems
- Load and summarize a dataset with pandas
- Draw charts with matplotlib and seaborn
- Export notebooks to HTML and PDF — from the CLI and from VS Code
- Build, document, and commit a complete project
This is a taste, not a lesson plan for each topic — the following courses go deep on each.
Companion notebook: module-08b-taste-of-python.ipynb — worked examples and self-checking exercises.
SetupAdd the packages we need
uv add numpy pandas matplotlib seaborn
uv add --dev jupyterlab ruff # skip any you already added in Part A
code .
Then create notebooks\02_taste.ipynb with the .venv kernel and type along. Put a Markdown heading above each section as you go.
Typing (not pasting) the examples is the fastest way to learn. Make typos. Read the error messages. Fix them.
Python Basics
print() and Python as a calculator.
print()Talking to the outside world
print("Hello, actuaries") # Hello, actuaries
print("PV =", 772.17) # PV = 772.17
print("a", "b", "c", sep=" | ") # a | b | c
name = "Jane"
rate = 0.0372
reserve = 1234567.891
print(f"Analyst: {name}") # Analyst: Jane
print(f"Lapse rate: {rate:.1%}") # Lapse rate: 3.7%
print(f"Reserve: {reserve:,.2f}") # Reserve: 1,234,567.89
print(f"{'Age':<5}{'qx':>8}") # Age qx
f-strings (f"…") insert values into text. After a colon, a format spec controls the look:
:.2f | 2 decimal places |
:,.2f | thousands separator too |
:.1% | as a percentage |
:<5 / :>8 | left / right align in a width |
CalculatorPython as a (very good) financial calculator
| Operator | Example | Result |
|---|---|---|
+ - * | 3 * (2 + 4) | 18 |
/ | 7 / 2 | 3.5 |
// floor division | 7 // 2 | 3 |
% remainder | 7 % 2 | 1 |
** power | 1.05 ** 2 | 1.1025 |
^ is not “power” in Python (it’s bitwise XOR). Excel users: use **.
i = 0.05 # effective annual rate
n = 10 # term in years
v = 1 / (1 + i) # discount factor
# Accumulate 1,000 for 10 years
round(1000 * (1 + i) ** n, 2) # 1628.89
# Present value of 1,000 due in 10 years
round(1000 * v ** n, 2) # 613.91
# Annuity-immediate: a-angle-n at 5%
a_n = (1 - v ** n) / i
round(a_n, 4) # 7.7217
NumPy
A vector and matrix calculator.
NumPyVectors: whole columns at once
import numpy as np
t = np.arange(1, 11) # [ 1 2 3 ... 10]
v = 1.05 ** -t # 10 discount factors at once
cf = np.full(10, 100.0) # 100 paid at the end of each year
pv = (cf * v).sum() # element-wise multiply, then add up
print(round(pv, 2)) # 772.17
round(pv, 2) # np.float64(772.17): same value, NumPy type
cf @ v # same thing as a dot product
- A NumPy array is like an Excel column you can do math on in one go — no dragging formulas down
- Operations apply element-wise:
1.05 ** -tcomputes all ten powers @is matrix / dot-product multiplication
Same answer as 100 * a_n from the previous slide — but this version handles any cash-flow pattern.
NumPySolving a system of linear equations
Three bonds, their cash flows at t = 1, 2, 3, and market prices. Which discount factors d1, d2, d3 price them all?
Each row: price = Σ cash flow × discount factor. That’s C d = P.
C = np.array([[105, 0, 0], # 1-yr bond, 5% coupon
[ 6, 106, 0], # 2-yr bond, 6% coupon
[ 4, 4, 104]]) # 3-yr bond, 4% coupon
P = np.array([100.00, 101.00, 96.50])
d = np.linalg.solve(C, P)
d.round(4) # array([0.9524, 0.8989, 0.8567])
# Implied spot rates, in %
t = np.arange(1, 4)
spot = d ** (-1 / t) - 1
(spot * 100).round(2) # array([5. , 5.47, 5.29])
np.linalg.solve handles 3 equations or 3,000 — the same one line. (You just bootstrapped a yield curve.)
pandas
Spreadsheets, programmable.
pandasThe sample dataset
Save this as data\policies.csv (VS Code: New File, paste, save):
policy_id,issue_age,sex,product,sum_assured,annual_premium,status
P001,34,F,TERM,250000,310.50,IN_FORCE
P002,45,M,TERM,500000,980.00,LAPSED
P003,29,F,WHOLE_LIFE,100000,1450.00,IN_FORCE
P004,52,M,WHOLE_LIFE,200000,3890.00,IN_FORCE
P005,41,F,TERM,300000,455.25,LAPSED
P006,38,M,TERM,400000,620.00,IN_FORCE
P007,60,F,WHOLE_LIFE,150000,4210.00,DEATH_CLAIM
P008,33,M,TERM,350000,402.75,IN_FORCE
This file is small and synthetic, so it lives in data\ and gets committed. Real extracts go in data\raw\, which .gitignore keeps out of Git (Module 5).
pandasLoad and look
import pandas as pd
df = pd.read_csv("../data/policies.csv")
df.head() # first 5 rows, as a table
df.shape # (8, 7) → rows, columns
df.dtypes # the type of each column
df.describe() # count, mean, std, min, max…
| policy_id | issue_age | product | annual_premium | status | |
|---|---|---|---|---|---|
| 0 | P001 | 34 | TERM | 310.50 | IN_FORCE |
| 1 | P002 | 45 | TERM | 980.00 | LAPSED |
| 2 | P003 | 29 | WHOLE_LIFE | 1450.00 | IN_FORCE |
(some columns omitted to fit the slide)
Excel files work too: pd.read_excel("../data/raw/extract.xlsx", sheet_name="Policies") — that’s what openpyxl is for.
pandasAsk questions of the data
# One column
df["annual_premium"].mean() # np.float64(1539.8125)
# Filter rows
df[df["issue_age"] >= 50] # P004, P007
# A new calculated column
df["rate_per_mille"] = (
df["annual_premium"] / df["sum_assured"] * 1000
)
# Count by category
df["status"].value_counts()
# Summarize by group (a pivot table)
df.groupby("product")["annual_premium"].mean().round(2)
status
IN_FORCE 5
LAPSED 2
DEATH_CLAIM 1
Name: count, dtype: int64
product
TERM 553.70
WHOLE_LIFE 3183.33
Name: annual_premium, dtype: float64
groupby is a pivot table you can re-run on next quarter’s extract without touching a single cell.
Charts
matplotlib for control, seaborn for statistical graphics.
matplotlibThe foundation
import matplotlib.pyplot as plt
avg = df.groupby("product")["annual_premium"].mean()
fig, ax = plt.subplots(figsize=(6, 4))
ax.bar(avg.index, avg.values, color=["#0e6b6b", "#c26a1b"])
ax.set_title("Average annual premium by product")
ax.set_ylabel("Premium")
fig.savefig("../output/premium_by_product.png",
dpi=150, bbox_inches="tight")
In a notebook the chart appears below the cell automatically. savefig writes a file to output\ for reports.
seabornStatistical charts in one line
import seaborn as sns
sns.set_theme(style="whitegrid")
sns.scatterplot(data=df, x="issue_age",
y="annual_premium", hue="product")
# other one-liners to try:
sns.boxplot(data=df, x="product", y="annual_premium")
sns.histplot(data=df, x="issue_age", bins=5)
sns.countplot(data=df, x="status")
seaborn understands DataFrames: name the columns, and it handles colors, legends, and axis labels.
Publishing Notebooks
HTML and PDF for people who don’t run Python.
nbconvertFrom the command line
# HTML (always works — jupyterlab already installed nbconvert)
uv run jupyter nbconvert --to html notebooks/02_taste.ipynb --output-dir output
# Re-run every cell first, so the export is guaranteed fresh
uv run jupyter nbconvert --to html --execute notebooks/02_taste.ipynb --output-dir output
# Hide the code — results and prose only, for managers and reviewers
uv run jupyter nbconvert --to html --no-input notebooks/02_taste.ipynb --output-dir output
# PDF via LaTeX (needs MiKTeX from Module 6)
uv run jupyter nbconvert --to pdf notebooks/02_taste.ipynb --output-dir output
# PDF via a headless browser (no LaTeX needed)
uv add --dev "nbconvert[webpdf]"
uv run jupyter nbconvert --to webpdf --allow-chromium-download notebooks/02_taste.ipynb --output-dir output
--execute + --no-input is a one-line, reproducible reporting pipeline: fresh numbers, no hidden state, no code on show.
VS CodeExporting from the Jupyter extension
- Open the notebook; Restart → Run All
- Click … (More Actions) in the notebook toolbar → Export
- Choose HTML or PDF
- Pick a location — save into
output\
Under the hood this uses the same nbconvert, running in your .venv kernel. PDF export needs a LaTeX distribution (MiKTeX).
No LaTeX? Export to HTML, open it in your browser, and use Print → Save as PDF.
Final Lab · 45 minYour first complete Python project
- Project
actuarial_introcreated withuv, standard folders, packages added - A script,
src\premium_summary.py, that uses pandas - A notebook,
notebooks\02_taste.ipynb, with prose, calculations, a table, and a chart - An HTML export in
output\ - A README and a clean
.gitignore - Everything committed to Git in small, well-described commits
Definition of done
Anyone can run:
git clone <your repo>
cd actuarial_intro
uv sync
uv run python src/premium_summary.py
…and get the same output as you.
Lab · The scriptsrc\premium_summary.py
"""Summarize the sample policy file by product."""
from pathlib import Path
import pandas as pd
DATA = Path("data") / "policies.csv"
df = pd.read_csv(DATA)
print(f"{len(df)} policies loaded from {DATA}")
print()
summary = (
df.groupby("product")["annual_premium"]
.agg(["count", "mean"])
.round(2)
)
print(summary)
PS> uv run python src/premium_summary.py
8 policies loaded from data\policies.csv
count mean
product
TERM 5 553.70
WHOLE_LIFE 3 3183.33
Notice pathlib printed data\policies.csv — backslash on Windows — though we wrote /-style parts. Portable code, native display (Module 1).
Save → Ruff formats it. Any squiggles? Fix them.
Lab · The notebooknotebooks\02_taste.ipynb
Build it from this deck’s examples, one section per heading:
- Markdown: title, your name, one-line purpose
- Calculator: the annuity value
a_n - NumPy: the bond-bootstrap system and spot rates
- pandas: load
policies.csv,describe(),value_counts(),groupby - Charts: the bar chart (saved to
output\) and the seaborn scatter - Markdown: three bullet-point observations
Before exporting: Restart kernel & Run All. If it fails top-to-bottom, fix it before anyone else sees it.
uv run jupyter nbconvert --to html --execute `
notebooks/02_taste.ipynb --output-dir output
start output\02_taste.html
The backtick ` at the end of a line continues a PowerShell command onto the next line.
Lab · CommitPut it all in Git
git init # skip if uv already created .git
notepad .gitignore # add the Module 5 sections (output/, data/raw/, .env …)
git status # .venv, output\ must NOT be listed
git add .gitignore pyproject.toml uv.lock .python-version
git commit -m "Set up actuarial_intro with numpy, pandas, matplotlib, seaborn"
git add data/policies.csv src/
git commit -m "Add sample policy data and premium summary script"
git add notebooks/
git commit -m "Add taste-of-Python notebook"
git add README.md .vscode/
git commit -m "Document project and share editor settings"
git log --oneline
# Optional: create an empty private repo on GitHub, then
git remote add origin https://github.com/<you>/actuarial_intro.git
git push -u origin main
Course 0W · RecapLook what you can do now
1 · Files
Read any path; keep work outside OneDrive2 · Terminal
Navigate and manage files in PowerShell3 · PATH
Fix “not recognized”; install with winget4 · uv
Reproducible Python environments5 · Git
History, diffs, and safe undo6 · Docs
Markdown, pandoc, notebooks7 · VS Code
One configured, shareable workspace8 · Python
Scripts, NumPy, pandas, chartsYour PC is now a programmer’s PC.
You’re ready to program.
Next: Python fundamentals in depth — built on the workspace, tools, and habits you set up here.