I spent the last stretch of time buried in 3,000 customer reviews, trying to answer a question that sounds simple but turned out not to be: when a customer leaves a 3-star review, what are they actually telling you?
The short answer — not what you'd think. And the project I built around that question ended up teaching me more about designing trustworthy AI tools than about sentiment analysis itself. I'm sharing the whole thing, code included, here: github.com/dshah-ds/customer-sentiment-review-automation
Why I started digging into this
I think most of us, without really deciding to, treat star ratings as a shorthand for how a customer feels. 5 stars, thrilled. 1 star, furious. 3 stars... whatever, average, nothing to see here.
I wanted to check that assumption against the actual words customers used, not just the number they clicked. So I took a dataset of 3,000 reviews and ran the review text through a sentiment scoring tool, completely separate from the star rating, and then compared the two.
They disagreed almost half the time. 45% of reviews had a star rating that didn't match the tone of what the customer actually wrote. And the 3-star group was the biggest offender — 78% of those "neutral" reviews were, in plain English, positive. Customers who liked the product but didn't feel strongly enough to hit the top rating.
That also means there's a smaller group hiding in that same 3-star bucket who are genuinely unhappy but never bothered to rate it lower. If your process is "escalate the 1 and 2 star reviews," you're walking right past them.
Not all "unhappy" looks the same
The next thing I wanted to understand was whether Positive, Neutral, and Negative reviews were really just different points on the same line, or if they were actually different kinds of feedback that deserved different responses.
So I split the reviews into three groups and measured a few things about each one: how positive or negative the language was, how "urgent" it sounded (I counted words like broken, defective, refund, immediately), how long the reviews were, and which words showed up disproportionately in each group.
What I found made each group feel like a real, distinct type of customer rather than a data label:
- Negative reviews were short and specific, and had a real urgency signal attached — customers who already knew exactly what was wrong and what they wanted done about it.
- Neutral reviews had zero urgency, on average, and their own vocabulary entirely — "okay," "fine," "decent," "basic." Not angry, not thrilled, just unmoved.
- Positive reviews were the most detailed and enthusiastic of the three, full of specific praise.
I ran the numbers to make sure this wasn't just my imagination — using a method called cosine similarity, which measures how alike two groups of text really are. All three groups came back clearly distinct from each other. They're not shades of the same feeling. They're three separate populations that need three separate responses.
Then I built the thing — and immediately found a flaw in it
The last part of the project was turning all of this into something usable: a small tool where you paste in a review and it tells you the sentiment, an urgency score, the likely themes, and even drafts a reply using Google's Gemini model that a support person could send.
While testing it, I found a bug I actually think is the most valuable part of the whole project.
One review said a product was "decent for the money." My tool flagged it as a Refund Request. Why? Because the word "money" is common in real refund complaints ("I want my money back"), so it was on the watch-list — but here it just meant "good value for the price." No refund involved anywhere.
I could have quietly fixed the keyword list and moved on like it never happened. Instead I left it in and wrote it up, because it's a small, honest example of exactly why I built this as a draft-and-review tool instead of a fully automatic one. A person glancing at that flagged review would catch the mistake in about two seconds. A system that skipped the human and auto-responded wouldn't — and would have treated a satisfied customer like an angry one.
That's the part of the project I'm proudest of, honestly. Not the parts that worked — the part where something broke in a way that made the argument for careful design better than any slide deck could.
If you want to poke around
Everything — the notebook, the three write-ups (insight generation, segment comparison, and the deployed tool), and my own reflection on what I'd change for a real production version — is up on GitHub:
github.com/dshah-ds/customer-sentiment-review-automation
I'd love to hear from a couple of different directions on this. If you've ever worked in support or read a pile of customer reviews for your own product, does that 45% mismatch number sound about right, or higher/lower than what you've noticed? And if data or AI work is newer territory for you, tell me what part of this you'd want unpacked further — happy to write a follow-up post on whichever piece people are most curious about.
Comments
Post a Comment