pip install contractions rake-nltk keybert★contractions = normalize; rake-nltk = statistical keyphrases (no ML); KeyBERT = semantic keyphrases (BERT embeddings, pulls in sentence-transformers + torch).import nltk nltk.download("stopwords"); nltk.download("punkt_tab")★rake-nltk needs NLTK data — stopwords and the tokenizer (punkt_tabon NLTK 3.9+). Do this once before using RAKE.# RAKE: fast, deterministic, no semantics # KeyBERT: semantic, needs a model (slower, better phrases)Rule of thumb: reach for RAKE at scale or with no GPU; KeyBERT when phrase quality/meaning matters.
import contractions contractions.fix("I can't believe it's working") # -> "I cannot believe it is working"★One function does it. Handles hundreds of forms, including compound ones likeshouldn't've→should not have.contractions.add("mfw", "my face when")★Register your own expansions (slang, domain abbreviations) before callingfix.# ambiguous forms expand to ONE fixed meaning contractions.fix("ain't") # -> "are not"Limitation: it's not context-aware —ain't(am/are/is/has/have not) always becomes one form.
text = contractions.fix(raw_text) text = text.strip() # then tokenize / remove stopwords / extract keywords★Expand contractions early — before tokenizing or stopword removal — so"don't"doesn't split into a junk"n't"token.# be gentle with lowercasingAggressive.lower()helps RAKE/count methods but can slightly hurt KeyBERT (its embeddings handle case). Normalize to match the extractor.# combine with NLTK / spaCy for tokenize + lemmatizeThese three cover normalize + keyphrases; use the NLTK/spaCy sheets for tokenization, POS, and lemmatization in the same pipeline.