Key ideas
- The pipeline. Classic NLP turns raw text into countable units: sentence segmentation → tokenization (words and punctuation) → normalization (case folding, accents) → optional stop-word removal and stemming or lemmatization → features such as bag of words and tf-idf. Tagging (part of speech, named entities) and parsing build on these tokens.
- Types vs. tokens. A token (word instance) is one running occurrence, a type is a distinct word: "a rose is a rose is a rose" has 8 tokens but 3 types. Whether "They" and "they" count as one type depends on the task1.
- Words are not always marked. Chinese, Japanese and Thai are written without spaces, so whitespace splitting cannot find words; use a segmenter, characters or learned subwords1.
- Sentence segmentation. "?" and "!" are fairly reliable sentence ends, but a period also ends abbreviations ("Dr.", "p.m.") and appears inside numbers, so splitting after every period over-segments1.
- Regular expressions do rule-based tokenization.
[tT]hehandles case, and\bmarks a word boundary, so\bthe\bno longer matches inside "other". Counters (* + ?) bind tighter than sequences, sequences tighter than|, and matching is greedy1. In Python, the branches ofA|Bare tried from left to right and the first branch that matches wins, even if a later one would match more text6. - Stemming vs. lemmatization. Both reduce word forms to a common base. Stemming chops affixes with heuristic rules (Porter's algorithm is the standard English stemmer), so stems need not be words; lemmatization uses a vocabulary and morphological analysis to return the dictionary form (the lemma), e.g. "saw" → "see" as a verb but "saw" as a noun2. In search, stemming tends to raise recall and lower precision2.
- Stop words are frequent words such as "the", "and", "is" that are presumed to carry little content and are often removed5. Lists are blunt: scikit-learn's built-in English list also contains "not".
- Case folding (lowercasing) lets "Apple" at the start of a sentence match the query "apple", but it also merges names with common words ("General Motors", "Bush")7; for tasks where capitalization is a useful feature, such as finding names, keep it1.
- Parsing with a PCFG. A probabilistic context-free grammar gives each rule a probability, and probabilistic CKY multiplies them: a parse tree's probability is the product of the probabilities of its rules, so two parses built from the same rules tie. CKY needs binary rules (Chomsky normal form), e.g. with probability becomes () and (1), and it fills a chart over all spans in time8.
Formulas
- A text of tokens has -gram occurrences ("a rose is …": 7 bigram tokens, 3 bigram types).
- Zipf's law: the -th most frequent term has frequency 3.
- Heaps' (Herdan's) law: vocabulary size with , often about 0.44–0.56, so the vocabulary never stops growing1.
- Bag of words: one dimension per vocabulary word holding its count; word order is lost5. Dividing by the document length gives the averaged version.
- tf-idf: and , so a term that occurs in every document gets weight 04,5. scikit-learn's default uses the smoothed and then L2-normalizes each row5.
- Cosine similarity: .
Minimum edit distance is computed by dynamic programming over prefixes1:
with for equal letters. Levenshtein distance charges 1 for every insertion, deletion and substitution (intention → execution: 5); the textbook variant charges 2 for a substitution, the price of a deletion plus an insertion (intention → execution: 8)1.
Worked example
Corpus of documents: d1 "the cat sat on the mat", d2 "the dog sat", d3 "the cat ran", d4 "a dog barked". Weights for d1 with raw counts and :
| term | count in d1 | df | idf | tf-idf |
|---|---|---|---|---|
| the | 2 | 3 | 0.125 | 0.250 |
| cat, sat | 1 | 2 | 0.301 | 0.301 |
| on, mat | 1 | 1 | 0.602 | 0.602 |
The words unique to d1 ("on", "mat") get the highest weight; "the" is damped by its idf.
In code
from sklearn.feature_extraction.text import TfidfVectorizer
docs = ["the cat sat on the mat", "the dog sat", "the cat ran", "a dog barked"]
vec = TfidfVectorizer() # smooth_idf=True, norm="l2" by default
X = vec.fit_transform(docs)
idf = dict(zip(vec.get_feature_names_out(), vec.idf_.round(3)))
print(idf["the"], idf["cat"], idf["mat"]) # 1.223 1.511 1.916
print("a" in idf) # False: default token_pattern needs 2+ characters
print(X[0].toarray().round(2)) # [[0. 0.36 0. 0.45 0.45 0. 0.36 0.58]]
With the smoothed idf, "the" (count 2) gets the largest weight in d1, unlike the textbook table above.
Common pitfalls
- Tokenizing is more than splitting on punctuation: "U.S.A.", "3.50", "don't" and URLs need rules, and a period is not always a sentence end.
[tT]hewithout\balso matches inside "other" and "there" (false positives), whilethealone misses "The" (a false negative).- Stems are not dictionary words ("located" → "locat"), and unrelated words can collide: Porter maps both "generous" and "general" to "gener" (overstemming). Irregular forms such as "better" → "good" need a lemmatizer, not a stemmer.
- Removing stop words can remove meaning: "The food was not good" and "The food was good" give the same vector with scikit-learn's English list.
- Bag of words ignores order: "this is interesting" and "is this interesting" have cosine similarity 1.
- idf variants differ: textbook gives 0 to a word found in every document, scikit-learn's smoothed idf gives it 1; check the log base too.
- For equal-length words, the number of differing positions (Hamming distance) is only an upper bound on the Levenshtein distance: "stop" → "tops" differs in 4 positions but needs 2 edits.
References
- Jurafsky & Martin, Speech and Language Processing, 3rd ed. draft (Aug 2026), Ch. 2 Words and Tokens — Sec. 2.1 Words, 2.6 Regular Expressions, 2.8.1 Sentence Segmentation, 2.9 Minimum Edit Distance
- Manning, Raghavan & Schütze, Introduction to Information Retrieval — Sec. 2.2.4 Stemming and lemmatization
- Manning, Raghavan & Schütze, Introduction to Information Retrieval — Sec. 5.1.2 Zipf's law: Modeling the distribution of terms
- Manning, Raghavan & Schütze, Introduction to Information Retrieval — Sec. 6.2.1 Inverse document frequency (Eq. 21)
- scikit-learn User Guide: Text feature extraction — Sec. 8.2.3 Text feature extraction (8.2.3.1 The Bag of Words representation, 8.2.3.4 Using stop words, 8.2.3.5 Tf–idf term weighting)
- Python documentation: re — Regular expression operations — Regular expression syntax, the `|` (alternation) operator
- Manning, Raghavan & Schütze, Introduction to Information Retrieval — Sec. 2.2.3 Normalization, Capitalization/case-folding
- Wikipedia: CYK algorithm — Introduction; Standard form; Probabilistic CYK; Parsing weighted context-free grammars