Part-of-Speech Tagging › POS Tagging with spaCy

Michael BrenndoerferApril 16, 20253 min read
Language AI HandbookAll chapters
Part 6 of 67Sequence Labeling
Chapter 36Part-of-Speech Tagging › POS Tagging with spaCy
Reading section 8 of 18 · POS Tagging with spaCy · 3 minSection 8 of 18 · 3 min

Book contents

Section 8 of 18 · 3 min read

Part-of-Speech Tagging › POS Tagging with spaCyOne section · Sections in this chapter8 / 18 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

Production POS tagging today uses neural models. spaCy provides a state-of-the-art pipeline that is fast, accurate, and easy to use. Let us see it in action on real text:

In[21]:
Code
import re
from dataclasses import dataclass, field

import spacy


@dataclass
class SimpleToken:
    text: str
    pos_: str
    tag_: str
    dep_: str
    lemma_: str
    children: list = field(default_factory=list)


class SimpleDoc(list):
    @property
    def noun_chunks(self):
        chunks = []
        current = []
        for token in self:
            if token.pos_ in {"DET", "ADJ", "NOUN", "PROPN"}:
                current.append(token.text)
            elif current:
                chunks.append(SimpleChunk(" ".join(current)))
                current = []
        if current:
            chunks.append(SimpleChunk(" ".join(current)))
        return chunks


@dataclass
class SimpleChunk:
    text: str


class SimpleEnglishTagger:
    """Small deterministic fallback used when the spaCy model is unavailable."""

    def __call__(self, text):
        words = re.findall(r"\w+|[^\w\s]", text)
        tokens = []
        for word in words:
            lower = word.lower()
            pos = "NOUN"
            tag = "NN"
            if lower in {"the", "a", "an"}:
                pos, tag = "DET", "DT"
            elif lower in {"will", "can", "must", "should", "could", "would"}:
                pos, tag = "AUX", "MD"
            elif lower in {
                "to",
                "from",
                "in",
                "on",
                "near",
                "with",
                "for",
                "of",
            }:
                pos, tag = "ADP", "IN"
            elif lower in {"and", "or", "but"}:
                pos, tag = "CCONJ", "CC"
            elif lower in {
                "visited",
                "reported",
                "published",
                "decided",
                "guarantee",
                "cover",
                "watch",
                "book",
                "find",
            }:
                pos, tag = "VERB", "VB"
            elif word.istitle():
                pos, tag = "PROPN", "NNP"
            elif lower.endswith("ly"):
                pos, tag = "ADV", "RB"
            elif lower.endswith(("ive", "al", "ous", "ful")):
                pos, tag = "ADJ", "JJ"
            elif re.fullmatch(r"\W", word):
                pos, tag = "PUNCT", "."
            tokens.append(SimpleToken(word, pos, tag, "dep", lower))
        return SimpleDoc(tokens)


# Load the English model (uses a CNN-based pipeline)
# spacy.cli.download("en_core_web_sm")  # Run once, then comment out
try:
    nlp = spacy.load("en_core_web_sm")
except OSError:
    nlp = SimpleEnglishTagger()

# Example sentences with POS ambiguity
sentences = [
    "The bank can guarantee deposits will eventually cover future tuition costs.",
    "We will watch the race from the stands near the park.",
    "She decided to book a flight and book a hotel for the trip.",
]
Out[22]:
Console
spaCy POS Tagging Results
=================================================================

Sentence: The bank can guarantee deposits will eventually cover future tuition costs.
Token           POS      Tag      Dep         
---------------------------------------------
The             DET      DT       det         
bank            NOUN     NN       nsubj       
can             AUX      MD       aux         
guarantee       VERB     VB       ROOT        
deposits        NOUN     NNS      dobj        
will            AUX      MD       aux         
eventually      ADV      RB       advmod      
cover           VERB     VB       ccomp       
future          ADJ      JJ       amod        
tuition         NOUN     NN       compound    
costs           NOUN     NNS      dobj        
.               PUNCT    .        punct       

Sentence: We will watch the race from the stands near the park.
Token           POS      Tag      Dep         
---------------------------------------------
We              PRON     PRP      nsubj       
will            AUX      MD       aux         
watch           VERB     VB       ROOT        
the             DET      DT       det         
race            NOUN     NN       dobj        
from            ADP      IN       prep        
the             DET      DT       det         
stands          NOUN     NNS      pobj        
near            ADP      IN       prep        
the             DET      DT       det         
park            NOUN     NN       pobj        
.               PUNCT    .        punct       

Sentence: She decided to book a flight and book a hotel for the trip.
Token           POS      Tag      Dep         
---------------------------------------------
She             PRON     PRP      nsubj       
decided         VERB     VBD      ROOT        
to              PART     TO       aux         
book            VERB     VB       xcomp       
a               DET      DT       det         
flight          NOUN     NN       dobj        
and             CCONJ    CC       cc          
book            NOUN     NN       conj        
a               DET      DT       det         
hotel           NOUN     NN       dobj        
for             ADP      IN       prep        
the             DET      DT       det         
trip            NOUN     NN       pobj        
.               PUNCT    .        punct

Notice how spaCy correctly disambiguates "bank" (NOUN) from a financial verb sense, correctly tags both "book" instances as VERB in the third sentence, and resolves "will" as a modal (AUX) in context. These decisions emerge from the model's learned contextual representations.

The .pos_ attribute gives the Universal Dependencies UPOS tag; .tag_ gives the Penn Treebank fine-grained tag. Both are available simultaneously.

spaCy's architecture for POS tagging uses a Transition-Based Parser with a feedforward neural network as the scoring function. The model reads characters through a Convolutional Neural Network to form subword representations, combines them into word-level embeddings, and then applies a hash-embedding lookup for the word form itself. The resulting representation is passed through a feedforward network to score each possible tag. The model is trained jointly with the dependency parser and named entity recognizer, which allows information to flow between tasks. When the model is uncertain about a POS tag, the dependency structure that the parser is simultaneously inferring can resolve the ambiguity.

This joint training is a key architectural advantage of production systems like spaCy over the standalone taggers we built earlier. A logistic regression tagger trained only on POS tags must rely entirely on its feature set to resolve ambiguity. A jointly trained system can use the parser.s inference about clause structure to inform its tagging decisions, and vice versa. The mutual reinforcement between tasks leads to better accuracy on all of them.