Complete walkthrough from raw text to semantic meaning — Levels 1 through 4
The Natural Language Toolkit (NLTK) is a free, open-source Python package providing interfaces for text processing, linguistic structure analysis, and access to a large collection of corpora. It is the leading platform for building Python programs to work with human language data.
NLTK provides interfaces to over 50 corpora and lexical resources such as WordNet, along with libraries for:
| Level | Name | Description | Key Tasks |
|---|---|---|---|
| 1 | Lexical | Breaks text into words and cleans it | Tokenization, Stop Words, Lowercasing |
| 2 | Morphological | Studies word formation and structure | Stemming, Lemmatization |
| 3 | Syntactic | Analyzes grammar and sentence structure | POS Tagging, Chunking, Parsing |
| 4 | Semantic | Extracts meaning from text | NER, WSD, Sense Detection |
Tokenization · Stop Words · Stemming · Lemmatization
import nltk
from nltk.tokenize import word_tokenize, sent_tokenize
from nltk.corpus import stopwords
# Required NLTK downloads (run once)
nltk.download('punkt_tab') # Tokenizer models
nltk.download('stopwords') # Stop words corpus
Tokenization divides text into smaller parts called tokens. It is the base step for stemming and lemmatization. NLTK provides two main methods:
| Method | Function | Returns | Description |
|---|---|---|---|
| Word Tokenize | word_tokenize() | List of words | Splits text into individual word tokens |
| Sentence Tokenize | sent_tokenize() | List of sentences | Splits text into individual sentences |
import nltk
from nltk.tokenize import word_tokenize
nltk.download('punkt_tab')
text = "Hello there! How are you doing today?"
words = word_tokenize(text)
print(words)
['Hello', 'there', '!', 'How', 'are', 'you', 'doing', 'today', '?']
from nltk.tokenize import sent_tokenize
text = "Hello there! How are you doing today? NLTK is very useful."
sentences = sent_tokenize(text)
print(sentences)
['Hello there!', 'How are you doing today?', 'NLTK is very useful.']
Stop words are commonly used words (such as "the", "a", "an", "in") that carry little semantic value and are typically ignored in processing. NLTK includes stop words lists for 16 different languages.
nltk_data/corpora/stopwords/english.txt.
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
nltk.download('punkt_tab')
nltk.download('stopwords')
sentence = "I went to the university in the morning with my friend."
words = word_tokenize(sentence)
stop_words = set(stopwords.words('english'))
filtered_words = [word for word in words if word.lower() not in stop_words]
print("Original:", sentence)
print("Filtered:", " ".join(filtered_words))
Original: I went to the university in the morning with my friend.
Filtered: went university morning friend .
| Stemmer | Class | Aggression | Notes | "running" → |
|---|---|---|---|---|
| Porter | PorterStemmer | Moderate | Most common & widely used | run |
| Lancaster | LancasterStemmer | High | Very aggressive, shortest roots | run |
| Snowball | SnowballStemmer | Moderate–Low | Multi-language support | run |
from nltk.stem import PorterStemmer
stemmer = PorterStemmer()
words = ["running", "happiness", "flies", "studying"]
stemmed = [stemmer.stem(word) for word in words]
print(stemmed)
['run', 'happi', 'fli', 'studi']
from nltk.stem import LancasterStemmer
stemmer = LancasterStemmer()
words = ["running", "happiness", "flies", "studying"]
stemmed = [stemmer.stem(word) for word in words]
print(stemmed)
['run', 'happy', 'fli', 'study']
from nltk.stem import SnowballStemmer
stemmer = SnowballStemmer("english")
words = ["running", "happiness", "flies", "studying"]
stemmed_words = [stemmer.stem(word) for word in words]
print("Original:", words)
print("Snowball:", stemmed_words)
Original: ['running', 'happiness', 'flies', 'studying']
Snowball: ['run', 'happi', 'fli', 'studi']
| POS Tag | Part of Speech | Example |
|---|---|---|
| n (default) | Noun | bats → bat, feet → foot |
| v | Verb | stripes → strip, running → run |
| a | Adjective | better → good |
| r | Adverb | quickly → quick |
pos parameter is omitted, the default is Noun (n).
nltk.download('wordnet') # WordNet lexical database
nltk.download('omw-1.4') # Open Multilingual WordNet
import nltk
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
text = "studies studying cries cry"
tokenization = nltk.word_tokenize(text)
for w in tokenization:
print(f"Lemma for {w} is {lemmatizer.lemmatize(w)}")
Lemma for studies is study
Lemma for studying is studying
Lemma for cries is cry
Lemma for cry is cry
lemmatizer = WordNetLemmatizer()
print("rocks :", lemmatizer.lemmatize("rocks")) # Noun (default)
print("corpora:", lemmatizer.lemmatize("corpora")) # Noun (default)
print("better :", lemmatizer.lemmatize("better", pos="a")) # Adjective
rocks : rock
corpora: corpus
better : good
print(lemmatizer.lemmatize("bats")) # → bat
print(lemmatizer.lemmatize("are")) # → are
print(lemmatizer.lemmatize("feet")) # → foot
print(lemmatizer.lemmatize("stripes", 'v')) # → strip
print(lemmatizer.lemmatize("stripes", 'n')) # → stripe
bat
are
foot
strip
stripe
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize
sentence = "The striped bats are hanging on their feet for best"
lemmatizer = WordNetLemmatizer()
word_list = word_tokenize(sentence)
lemmatized_output = ' '.join([lemmatizer.lemmatize(w) for w in word_list])
print(lemmatized_output)
The striped bat are hanging on their foot for best
from nltk.tokenize import word_tokenize
from nltk.stem import WordNetLemmatizer
lemmatizer = WordNetLemmatizer()
text = "the boy cries when he goes to the school with the students by the bus."
sent = word_tokenize(text)
for w in sent:
print(lemmatizer.lemmatize(w))
the boy cry when he go to the
school with the student by the bus .
from nltk.stem import WordNetLemmatizer
from nltk.tokenize import word_tokenize
text = "The children were running and the mice were eating cheese"
lemmatizer = WordNetLemmatizer()
result = [lemmatizer.lemmatize(word) for word in word_tokenize(text)]
print(result)
['The', 'child', 'were', 'running', 'and', 'the', 'mouse', 'were', 'eating', 'cheese']
Note: "children" → "child" | "mice" → "mouse"
Stemming vs Lemmatization — Comparison Summary
| Feature | Stemming | Lemmatization |
|---|---|---|
| Method | Rule-based (removes suffixes) | Dictionary-based (WordNet) |
| Output | May not be a real word | Always a real word (lemma) |
| Speed | ⚡ Faster | Slower (requires lookup) |
| Accuracy | Lower | Higher |
| POS Aware? | ❌ No | ✅ Yes (pos parameter) |
| Example | "studies" → studi | "studies" → study |
| Best for | Search engines, IR | NLP, text understanding |
POS Tagging · Chunking · Constituency Parsing · Dependency Parsing
import nltk
from nltk.tokenize import word_tokenize
from nltk import pos_tag, RegexpParser
from nltk.parse import DependencyGrammar
nltk.download('punkt_tab')
nltk.download('averaged_perceptron_tagger_eng') # POS tagger
POS tagging assigns a grammatical category (noun, verb, adjective, etc.) to each word in a sentence.
| Tag | Meaning | Examples |
|---|---|---|
| NN | Noun, singular | "apple", "school" |
| NNS | Noun, plural | "apples", "students" |
| NNP | Proper noun, singular | "Tom", "Google" |
| NNPS | Proper noun, plural | "Avengers" |
| VB | Verb, base form | "eat", "run" |
| VBD | Verb, past tense | "ate", "went" |
| VBZ | Verb, 3rd person singular | "eats", "goes" |
| VBG | Verb, gerund/present participle | "eating", "running" |
| JJ | Adjective | "big", "early" |
| RB | Adverb | "quickly", "everyday" |
| DT | Determiner | "the", "a", "an" |
| IN | Preposition / subordinating conj. | "in", "on", "at" |
| PRP | Personal pronoun | "I", "he", "she" |
| CD | Cardinal number | "three", "5.1" |
| TO | Preposition "to" | "to" |
| CC | Coordinating conjunction | "and", "but", "or" |
| WRB | Wh-adverb | "when", "where" |
import nltk
from nltk import word_tokenize, pos_tag
sentence = "Tom ate an apple at 10:00 am."
tokens = word_tokenize(sentence)
tags = pos_tag(tokens)
print(tags)
[('Tom', 'NNP'), ('ate', 'VBD'), ('an', 'DT'), ('apple', 'NN'),
('at', 'IN'), ('10:00', 'CD'), ('am', 'NN')]
text = "I went to the school early morning."
tokens = word_tokenize(text)
tag = nltk.pos_tag(tokens)
print(tokens)
print(tag)
['I', 'went', 'to', 'the', 'school', 'early', 'morning', '.']
[('I', 'PRP'), ('went', 'VBD'), ('to', 'TO'), ('the', 'DT'),
('school', 'NN'), ('early', 'JJ'), ('morning', 'NN'), ('.', '.')]
from nltk.tokenize import word_tokenize
from nltk.tag import pos_tag
ex = 'European authorities fined Google a record $5.1 billion on Wednesday'
def preprocess(sent):
sent = word_tokenize(sent)
sent = pos_tag(sent)
return sent
print(preprocess(ex))
[('European', 'JJ'), ('authorities', 'NNS'), ('fined', 'VBD'),
('Google', 'NNP'), ('a', 'DT'), ('record', 'NN'), ('$', '$'),
('5.1', 'CD'), ('billion', 'CD'), ('on', 'IN'), ('Wednesday', 'NNP')]
| Symbol | Meaning | Example |
|---|---|---|
<DT> | Match determiner tag | "the", "a", "an" |
<JJ>* | Zero or more adjectives | Optional: "big", "red" |
<NN>+ | One or more nouns | "school", "apple book" |
? | Optional element | <DT>? = optional determiner |
{} | Chunk pattern | NP: {<DT>?<JJ>*<NN>} |
import nltk
text = "The boy ate the apple quickly"
tokens = nltk.word_tokenize(text)
tag = nltk.pos_tag(tokens)
grammar = "NP: {<DT>?<JJ>*<NN>}"
cp = nltk.RegexpParser(grammar)
result = cp.parse(tag)
print(result)
(S (NP The/DT boy/NN) ate/VB (NP the/DT apple/NN) quickly/RB)
import nltk
from nltk import word_tokenize, pos_tag, RegexpParser
sentence = "Tom ate an apple at 10:00 am."
tokens = word_tokenize(sentence)
tagged = pos_tag(tokens)
grammar = r"""
NP: {<DT>?<JJ>*<NN|NNP|NNS>+}
VP: {<VB.*><NP|PP|CLAUSE>*}
"""
parser = RegexpParser(grammar)
tree = parser.parse(tagged)
print(tree)
(S
(NP Tom/NNP)
(VP ate/VBD (NP an/DT apple/NN))
at/IN 10:00/CD am/NN ./.)
result.draw() method visualizes the tree in a window.
import nltk
sentence = [("the", "DT"), ("little", "JJ"), ("yellow", "JJ"),
("dog", "NN"), ("barked", "VBD"), ("at", "IN"),
("the", "DT"), ("cat", "NN")]
grammar = "NP: {<DT>?<JJ>*<NN>}"
cp = nltk.RegexpParser(grammar)
result = cp.parse(sentence)
print(result)
result.draw() # Opens visual tree window
(S
(NP the/DT little/JJ yellow/JJ dog/NN)
barked/VBD
at/IN
(NP the/DT cat/NN))
| Term | Description |
|---|---|
| Head | The governing word in a relationship (usually the verb) |
| Dependent | A word that modifies or relates to the head |
SBJ | Subject dependency label |
NMOD | Noun modifier dependency label |
nsubj | Nominal subject (modern parsers) |
dobj | Direct object dependency label |
import nltk
groucho_dep_grammar = nltk.DependencyGrammar.fromstring("""
'shot' -> 'I' | 'elephant' | 'in'
'elephant' -> 'an' | 'in'
'in' -> 'pajamas'
'pajamas' -> 'my'
""")
print(groucho_dep_grammar)
Dependency grammar with 7 productions
'shot' -> 'I'
'shot' -> 'elephant'
'shot' -> 'in'
'elephant' -> 'an'
'elephant' -> 'in'
'in' -> 'pajamas'
'pajamas' -> 'my'
Named Entity Recognition (NER)
| Tag | Entity Type | Example |
|---|---|---|
| PERSON | Person names | "Robert Downey Jr.", "Chris Evans" |
| ORGANIZATION | Organizations, companies | "IBM", "Marvel Studios" |
| GPE | Geopolitical entity (location) | "Boston", "Jordan", "USA" |
| geo | Geographical entity | "Mississippi River", "Alps" |
| tim | Time indicator | "Wednesday", "2020", "10:00 am" |
| art | Artifact | "iPhone", "Boeing 747" |
| eve | Event | "Olympics", "World Cup" |
| nat | Natural phenomenon | "hurricane", "earthquake" |
import nltk
from nltk.tokenize import word_tokenize
from nltk import word_tokenize, pos_tag, ne_chunk
nltk.download('words')
nltk.download('punkt_tab')
nltk.download('averaged_perceptron_tagger_eng')
nltk.download('maxent_ne_chunker_tab') # NER model
nltk.download('wordnet')
nltk.download('stopwords')
"boston" would likely NOT be detected as a location, but "Boston" will be detected as (GPE Boston).
ne_chunk() requires POS-tagged input. It uses the POS tags to determine which words are proper nouns (NNP) before classifying them as named entities.
from nltk import word_tokenize, pos_tag, ne_chunk
input_str = 'Bill works for IBM so he went to Boston for a conference in 2020.'
print(ne_chunk(pos_tag(word_tokenize(input_str))))
(S
(PERSON Bill/NNP)
works/VBZ
for/IN
(ORGANIZATION IBM/NNP)
so/IN he/PRP went/VBD to/TO
(GPE Boston/NNP)
for/IN a/DT conference/NN in/IN 2020/CD ./.)
from nltk import word_tokenize, pos_tag, ne_chunk
text = "I live in Jordan"
tokens = word_tokenize(text) # Step 1
tagged = pos_tag(tokens) # Step 2
entities = ne_chunk(tagged) # Step 3
print(entities)
Tokenization: ['I', 'live', 'in', 'Jordan']
POS: [('I', 'PRP'), ('live', 'VBP'), ('in', 'IN'), ('Jordan', 'NNP')]
(S I/PRP live/VBP in/IN (GPE Jordan/NNP))
Complete NLP Levels Reference — Exam Preparation
| Level | Task | Library / Module | NLTK Downloads | Output |
|---|---|---|---|---|
| 1 Lexical | Tokenizationword_tokenize sent_tokenize |
nltk.tokenize |
punkt_tab |
List of tokens |
| 1 Lexical | Stop Words Removal | nltk.corpus stopwords |
stopwords |
Filtered token list |
| 1 Lexical | Lowercasing | Python .lower() |
None required |
Lowercase tokens |
| 2 Morphological | StemmingPorter / Lancaster Snowball |
nltk.stem |
None (built-in rules) |
Stemmed root forms |
| 2 Morphological | LemmatizationWordNetLemmatizer | nltk.stem |
wordnetomw-1.4 |
Real dictionary words |
| 3 Syntactic | POS Taggingpos_tag() | nltk |
punkt_tabaveraged_perceptron_tagger_eng |
|
| 3 Syntactic | ChunkingRegexpParser | nltk |
punkt_tabaveraged_perceptron_tagger_eng |
Phrase chunks (NP, VP) |
| 3 Syntactic | Constituency ParsingRegexpParser + .draw() | nltk |
punkt_tabaveraged_perceptron_tagger_eng |
Full parse trees |
| 3 Syntactic | Dependency ParsingDependencyGrammar | nltk |
None required |
Head→dependent graph |
| 4 Semantic | Named Entity Recognitionne_chunk() | nltk |
wordspunkt_tabaveraged_perceptron_tagger_engmaxent_ne_chunker_tab |
PERSON · ORG · GPE |
word_tokenize · stopwordsPorterStemmer · WordNetLemmatizerpos_tag() · averaged_perceptron_taggerRegexpParser · DependencyGrammarne_chunk() · maxent_ne_chunker