Mini Project: Analyse a CSV File and Make a Report

Python for Beginners: Learn to Code with Real Projects · Objects, Libraries and Projects · 5 min read · Updated

From CSV to report

  1. The data starts in a CSV file with one expense on each row.
  2. csv.DictReader reads each row as a dictionary, with the column names as keys.
  3. The loop converts amounts to numbers and adds them to the total of each category.
  4. The totals are sorted from biggest to smallest and printed with each category share.

Time to use what you have learned. This project is typical of real office, finance and analyst work: take a CSV export, find out where the money goes and print a short report. It combines files, dictionaries, loops, sorting and formatted output. You do not need any extra packages. Later, if you move on to data work, tools such as pandas do the same job with less code, but doing it by hand first helps you understand what they do.

The data

Save this as expenses.csv in your project folder. It is a made-up set of expenses for one month. Each row has a date, a category, a description and an amount.

date,category,description,amount
2026-01-03,Food,Groceries,1250.50
2026-01-04,Travel,Metro card,500
2026-01-09,Food,Lunch with team,320
2026-01-12,Bills,Electricity,1800
2026-01-15,Food,Dinner out,780
2026-01-20,Travel,Taxi,260.75
2026-01-25,Bills,Internet,999
2026-01-28,Fun,Movie,450

The goal

We want a table that shows, for each category, the total amount and its share of all spending, the biggest categories first. We also want the biggest single expense. Plan the steps before you write code.

  1. Open the CSV and read each row as a dictionary.
  2. Convert the amount from text to a number.
  3. Add the amount to the total of its category, and remember the biggest expense so far.
  4. Work out the grand total.
  5. Sort the categories by total, from the biggest.
  6. Print a neat table.

The program

import csv
from collections import defaultdict
from pathlib import Path

here = Path(__file__).parent
totals = defaultdict(float)
biggest = None

with open(here / "expenses.csv", newline="", encoding="utf-8") as f:
    for row in csv.DictReader(f):
        amount = float(row["amount"])
        totals[row["category"]] += amount
        if biggest is None or amount > biggest["amount"]:
            biggest = {"description": row["description"], "amount": amount}

grand_total = sum(totals.values())
print(f"{'Category':<10}{'Total':>10}{'Share':>8}")
for category, total in sorted(totals.items(), key=lambda item: item[1], reverse=True):
    print(f"{category:<10}{total:>10.2f}{total / grand_total:>8.0%}")
print(f"{'All':<10}{grand_total:>10.2f}")
print("Biggest:", biggest["description"], biggest["amount"])
Category       Total   Share
Bills        2799.00     44%
Food         2350.50     37%
Travel        760.75     12%
Fun           450.00      7%
All          6360.25
Biggest: Electricity 1800.0

How it works

  • Path(__file__).parent is the folder where this script lives. Building the path from it means that the program finds expenses.csv wherever you start it from.
  • defaultdict(float) starts every new category at 0.0, so totals[row["category"]] += amount works even the first time a category appears.
  • The biggest variable starts as None. The first row replaces it, and later rows replace it only if their amount is larger.
  • sorted(totals.items(), key=lambda item: item[1], reverse=True) sorts the pairs by total, with the largest first.
  • In the f-string, {total / grand_total:>8.0%} formats a fraction as a percentage with no decimals. 2799 divided by 6360.25 is 44 percent.
  • The All row repeats the total, and you can check it by adding the categories by hand: 2799 plus 2350.50 plus 760.75 plus 450 is 6360.25.

Checking your work

A report that looks neat can still be wrong. Check it in a second way. Add up the amounts in the file by hand, or with a calculator, or in a spreadsheet, and compare it with the program total. Check one category by hand too. For Food, the rows are 1250.50, 320 and 780, and their sum is 2350.50, exactly as printed. When your program and a hand check agree, you can trust it.

Make it your own

  • Add a command-line option for the month or the file name (lesson 15 shows argparse).
  • Write the report into a file, with Path.write_text, so you can send it to someone.
  • Find expenses above a limit, such as 1000, and list them.
  • Group by month. Use the date column: row["date"][:7] gives 2026-01.
  • Handle bad rows. If an amount is not a number, float() raises a ValueError. Decide whether to skip the row and print a warning, or stop. Lesson 9 shows how.

From here to data jobs

Reading a file, cleaning it, grouping, summing and reporting is the heart of many data and office automation tasks. If you want to go further, look at pandas for tables and matplotlib for charts. Those are separate packages that you install with pip in a virtual environment (lesson 10). Learn the basics in this course first. They make every later tool easier to understand.

Your task

  1. Save expenses.csv and the program. Run it and compare each total with a hand calculation.
  2. Add a line that prints the average expense and the number of expenses.
  3. Add a second report that lists every expense over 700, one per line.
  4. Add three more rows to the CSV, including a new category, and check that the report updates.

How to check it worked

  • The report shows Bills 2799.00, Food 2350.50, Travel 760.75, Fun 450.00 and All 6360.25.
  • The biggest expense is Electricity 1800.0.
  • The program still works after you add rows with a new category.

Frequently asked questions

Why not just use a spreadsheet?

A spreadsheet is fine for one-off work. A Python script is better when you repeat the same job every week, when the file is very large, or when you want the steps written down and checked.

When should I use pandas?

When you work with large tables, many columns or need joins and charts. It saves code, but learn plain Python first so you understand what it does.