spaCy & WordNet
2025-11-07
import spacy
import pandas as pd
# Load English model
nlp = spacy.load("en_core_web_sm")
text = "Dr. Byrd's students can't wait to analyze PIE roots!"
doc = nlp(text)
# Create list of dicts, one per token
data = []
for t in doc:
data.append({
"text": t.text,
"lemma": t.lemma_,
"POS": t.pos_,
"tag": t.tag_,
"stop": t.is_stop,
"is_punct": t.is_punct
})
# Make DataFrame
df = pd.DataFrame(data)
print(df)import spacy
import pandas as pd
# Load English model
nlp = spacy.load("en_core_web_sm")
text2 = "President Pitzer, Mr. Vice President, Governor Connally, ladies and gentlemen: I am delighted to be here today. We meet in an hour of change and challenge."
doc2 = nlp(text2)
[s.text for s in doc2.sents]import spacy
from nltk.corpus import wordnet as wn
from nltk.corpus.reader.wordnet import NOUN, VERB, ADJ, ADV
# Load spaCy
nlp = spacy.load("en_core_web_sm")
# Sentence with both noun and verb "bear"
text = "The bears bear their burdens bravely."
doc = nlp(text)
# Map spaCy POS tags to WordNet POS tags -- this is a **function**, we'll get to these soon
def get_wordnet_pos(spacy_pos):
if spacy_pos.startswith("N"):
return NOUN
elif spacy_pos.startswith("V"):
return VERB
elif spacy_pos.startswith("J"):
return ADJ
elif spacy_pos.startswith("R"):
return ADV
return None
# Loop through tokens and look up WordNet entries
for token in doc:
wn_pos = get_wordnet_pos(token.tag_)
lemma = token.lemma_.lower()
if wn_pos and not token.is_stop and not token.is_punct:
synsets = wn.synsets(lemma, pos=wn_pos)
print(f"\n{token.text.upper()} ({token.pos_}) → lemma: {lemma}")
for s in synsets[:3]: # show just the first 3 senses
print(f" - {s.definition()} [examples: {s.examples()}]")Copy the below string, and after filtering out stopwords and non-words
identify the top 10 most frequent words.
select the first sentence using spaCy’s attitude .sents
parse each word by meaning using WordNet.
getty = "Four score and seven years ago our fathers brought forth on this continent, a new nation, conceived in Liberty, and dedicated to the proposition that all men are created equal.Now we are engaged in a great civil war, testing whether that nation, or any nation so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.But, in a larger sense, we can not dedicate—we can not consecrate—we can not hallow—this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us—that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain—that this nation, under God, shall have a new birth of freedom—and that government of the people, by the people, for the people, shall not perish from the earth."antonyms
hypernyms
hyponyms
meronyms
holonyms
entailments
def get_antonyms(word): # this is also a function
antonyms = set() # A set is like a list, but prevents duplicates
for syn in wn.synsets(word):
for lemma in syn.lemmas(): # analyzes each lemma associated with the token
for ant in lemma.antonyms():
antonyms.add(ant.name())
return list(antonyms)
get_antonyms("slow")get_antonyms() function.import spacy
from spacy.tokens import Token
from nltk.corpus import wordnet as wn
nlp = spacy.load("en_core_web_sm")
# Register a getter-based extension
def get_synsets(token):
# You can filter by POS if you want, e.g., pos=wn.NOUN for nouns
return wn.synsets(token.lemma_.lower())
Token.set_extension("synsets", getter=get_synsets, force=True)
doc = nlp("dog")
token = doc[0]
word_synsets = token._.synsets # now this works
for synset in word_synsets:
hypernym_names = [h.name() for h in synset.hypernyms()]
hyponym_names = [h.name() for h in synset.hyponyms()]
print(f"\nSense: {synset.name()}")
print(f" Hypernyms: {hypernym_names}")
print(f" Hyponyms: {hyponym_names}")import spacy
from spacy.tokens import Token
from nltk.corpus import wordnet as wn
# Creating a function to "get" synsets
def get_synsets(token):
# You can filter by POS if you want, e.g., pos=wn.NOUN for nouns
return wn.synsets(token.lemma_.lower())
Token.set_extension("synsets", getter=get_synsets, force=True)
doc = nlp("dog")
token = doc[0]
word_synsets = token._.synsets # now this works
for synset in word_synsets:
hypernym_names = [h.name() for h in synset.hypernyms()]
hyponym_names = [h.name() for h in synset.hyponyms()]
mero_names = [h.name() for h in synset.part_meronyms()]
holo_names = [h.name() for h in synset.part_holonyms()]
print(f"\nSense: {synset.name()}")
print(f" Hypernyms: {hypernym_names}")
print(f" Hyponyms: {hyponym_names}")
print(f" Part Meronyms: {mero_names}")
print(f" Part Holonyms: {holo_names}")import spacy
from spacy.tokens import Token
from nltk.corpus import wordnet as wn
# Creating a function to "get" synsets
def get_synsets(token):
# You can filter by POS if you want, e.g., pos=wn.NOUN for nouns
return wn.synsets(token.lemma_.lower())
Token.set_extension("synsets", getter=get_synsets, force=True)
doc = nlp("dog")
token = doc[0]
word_synsets = token._.synsets # now this works
for synset in word_synsets:
hypernym_names = [h.name() for h in synset.hypernyms()]
hyponym_names = [h.name() for h in synset.hyponyms()]
mero_names = [h.name() for h in synset.part_meronyms()]
holo_names = [h.name() for h in synset.part_holonyms()]
ent_names = [h.name() for h in synset.entailments()]
print(f"\nSense: {synset.name()}")
print(f" Hypernyms: {hypernym_names}")
print(f" Hyponyms: {hyponym_names}")
print(f" Part Meronyms: {mero_names}")
print(f" Part Holonyms: {holo_names}")
print(f" Entailments: {ent_names}")Key Terms
\(wup\_similarity(s_1, s_2) = \frac{2 \times depth(LCS)}{depth(s_1) + depth(s_2)}\)
dog.n.01 and cat.n.01; these are s\(_1\), s\(_2\), respectively\(wup\_similarity(s_1, s_2) = \frac{2 \times depth(LCS)}{depth(s_1) + depth(s_2)}\)
Interpretation
1.0 → identical meaning0.0 → completely unrelated\(wup\_similarity(dog, cat) = \frac{2 \times 7}{8 + 8} = \frac{14}{16} = 0.875\)
import spacy
from spacy.matcher import PhraseMatcher
from nltk.corpus import wordnet as wn
nlp = spacy.load("en_core_web_sm")
# WordNet helpers (via NLTK) – returns only verb synsets
def verb_senses(word):
return wn.synsets(word, pos='v') # verb synsets only
# Collects all (recursive) hyponyms for a verb synset (troponyms in WN terms).
# This function recursively collects all *hyponyms* (a.k.a. “troponyms” for verbs)
# of a given synset. A hyponym is a more *specific* instance of an action.
# Example: the verb “attack.v.01” has hyponyms like “bomb.v.01”, “invade.v.01”, etc.
def all_verb_hyponyms(root):
seen, stack = set(), [root]
while stack:
cur = stack.pop()
if cur in seen:
continue
seen.add(cur)
# For verbs, .hyponyms() are the troponyms
stack.extend(cur.hyponyms())
return {s for s in seen if s.pos() == 'v'}
# This function extracts lemma names (the “canonical” word forms)
# from a set of synsets, e.g. 'strike.v.01' → ['strike', 'hit', 'smite', ...].
# Optionally filters out multiword expressions like "shoot_down".
def lemmas_from_synsets(synsets, keep_multiword=False):
out = set()
for s in synsets:
for lem in s.lemmas():
name = lem.name().lower()
if not keep_multiword and "_" in name:
continue
out.add(name.replace("_", " "))
return out
# Build a violence lexicon from WordNet using a few intuitive seeds
seed_verbs = ["attack", "assault", "hit", "strike", "punch", "kick", "stab", "shoot", "beat"]
base_synsets = []
for w in seed_verbs:
ss = verb_senses(w)
if ss:
# take the most “central” sense by picking the one with most hyponyms
ss_scored = sorted(ss, key=lambda s: len(s.hyponyms()), reverse=True)
base_synsets.append(ss_scored[0])
# expand via hyponyms (troponyms)
expanded = set()
for s in base_synsets:
expanded |= all_verb_hyponyms(s)
# collect lemmas (single-token by default)
violent_verb_lemmas = sorted(lemmas_from_synsets(expanded, keep_multiword=False) | set(seed_verbs))
print(f"{len(violent_verb_lemmas)} violent verb lemmas (sample):", violent_verb_lemmas[:25])
# 4) spaCy PhraseMatcher by lemma — IMPORTANT: run full pipeline on patterns
matcher = PhraseMatcher(nlp.vocab, attr="LEMMA")
patterns = list(nlp.pipe(violent_verb_lemmas)) # not make_doc: we need lemmas
matcher.add("VIOLENCE", patterns)violent_vs = ['assail', 'assault', 'atom-bomb', 'atomise', 'atomize', 'attack', 'backbite', 'backhand', 'bait', 'bastinado', 'bat', 'batter', 'bayonet', 'beak', 'beat', 'beef', 'beetle', 'beleaguer', 'bellyache', 'bemoan', 'beset', 'besiege', 'best', 'better', 'bewail', 'birdie', 'bitch', 'blast', 'bleat', 'blindside', 'blitz', 'blockade', 'bogey', 'bomb', 'bombard', 'bounce', 'break', 'buffet', 'bulldog', 'bunker', 'bunt', 'bust', 'butt', 'cannon', 'cannonade', 'carom', 'carry', 'charge', 'cheat', 'checkmate', 'chicane', 'chip', 'chop', 'chouse', 'circumvent', 'clap', 'clobber', 'clout', 'coldcock', 'complain', 'connect', 'counterattack', 'counterstrike', 'crab', 'cream', 'croak', 'croquet', 'crump', 'crush', 'cuff', 'dab', 'deck', 'declaim', 'deplore', 'desecrate', 'dishonor', 'dishonour', 'dive-bomb', 'double', 'down', 'dribble', 'drive', 'drub', 'dump', 'dunk', 'eagle', 'ebb', 'eliminate', 'exceed', 'firebomb', 'floor', 'fly', 'foul', 'full', 'gang-rape', 'gas', 'glide-bomb', 'gnarl', 'gripe', 'grizzle', 'grouch', 'ground', 'grouse', 'grumble', 'hammer', 'headbutt', 'heel', 'hen-peck', 'hew', 'hit', 'hole', 'holler', 'hook', 'hydrogen-bomb', 'immobilise', 'immobilize', 'infest', 'invade', 'inveigh', 'jab', 'jockey', 'jump', 'kick', 'kill', 'knap', 'knife', 'knock', 'knuckle', 'kvetch', 'lament', 'lash', 'lick', 'loft', 'master', 'mate', 'molest', 'murmur', 'mutter', 'nag', 'nuke', 'occupy', 'out-herod', 'outbrave', 'outcry', 'outdo', 'outdraw', 'outfight', 'outflank', 'outfox', 'outgeneral', 'outgo', 'outgrow', 'outmaneuver', 'outmanoeuvre', 'outmarch', 'outmatch', 'outpace', 'outperform', 'outplay', 'outpoint', 'outrage', 'outrange', 'outroar', 'outsail', 'outscore', 'outsell', 'outshine', 'outshout', 'outsmart', 'outstrip', 'outwear', 'outweigh', 'outwit', 'overcome', 'overmaster', 'overpower', 'overreach', 'overrun', 'overwhelm', 'paste', 'pat', 'pattern-bomb', 'peck', 'pelt', 'pepper', 'percuss', 'pick', 'pip', 'pitch', 'plain', 'play', 'plug', 'poniard', 'pop', 'profane', 'protest', 'pull', 'punch', 'putt', 'quetch', 'racket', 'raid', 'rail', 'rap', 'rape', 'ravish', 'reassail', 'repine', 'report', 'retaliate', 'rout', 'rush', 'savage', 'sclaff', 'scold', 'scoop', 'screw', 'set', 'shaft', 'shame', 'shank', 'shell', 'shoot', 'sic', 'sideswipe', 'single', 'skip-bomb', 'slam-dunk', 'slap', 'sledge', 'sledgehammer', 'slice', 'smash', 'snag', 'snap', 'snick', 'spread-eagle', 'spreadeagle', 'spur', 'squawk', 'stab', 'steamroll', 'steamroller', 'storm', 'strafe', 'strike', 'stroke', 'subdue', 'submarine', 'surmount', 'surpass', 'surprise', 'surround', 'tap', 'teargas', 'thrash', 'thresh', 'tip', 'toe', 'top', 'torpedo', 'triple', 'trounce', 'trump', 'undercut', 'upstage', 'urticate', 'vanquish', 'violate', 'volley', 'whang', 'whine', 'whip', 'whomp', 'worst', 'yammer', 'yawp', 'zap']import spacy
from spacy.matcher import PhraseMatcher
nlp = spacy.load("en_core_web_sm")
patterns = [nlp(v) for v in violent_verb_lemmas]
matcher = PhraseMatcher(nlp.vocab, attr="LEMMA")
doc = nlp("They punched, kicked, and attacked the intruder before fleeing.")
matcher.add("VIOLENCE", patterns)
[(doc[s:e].text, doc[s:e].lemma_) for _, s, e in matcher(doc)]