Personal Finance Analyzer, Revisited With pandas
Data Science & ML Projects (Beginner)
Chapter 4 · Personal Finance Analyzer, Revisited With pandas
py4-8's own expense tracker built its category totals with a hand-rolled dict-accumulation loop and its overall total with a generator expression — genuinely good Python, and completely appropriate for that course's own scope. This chapter takes the exact same problem and rebuilds its analysis with the tools this course has been using all along, making concrete exactly what "the right tool for the job" bought a learner who has now taken both courses.
What We're Building
The same expense data py4-8 tracked — amount, category, description — now with one addition a real finance tool needs: a date per expense. Loaded into a DataFrame, the exact same two summaries py4-8 built by hand become one-line pandas operations, and two genuinely new analyses (monthly trends, a real chart) become possible that weren't practical to hand-roll before.
# expenses.json — py4-8's own schema, plus one new field: date [ {"date": "2026-01-03", "amount": 12.50, "category": "Food", "description": "Lunch"}, {"date": "2026-01-05", "amount": 45.00, "category": "Transport", "description": "Fuel"}, {"date": "2026-02-01", "amount": 89.99, "category": "Food", "description": "Groceries"} ]
Step 1: Loading Into a DataFrame
import pandas as pd df = pd.read_json("expenses.json") df["date"] = pd.to_datetime(df["date"]) print(df.head())
One line replaces py4-8's own json.loads(FILE.read_text()) plus manually keeping the result as a list of dicts — pd.read_json() parses the file directly into a DataFrame.
Step 2: Totals — The Direct Payoff
| py4-8's own plain Python | This chapter's pandas equivalent |
|---|---|
totals = {}
for e in expenses:
totals[e["category"]] = (
totals.get(e["category"], 0)
+ e["amount"]
) |
totals = df.groupby("category")["amount"].sum() |
sum(e["amount"] for e in expenses) |
df["amount"].sum() |
py4-8's own totals.get(category, 0) + amount pattern was itself a direct reuse of the site's own word-frequency-counter idiom — real, working code. .groupby("category")["amount"].sum() does the identical job in one call, built on the same vectorized, C-level operations ds1-2 introduced as NumPy's own real advantage over a plain Python loop.
Step 3: What py4-8 Genuinely Couldn't Do Easily — Monthly Trends
monthly = df.set_index("date").resample("ME")["amount"].sum() print(monthly) # 2026-01-31 57.50 # 2026-02-28 89.99
Reproducing this in plain Python would mean manually parsing every date string, bucketing entries by year-and-month into a dict, and keeping that bucketing logic in sync everywhere it's needed — not impossible, but real, fiddly work py4-8's own scope never asked for. .resample("ME") does the entire "group by calendar month" operation in one call, because the DataFrame's own datetime index already understands calendar structure.
Step 4: A Real Chart
import matplotlib.pyplot as plt fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4.5)) totals.plot(kind="pie", ax=ax1, autopct="%1.0f%%", ylabel="", colors=["#15803D", "#EAB308", "#4ade80", "#facc15"]) ax1.set_title("Spending by Category") monthly.plot(kind="line", marker="o", ax=ax2, color="#15803D") ax2.set_title("Spending Over Time") ax2.set_ylabel("$") plt.tight_layout() plt.savefig("finance_dashboard.png")
Both charts plot directly off the groupby/resample results from Steps 2 and 3 — a genuine payoff of keeping the data in a DataFrame throughout, rather than converting back to plain lists and dicts just to hand them to a chart.
The Complete Analysis Script
import pandas as pd, matplotlib.pyplot as plt df = pd.read_json("expenses.json") df["date"] = pd.to_datetime(df["date"]) totals = df.groupby("category")["amount"].sum() monthly = df.set_index("date").resample("ME")["amount"].sum() print("Totals by category:\n", totals) print("\nMonthly spending:\n", monthly) print(f"\nOverall total: ${df['amount'].sum():.2f}") fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 4.5)) totals.plot(kind="pie", ax=ax1, autopct="%1.0f%%", ylabel="") ax1.set_title("Spending by Category") monthly.plot(kind="line", marker="o", ax=ax2) ax2.set_title("Spending Over Time") plt.tight_layout() plt.savefig("finance_dashboard.png")
py4-8's own scope — a few dozen expenses, entered one at a time through a CLI menu — plain Python was completely appropriate; pulling in pandas for that would have been real, unnecessary overhead. pandas earns its keep specifically at the scale and shape of analysis this chapter adds: month-over-month trends across a genuinely large history, and charts built directly from the data without a manual conversion step. The right tool depends on what the job actually is, not on which tool is newer or more powerful in the abstract.
pd.read_json()
Loads JSON directly into a DataFrame — one line, no manual list-of-dicts handling.
.groupby().sum()
Replaces a hand-rolled dict-accumulation loop with one vectorized call.
.resample("ME")
Groups by calendar month using a datetime index — no manual date-bucketing logic.
Charting straight from results
groupby/resample output plots directly — no conversion back to plain Python first.
Try these on your own:
- Add a
budgetdict per category and compute how far over/under budget each category is for the current month. - Use
.resample("W")instead of"ME"to see weekly rather than monthly spending trends. - Merge in the weather log from Chapter 3 by date and check, out of genuine curiosity, whether spending correlates with rainy days.
- Bring back
py4-8's ownadd_expense()CLI function to append new entries, then re-run this chapter's analysis on the growing file.
What's Next
Chapter 5: Movie Ratings Explorer — the course's own central EDA chapter, applying ds1-9's/ds1-10's own seven-step methodology to a fresh public dataset without a checklist to lean on.
Chapter 4 Quick Reference
- Rebuilds py4-8's own expense-tracker analysis with pandas — same problem, the tools this course has been using since Chapter 2
.groupby("category")["amount"].sum()replaces a hand-rolled dict-accumulation loop directly.resample("ME")makes month-over-month trends practical in one line — genuinely hard to hand-roll well in plain Python- Charts plot directly from groupby/resample results — no manual conversion step needed
- Honest note: pandas earns its keep at this chapter's own scale and shape of analysis, not universally — py4-8's own plain-Python scope didn't need it