NLP in practice
Real NLP systems discover themes, feed dashboards and handle personal data. This module brings it together responsibly.
Learning objectives
- Discover topics with NMF and name them
- Track predicted categories over time
- Redact personal data before analysis
- Plan evaluation, routing and monitoring for production NLP
6.1 Discovering topics without labels
When you don't know the categories in advance — open-ended survey comments, for example — topic modelling groups words that tend to appear together. Non-negative matrix factorisation (NMF) on TF-IDF is a simple, effective method:
from sklearn.decomposition import NMF
topic_vec = TfidfVectorizer(stop_words="english", min_df=3)
Xt = topic_vec.fit_transform(messages["text"])
nmf = NMF(n_components=3, random_state=0, max_iter=500).fit(Xt)
terms = topic_vec.get_feature_names_out()
for i, comp in enumerate(nmf.components_):
print(f"Topic {i}:", ", ".join(terms[comp.argsort()[-6:][::-1]]))
Topics are lists of words that a human must interpret and name. Clustering embeddings (Module 3) is a modern alternative, and an LLM can suggest names for each cluster — which a person should then check.
6.2 Tracking language over time
rng = np.random.default_rng(0)
messages["week"] = rng.integers(1, 9, len(messages))
messages["predicted"] = clf.predict(messages["text"])
trend = pd.crosstab(messages["week"], messages["predicted"], normalize="index").round(2)
print(trend)
Dashboards of predicted categories or sentiment by week turn thousands of messages into a signal managers can act on — "billing complaints doubled after the price change". Always show volumes alongside percentages, and remember the model has errors of its own.
6.3 Personal data in text
Free text is full of personal data: names, emails, phone numbers, addresses, and sometimes health or financial details customers volunteer. Under data protection law (such as UK and EU GDPR), processing it needs a lawful basis, minimisation and security. Redact what you don't need before analysis or sending text to an external API:
def redact(text):
text = re.sub(r"[\w.+-]+@[\w-]+\.[\w.]+", "[EMAIL]", text)
text = re.sub(r"\b(?:\+44\s?7\d{3}|07\d{3})\s?\d{3}\s?\d{3}\b", "[PHONE]", text)
return text
print(redact("Call me on 07700 900123 or email sam.lee@example.com about GFY-48213"))
Regex redaction catches well-formed patterns but misses names and free-form details; dedicated PII-detection tools (and checking samples by hand) are needed for higher-risk data. See Responsible AI for the wider picture.
6.4 Bias, language and fairness
- Models trained mostly on standard English may perform worse on dialects, non-native writing or other languages — measure accuracy by group
- Sentiment and toxicity models have been shown to score some identity terms as negative regardless of context
- Keep a human route for customers whose messages the system misunderstands
- Document intended use, languages covered and known weaknesses
6.5 Putting an NLP system into production
- Evaluate on a held-out, hand-checked sample that reflects real traffic
- Route low-confidence or high-risk cases to people
- Monitor category mix, confidence and error rates — language drifts with new products, campaigns and slang
- Re-label and retrain regularly; keep a log of label guideline changes
- Protect personal data at every step, especially before calling external APIs
Combine what you've built: for the latest week in messages, report the number of messages, the share of each predicted category, the most common product mentioned (search for each name in products), and how many messages would need human review using route().
Show a solution
latest = messages[messages["week"] == messages["week"].max()]
print("Messages:", len(latest))
print(latest["predicted"].value_counts(normalize=True).round(2))
mentions = {p: latest["text"].str.contains(p, case=False).sum() for p in products}
print("Most mentioned product:", max(mentions, key=mentions.get))
print("Needs review:", route(latest["text"])["needs_review"].sum())Key takeaways
- Topic models find word groups; humans name them.
- Trends need volumes and known error rates.
- Redact personal data you don't need — especially before external APIs.
- Measure performance across dialects and languages.
- Route low-confidence cases, monitor drift, retrain.