0% found this document useful (0 votes)
9 views14 pages

NLP Lab Experiments: Python Programs

The document outlines a series of 10 experiments in Natural Language Processing (NLP) using Python, covering topics such as text preprocessing, language models, POS tagging, RNNs, parsing, word sense disambiguation, and information extraction. Each experiment includes an aim, runnable code, and expected outcomes, with recommended environments for execution. Key libraries used include NLTK, PyTorch, and spaCy.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views14 pages

NLP Lab Experiments: Python Programs

The document outlines a series of 10 experiments in Natural Language Processing (NLP) using Python, covering topics such as text preprocessing, language models, POS tagging, RNNs, parsing, word sense disambiguation, and information extraction. Each experiment includes an aim, runnable code, and expected outcomes, with recommended environments for execution. Key libraries used include NLTK, PyTorch, and spaCy.
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

NATURAL LANGUAGE PROCESSING (NLP) LAB

Experiments 1 to 10 - Programs and Outcomes

This document contains concise, runnable Python programs for common NLP lab experiments. Each experiment
includes Aim, Program, and Outcome (expected output/behavior). Recommended environment: Google Colab or a
Python 3.10+ setup.

Section Topic

1 Preprocessing + Edit Distance


2 N-gram Language Models + Smoothing + Perplexity
3 HMM POS Tagger + Viterbi
4 RNN Next-Word Prediction (Embeddings)
5 CFG + Top-down & Bottom-up Parsing
6 PCFG + Dependency Parsing
7 WSD (Decision Tree & Lesk)
8 Information Extraction (NER + Relations)
9 ASR + TTS (Deep Learning Pipelines)
10 Neural Machine Translation (Seq2Seq + Attention)
Experiment 1: Text Preprocessing and Edit Distance
Aim: Implement tokenization, case folding, stemming, lemmatization, and compute edit distance between two
strings.

Setup / Libraries: Python, NLTK (punkt, wordnet).

Program:
import re
import nltk
[Link]("punkt")
[Link]("wordnet")
[Link]("omw-1.4")

from [Link] import word_tokenize


from [Link] import PorterStemmer, WordNetLemmatizer

def preprocess(text):
text = [Link]() # case folding
tokens = word_tokenize(text) # tokenization
tokens = [t for t in tokens if [Link](r"^[a-z]+$", t)] # keep only words
return tokens

def stem(tokens):
ps = PorterStemmer()
return [[Link](t) for t in tokens]

def lemmatize(tokens):
lem = WordNetLemmatizer()
return [[Link](t) for t in tokens]

def edit_distance(a, b):


# Levenshtein distance (DP)
m, n = len(a), len(b)
dp = [[0]*(n+1) for _ in range(m+1)]
for i in range(m+1): dp[i][0] = i
for j in range(n+1): dp[0][j] = j
for i in range(1, m+1):
for j in range(1, n+1):
cost = 0 if a[i-1] == b[j-1] else 1
dp[i][j] = min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + cost)
return dp[m][n]

text = "NLP is Amazing! Tokenization, stemming & lemmatization are useful."


tokens = preprocess(text)

print("Tokens:", tokens)
print("Stemmed:", stem(tokens))
print("Lemmatized:", lemmatize(tokens))
print("Edit distance (kitten, sitting):", edit_distance("kitten", "sitting"))

Outcome: Shows tokens, stems, lemmas for the input text; edit distance for 'kitten' and 'sitting' is 3.
Experiment 2: Unigram, Bigram, Trigram Language Models
with Smoothing and Perplexity
Aim: Build unigram/bigram/trigram LMs, apply Laplace (add-1) smoothing, and compute perplexity for a test
sentence.

Setup / Libraries: Python standard library only.

Program:
import math
from collections import Counter

def ngrams(tokens, n):


return [tuple(tokens[i:i+n]) for i in range(len(tokens)-n+1)]

def train_ngram(tokens, n):


ng = Counter(ngrams(tokens, n))
ctx = Counter(ngrams(tokens, n-1)) if n > 1 else None
vocab = sorted(set(tokens))
return ng, ctx, vocab

def prob_add1(ngram, ng_counts, ctx_counts, vocab):


V = len(vocab)
if len(ngram) == 1:
return (ng_counts[ngram] + 1) / (sum(ng_counts.values()) + V)
context = ngram[:-1]
return (ng_counts[ngram] + 1) / (ctx_counts[context] + V)

def perplexity(test_tokens, n, ng_counts, ctx_counts, vocab):


test_ng = ngrams(test_tokens, n)
logp = 0.0
for g in test_ng:
p = prob_add1(g, ng_counts, ctx_counts, vocab)
logp += [Link](p)
return [Link](-logp / len(test_ng))

train_text = "i love nlp and i love machine learning"


train_tokens = train_text.split()

test_text = "i love learning"


test_tokens = test_text.split()

for n in [1, 2, 3]:


ng, ctx, vocab = train_ngram(train_tokens, n)
ppl = perplexity(test_tokens, n, ng, ctx, vocab)
print(f"{n}-gram perplexity for '{test_text}': {ppl:.4f}")

Outcome: Prints perplexity values for 1-gram, 2-gram, 3-gram models. Lower perplexity means better prediction of
the test sentence.
Experiment 3: POS Tagger using HMM and Viterbi Decoding
Aim: Construct a POS tagger using an HMM and decode the most probable tag sequence using the Viterbi
algorithm.

Setup / Libraries: Python standard library only.

Program:
import math
from collections import Counter

train_sents = [
[("time","NN"), ("flies","VBZ"), ("like","IN"), ("an","DT"), ("arrow","NN")],
[("fruit","NN"), ("flies","NNS"), ("like","IN"), ("a","DT"), ("banana","NN")],
]

def train_hmm(tagged_sents):
tag_counts = Counter()
emit = Counter()
trans = Counter()
start = Counter()
for sent in tagged_sents:
start[sent[0][1]] += 1
prev_tag = None
for word, tag in sent:
tag_counts[tag] += 1
emit[(tag, word)] += 1
if prev_tag is not None:
trans[(prev_tag, tag)] += 1
prev_tag = tag
tags = list(tag_counts.keys())
vocab = set(w for sent in tagged_sents for (w, _) in sent)
return tags, vocab, tag_counts, emit, trans, start

def viterbi(words, tags, vocab, tag_counts, emit, trans, start):


V = len(vocab) + 1
T = len(tags)
def log(x): return -1e9 if x == 0 else [Link](x)

dp = [{} for _ in range(len(words))]


back = [{} for _ in range(len(words))]

for tag in tags:


p_start = (start[tag] + 1) / (sum([Link]()) + T)
p_emit = (emit[(tag, words[0])] + 1) / (tag_counts[tag] + V)
dp[0][tag] = log(p_start) + log(p_emit)
back[0][tag] = None

for i in range(1, len(words)):


for tag in tags:
p_emit = (emit[(tag, words[i])] + 1) / (tag_counts[tag] + V)
best_prev, best_score = None, -1e18
for prev in tags:
p_trans = (trans[(prev, tag)] + 1) / (tag_counts[prev] + T)
score = dp[i-1][prev] + log(p_trans) + log(p_emit)
if score > best_score:
best_score, best_prev = score, prev
dp[i][tag] = best_score
back[i][tag] = best_prev

last = max(dp[-1], key=dp[-1].get)


seq, cur = [], last
for i in reversed(range(len(words))):
[Link](cur)
cur = back[i][cur]
return list(reversed(seq))

tags, vocab, tag_counts, emit, trans, start = train_hmm(train_sents)


sent = "time flies like a banana".split()
pred = viterbi(sent, tags, vocab, tag_counts, emit, trans, start)
print(list(zip(sent, pred)))

Outcome: Outputs word-tag pairs for the input sentence (the tag for 'flies' may be VBZ or NNS depending on
learned probabilities).
Experiment 4: RNN for Next-Word Prediction (with
Embeddings)
Aim: Implement an RNN architecture for next-word prediction using an embedding layer (can be initialized with
Word2Vec/GloVe).

Setup / Libraries: PyTorch (torch).

Program:
# Next-word prediction with a simple RNN language model (PyTorch)
# Colab setup: !pip -q install torch

import torch
import [Link] as nn

sentences = [
"i love nlp",
"i love deep learning",
"nlp is fun",
"deep learning is powerful"
]

tokens = [w for s in sentences for w in [Link]()]


vocab = sorted(set(tokens))
stoi = {w:i for i,w in enumerate(vocab)}
itos = {i:w for w,i in [Link]()}

pairs = []
for s in sentences:
w = [Link]()
for i in range(len(w)-1):
[Link]((w[i], w[i+1]))

X = [Link]([stoi[a] for a,_ in pairs])


Y = [Link]([stoi[b] for _,b in pairs])

class RNNLM([Link]):
def __init__(self, vocab_size, emb_dim=32, hidden=64):
super().__init__()
[Link] = [Link](vocab_size, emb_dim)
[Link] = [Link](emb_dim, hidden, batch_first=True)
[Link] = [Link](hidden, vocab_size)

def forward(self, x):


e = [Link](x).unsqueeze(1) # (B,1,emb)
out, _ = [Link](e) # (B,1,hid)
return [Link]([Link](1)) # (B,vocab)

model = RNNLM(len(vocab))
opt = [Link]([Link](), lr=0.01)
loss_fn = [Link]()

for epoch in range(200):


opt.zero_grad()
logits = model(X)
loss = loss_fn(logits, Y)
[Link]()
[Link]()

def predict_next(word, k=3):


with torch.no_grad():
x = [Link]([stoi[word]])
probs = [Link](model(x), dim=-1).squeeze()
top = [Link](probs, k)
return [(itos[int(i)], float(p)) for p,i in zip([Link], [Link])]

print("Next words for 'love':", predict_next("love"))


print("Next words for 'deep':", predict_next("deep"))
Outcome: Prints top predicted next words for input tokens (e.g., love -> nlp/deep/learning).

Notes: To use GloVe/Word2Vec: load vectors and copy them into [Link].
Experiment 5: Context-Free Grammar (CFG) and Parsing
(Top-down and Bottom-up)
Aim: Construct a CFG and apply top-down and bottom-up parsing algorithms for syntactic analysis.

Setup / Libraries: NLTK (CFG, parsers).

Program:
import nltk
from nltk import CFG
from [Link] import RecursiveDescentParser, ChartParser

grammar = [Link]('''
S -> NP VP
NP -> Det N | Det Adj N
VP -> V NP | V
Det -> 'a' | 'the'
Adj -> 'big' | 'small'
N -> 'cat' | 'dog'
V -> 'sees' | 'runs'
''')

sentence = "the big dog sees a cat".split()

topdown = RecursiveDescentParser(grammar) # Top-down


bottomup = ChartParser(grammar) # Bottom-up

print("Top-down parse trees:")


for tree in [Link](sentence):
print(tree)

print("\nBottom-up parse trees:")


for tree in [Link](sentence):
print(tree)

Outcome: Prints parse tree(s) for the given sentence using both parsing strategies.
Experiment 6: PCFG Statistical Parsing and Dependency
Parsing
Aim: Implement PCFG for statistical parsing and explore dependency parsing methods for syntactic analysis.

Setup / Libraries: NLTK (PCFG, ViterbiParser). spaCy optional for dependency parsing.

Program:
# PCFG (statistical parsing) + Dependency parsing example

# ----- PCFG with Viterbi parsing (NLTK) -----


from nltk import PCFG
from [Link] import ViterbiParser

pcfg = [Link]('''
S -> NP VP [1.0]
NP -> Det N [0.6] | Det Adj N [0.4]
VP -> V NP [0.7] | V [0.3]
Det -> 'the' [0.6] | 'a' [0.4]
Adj -> 'big' [0.5] | 'small' [0.5]
N -> 'dog' [0.5] | 'cat' [0.5]
V -> 'sees' [0.6] | 'runs' [0.4]
''')

parser = ViterbiParser(pcfg)
sent = "the dog sees a cat".split()

for tree in [Link](sent):


print(tree)
print("Tree probability:", [Link]())

# ----- Dependency parsing (spaCy) -----


# Colab setup:
# !pip -q install spacy
# !python -m spacy download en_core_web_sm
# import spacy
# nlp = [Link]("en_core_web_sm")
# doc = nlp("The dog sees a cat.")
# for token in doc:
# print([Link], token.dep_, "->", [Link])

Outcome: PCFG: prints most probable parse tree with probability. Dependency parsing: prints dependency arcs if
spaCy is installed.
Experiment 7: Word Sense Disambiguation (WSD):
Supervised and Unsupervised
Aim: Implement and compare Decision Tree classifier (supervised) and Lesk algorithm (unsupervised) for WSD.

Setup / Libraries: scikit-learn, NLTK (wordnet, punkt).

Program:
# Word Sense Disambiguation (WSD): Decision Tree (supervised) and Lesk (unsupervised)

from [Link] import DecisionTreeClassifier


from sklearn.feature_extraction.text import CountVectorizer

X_train = [
"I deposited money in the bank",
"The bank approved my loan",
"He sat on the river bank",
"Trees grew along the bank"
]
y_train = ["FIN", "FIN", "RIVER", "RIVER"]

vec = CountVectorizer()
Xv = vec.fit_transform(X_train)

clf = DecisionTreeClassifier()
[Link](Xv, y_train)

tests = [
"She went to the bank to withdraw cash",
"We walked along the bank of the river"
]
Xt = [Link](tests)
print("Decision Tree WSD:", list(zip(tests, [Link](Xt))))

import nltk
[Link]("wordnet")
[Link]("punkt")
from [Link] import lesk

s1 = "I went to the bank to deposit money".split()


s2 = "The fisherman sat on the bank".split()

sense1 = lesk(s1, "bank")


sense2 = lesk(s2, "bank")

print("Lesk sense (money):", sense1, "-", [Link]() if sense1 else None)


print("Lesk sense (river):", sense2, "-", [Link]() if sense2 else None)

Outcome: Decision Tree predicts FIN vs RIVER senses; Lesk outputs WordNet synset and definition for each
context.
Experiment 8: Information Extraction using NER and
Relation Extraction
Aim: Implement Information Extraction using Named Entity Recognition and Relation Extraction.

Setup / Libraries: spaCy (en_core_web_sm).

Program:
# Information Extraction: Named Entity Recognition (NER) + simple Relation Extraction
# Setup: !pip -q install spacy ; !python -m spacy download en_core_web_sm

import spacy
nlp = [Link]("en_core_web_sm")

text = "Sundar Pichai is the CEO of Google and he lives in the United States."
doc = nlp(text)

print("Named Entities:")
for ent in [Link]:
print([Link], ent.label_)

# Simple relation extraction: PERSON CEO_OF ORG


person = next(([Link] for e in [Link] if e.label_ == "PERSON"), None)
org = next(([Link] for e in [Link] if e.label_ == "ORG"), None)

if person and org and "CEO" in text:


print("Relation:", (person, "CEO_OF", org))

Outcome: Prints entities (PERSON, ORG, GPE, etc.) and a relation tuple such as (Sundar Pichai, CEO_OF,
Google).
Experiment 9: ASR and TTS Systems using Deep Learning
Aim: Construct ASR and TTS systems using deep learning techniques.

Setup / Libraries: transformers (Whisper), gTTS (quick TTS).

Program:
# ASR and TTS using deep learning pipelines (HuggingFace + gTTS)
# Recommended: Google Colab
# Setup:
# !pip -q install transformers torchaudio soundfile gtts

from transformers import pipeline

# ASR (Whisper)
asr = pipeline("automatic-speech-recognition", model="openai/whisper-small")
print("ASR pipeline loaded. Use: asr('[Link]')")

# Example:
# result = asr("[Link]")
# print("Transcription:", result["text"])

# TTS (quick demo)


from gtts import gTTS
text = "Hello, this is a text to speech demo."
tts = gTTS(text=text, lang="en")
[Link]("tts_demo.mp3")
print("Saved tts_demo.mp3")

Outcome: ASR: returns transcribed text from an audio file. TTS: generates an mp3 file with synthesized speech.
Experiment 10: Neural Machine Translation (Seq2Seq with
Attention)
Aim: Build a Seq2Seq NMT model with attention and translate simple sentences.

Setup / Libraries: PyTorch (torch).

Program:
# Neural Machine Translation (NMT): Seq2Seq with Attention (toy example in PyTorch)

import torch
import [Link] as nn
import [Link] as optim

pairs = [
("i am happy", "mai khush hu"),
("i am sad", "mai udaas hu"),
("he is happy", "vah khush hai"),
("he is sad", "vah udaas hai"),
]

def tok(s): return [Link]()

src_vocab = sorted(set(w for a,_ in pairs for w in tok(a)))


tgt_vocab = sorted(set(w for _,b in pairs for w in tok(b)))

src_vocab = ["<pad>","<sos>","<eos>"] + src_vocab


tgt_vocab = ["<pad>","<sos>","<eos>"] + tgt_vocab

src_stoi = {w:i for i,w in enumerate(src_vocab)}


tgt_stoi = {w:i for i,w in enumerate(tgt_vocab)}
tgt_itos = {i:w for w,i in tgt_stoi.items()}

def encode(sent, stoi):


ids = [stoi["<sos>"]] + [stoi[w] for w in tok(sent)] + [stoi["<eos>"]]
return [Link](ids, dtype=[Link])

data = [(encode(a,src_stoi), encode(b,tgt_stoi)) for a,b in pairs]

class Encoder([Link]):
def __init__(self, V, emb=32, hid=64):
super().__init__()
[Link] = [Link](V, emb)
[Link] = [Link](emb, hid, batch_first=True)
def forward(self, x):
e = [Link]([Link](0))
out, h = [Link](e)
return out, h

class Attention([Link]):
def __init__(self, hid=64):
super().__init__()
self.W = [Link](hid*2, hid)
self.v = [Link](hid, 1, bias=False)
def forward(self, enc_out, dec_h):
src_len = enc_out.size(1)
dec_rep = dec_h.repeat(1, src_len, 1)
energy = [Link](self.W([Link]([enc_out, dec_rep], dim=-1)))
scores = self.v(energy).squeeze(-1)
attn = [Link](scores, dim=-1)
ctx = [Link]([Link](1), enc_out)
return ctx, attn

class Decoder([Link]):
def __init__(self, V, emb=32, hid=64):
super().__init__()
[Link] = [Link](V, emb)
[Link] = Attention(hid)
[Link] = [Link](emb + hid, hid, batch_first=True)
[Link] = [Link](hid, V)
def forward(self, y_prev, h, enc_out):
yemb = [Link](y_prev).unsqueeze(0).unsqueeze(1)
ctx, _ = [Link](enc_out, [Link](1,0,2))
rnn_in = [Link]([yemb, ctx], dim=-1)
out, h_new = [Link](rnn_in, h)
logits = [Link]([Link](1))
return logits, h_new

enc_model = Encoder(len(src_vocab))
dec_model = Decoder(len(tgt_vocab))

opt = [Link](list(enc_model.parameters()) + list(dec_model.parameters()), lr=0.01)


loss_fn = [Link]()

# train (toy)
for epoch in range(300):
for x, y in data:
opt.zero_grad()
enc_out, h = enc_model(x)
loss = 0.0
for t in range(1, len(y)):
logits, h = dec_model(y[t-1], h, enc_out)
loss += loss_fn(logits, y[t].unsqueeze(0))
[Link]()
[Link]()

def translate(src_sentence, max_len=10):


x = encode(src_sentence, src_stoi)
enc_out, h = enc_model(x)
y_prev = [Link](tgt_stoi["<sos>"])
out_words = []
for _ in range(max_len):
logits, h = dec_model(y_prev, h, enc_out)
y_prev = [Link](logits, dim=-1).squeeze(0)
w = tgt_itos[int(y_prev)]
if w == "<eos>":
break
out_words.append(w)
return " ".join(out_words)

print("i am happy ->", translate("i am happy"))


print("he is sad ->", translate("he is sad"))

Outcome: After toy training, prints translations like 'i am happy -> mai khush hu'.

Notes: For real tasks: train on parallel corpora and evaluate using BLEU.

You might also like