Project: analysing reviews with AI
Put it all together. You'll build a small but genuinely useful AI data pipeline — the kind analysts build every day.
Learning objectives
- Combine pandas and an AI API in one workflow
- Test AI processing on a sample before scaling
- Check AI labels for errors
- Summarise results and generate a brief
- Apply good habits: environments, scripts, Git and data protection
6.1 The project: analyse customer reviews with AI
You'll combine everything: a DataFrame of reviews, a function that asks an AI model to classify each one, and pandas to summarise the results into insights a manager can act on.
6.2 Step 1 — the data
import pandas as pd
reviews = pd.DataFrame({
"id": range(1, 9),
"text": [
"Gorgeous board, really solid. Arrived in two days.",
"Took nearly three weeks to arrive and no tracking updates.",
"Good quality but a bit expensive for the size.",
"The handle on the spatula snapped after a week.",
"Perfect gift, beautifully packaged!",
"Courier left it in the rain, box soaked.",
"Fine. Does the job.",
"Customer service sorted my refund quickly, thank you.",
],
})
6.3 Step 2 — classify with AI (test small first)
sample = reviews.head(3).copy()
sample["result"] = sample["text"].apply(classify_review) # from Module 5
print(sample)
# looks good? run on everything
reviews["result"] = reviews["text"].apply(classify_review)
results = pd.json_normalize(reviews["result"]) # dict column -> columns
reviews = pd.concat([reviews.drop(columns="result"), results], axis=1)
6.4 Step 3 — check the AI's work
Never trust AI labels blindly (see Validating AI Output). Read a sample, count failures, and fix the prompt if needed:
print(reviews[["text", "sentiment", "topic"]])
print("Unparsed:", reviews["sentiment"].isna().sum())
print(reviews["topic"].value_counts())
6.5 Step 4 — summarise for a manager
table = pd.crosstab(reviews["topic"], reviews["sentiment"])
print(table)
negatives = reviews[reviews["sentiment"] == "negative"]["text"].tolist()
brief = ask("Write a 4-bullet summary for a shop manager of these negative reviews, "
"with one suggested action each:\n- " + "\n- ".join(negatives))
print(brief)
6.6 Good habits as you grow
- Virtual environments (
python -m venv .venv) keep each project's packages separate - requirements.txt records the packages your project needs
- Move from notebooks to scripts (
.pyfiles) for code you'll reuse - Version control with Git — but add secrets files to
.gitignore - Small functions with clear names; test them on known inputs
- Data protection — don't send personal data to APIs without a lawful basis and an approved provider
6.7 Where next?
You now have the Python foundations used throughout the technical courses. Next steps: Data Quality & Preparation, Machine Learning Fundamentals and Building LLM Applications with RAG.
Exercise: extend the project
Add a column urgent that is True when a review is negative and mentions delivery or damage, then print the urgent reviews for follow-up.
Show a solution
reviews["urgent"] = (reviews["sentiment"] == "negative") & reviews["text"].str.contains(
"deliver|arriv|courier|damag|soaked|snapped", case=False)
print(reviews.loc[reviews["urgent"], ["id", "text"]])Key takeaways
- apply() runs a function over every row.
- json_normalize turns dictionary results into columns.
- Always check AI labels — count failures and read samples.
- Cross-tabs turn labels into insight.
- Virtual environments, scripts, Git and data protection keep projects healthy.