Learn Python for Beginners: Analyse a Sales CSV
Read a small CSV, apply a business rule and verify category totals using only Python’s standard library.
Start with a question you can check
You do not need a large dataset or several libraries to practise useful analysis. This exercise asks: what is the value of completed orders in each category? Every row is one order, amounts are whole US dollars (USD), and the data is invented. Returned and pending orders are excluded under the exercise’s definition.
The distinction between the data and the rule matters. A returned order is a valid record, but it is outside this particular calculation. In a real revenue report, clarify partial refunds, cancellations, taxes and the timing of recognition before reusing the rule.
Use Python 3 in a local editor or notebook. No extra package is required. Paste the full example into a new file and run it. The input is embedded in the code, so there is no download or file path to configure.
Run the complete example
import csv
from io import StringIO
from collections import defaultdict
data = """order_id,category,amount,status
101,Books,500,completed
102,Games,700,completed
103,Books,200,returned
104,Books,300,completed
105,Games,100,pending
"""
totals = defaultdict(int)
seen = set()
completed_count = 0
for row in csv.DictReader(StringIO(data)):
order_id = row["order_id"]
if order_id in seen:
raise ValueError(f"Duplicate order: {order_id}")
seen.add(order_id)
if row["status"] not in {"completed", "returned", "pending"}:
raise ValueError("Unexpected status")
amount = int(row["amount"])
if amount < 0:
raise ValueError("Negative amount in this exercise")
if row["status"] == "completed":
totals[row["category"]] += amount
completed_count += 1
for category, revenue in sorted(totals.items()):
print(category, revenue)
print("Completed orders:", completed_count)
print("Total:", sum(totals.values()))Compare the output with a hand calculation
| Printed line | Why it is correct |
|---|---|
| Books 800 | Completed orders 101 and 104: 500 + 300 |
| Games 700 | Completed order 102 only |
| Completed orders: 3 | 101, 102 and 104 satisfy the status rule |
| Total: 1500 | 800 + 700 |
The input amount total is US$1,800. The returned US$200 order and pending US$100 order explain the US$300 difference from the completed total. This reconciliation is more informative than simply saying that the script ran successfully.
Alphabetical sorting makes the printed order predictable. It does not mean Books is always the highest-revenue category; the sorting rule is the category name. To rank by revenue, you would change that rule and define how to resolve ties.
Understand the pieces
csv.DictReader uses the header row as field names. CSV fields arrive as strings here, so the code explicitly converts each amount into an integer. StringIO lets the example read a string as a file-like object. For a real CSV file, use a context manager and open it with newline="", as shown in the Python CSV documentation.
The set called seen detects a repeated order ID. That check is appropriate only because we defined one row as one order. For an order-line file, several rows can legitimately share an order ID; you would need a line identifier or a different uniqueness rule.
The dictionary accumulates one total per category. Its default value is zero, so the first completed order can be added without first creating the category. The status check rejects unfamiliar values instead of silently excluding a misspelling such as “complete”.
Change the input and predict the answer
- Add order 106 for Books, amount 100, status completed. Expect Books 900, four completed orders and a total of 1,600.
- Repeat order 101 with a new amount. Expect a duplicate-order error. Investigate the record rather than deleting whichever row is inconvenient.
- Change an amount to an empty field. Integer conversion should fail; an unknown amount is not automatically zero.
- Change all statuses to pending. Expect no category lines, zero completed orders and a zero total.
The example deliberately uses whole US dollars (USD). For fractional currency, define an appropriate representation such as integer US cents or decimal arithmetic; do not casually round away differences. Also check blank categories, missing IDs and unexpected columns before adapting the script to messier data.
Once you can explain the loop, try the pandas worked example. Compare both implementations against the same expected totals. A useful interview explanation names the grain, the filter, the aggregation and the evidence that the result is correct.
