nlpkit14 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nlpkit14-0.3.0/MANIFEST.in +2 -0
- nlpkit14-0.3.0/PKG-INFO +71 -0
- nlpkit14-0.3.0/README.md +54 -0
- nlpkit14-0.3.0/TEST_RESULTS.md +15 -0
- nlpkit14-0.3.0/pyproject.toml +20 -0
- nlpkit14-0.3.0/setup.cfg +4 -0
- nlpkit14-0.3.0/src/nlpkit14/__init__.py +70 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q1.py +30 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q10.py +41 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q11.py +39 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q12.py +50 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q13.py +25 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q14.py +40 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q2.py +33 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q3.py +29 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q4.py +44 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q5.py +33 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q6.py +43 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q7.py +31 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q8.py +39 -0
- nlpkit14-0.3.0/src/nlpkit14/programs/q9.py +36 -0
- nlpkit14-0.3.0/src/nlpkit14/questions.json +72 -0
- nlpkit14-0.3.0/src/nlpkit14.egg-info/PKG-INFO +71 -0
- nlpkit14-0.3.0/src/nlpkit14.egg-info/SOURCES.txt +26 -0
- nlpkit14-0.3.0/src/nlpkit14.egg-info/dependency_links.txt +1 -0
- nlpkit14-0.3.0/src/nlpkit14.egg-info/requires.txt +11 -0
- nlpkit14-0.3.0/src/nlpkit14.egg-info/top_level.txt +1 -0
- nlpkit14-0.3.0/tests/test_programs.py +87 -0
nlpkit14-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nlpkit14
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Execute fourteen NLP practical programs with commented source and expected outputs
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: nltk<4,>=3.9
|
|
8
|
+
Requires-Dist: spacy<4,>=3.8
|
|
9
|
+
Requires-Dist: scikit-learn<2,>=1.5
|
|
10
|
+
Requires-Dist: requests<3,>=2.32
|
|
11
|
+
Requires-Dist: beautifulsoup4<5,>=4.12
|
|
12
|
+
Provides-Extra: models
|
|
13
|
+
Requires-Dist: torch<3,>=2.4; extra == "models"
|
|
14
|
+
Requires-Dist: transformers<5,>=4.45; extra == "models"
|
|
15
|
+
Requires-Dist: benepar<0.3,>=0.2.0; extra == "models"
|
|
16
|
+
Requires-Dist: sentencepiece<1,>=0.2; extra == "models"
|
|
17
|
+
|
|
18
|
+
# nlpkit14 0.3.0
|
|
19
|
+
|
|
20
|
+
Run the fourteen programs from the supplied IA1 question/code/output document.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import nlpkit14 as n
|
|
24
|
+
n.q1() # Actually runs question 1 and prints computed output
|
|
25
|
+
n.source(1) # Shows the code, question and expected output as comments
|
|
26
|
+
n.questions()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Question numbers 1–7 are B1–B7. Numbers 8–14 are C1–C7. The question, expected output, and extra notes are comments in each bundled standalone Python program. Exercise calls print only the program's output. No expected-output text is substituted for model computation.
|
|
30
|
+
|
|
31
|
+
## Install and prepare online once
|
|
32
|
+
|
|
33
|
+
Install the shared wheel, then prepare the basic data and spaCy model:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
python -m pip install ./nlpkit14-0.3.0-py3-none-any.whl
|
|
37
|
+
python -c "import nlpkit14 as n; n.setup()"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For all exercises, install the model extra and run the complete setup (large downloads):
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
python -m pip install './nlpkit14-0.3.0-py3-none-any.whl[models]'
|
|
44
|
+
python -c "import nlpkit14 as n; n.setup(models=True)"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This is a local release of the new nlpkit14 project, not yet uploaded to PyPI. Do not use pip install nlpkit14 until publication succeeds.
|
|
48
|
+
|
|
49
|
+
## Offline installation
|
|
50
|
+
|
|
51
|
+
On an internet-connected machine with the SAME OS, architecture and Python version as the offline machine, download the wheel and dependencies:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
python -m pip download --dest wheelhouse './nlpkit14-0.3.0-py3-none-any.whl[models]'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Install and run setup online on that matching machine. Copy the wheelhouse, both installed spaCy model packages (or their installation wheels), and the full data/cache folder to the offline machine. Model data defaults to ~/.nlpkit14; set NLPKIT14_DATA before setup/import to choose a portable folder. Copying the entire prepared Python environment is platform specific; do not copy a Mac environment to Windows.
|
|
58
|
+
|
|
59
|
+
On the offline computer:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
python -m pip install --no-index --find-links=wheelhouse nlpkit14==0.3.0
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Install the spaCy model wheels from local storage too. Keep the copied data folder at ~/.nlpkit14 or point NLPKIT14_DATA to it. Model and dependency archives are not included in this small library wheel.
|
|
66
|
+
|
|
67
|
+
q8 fetches https://www.bnmit.org/ and requires internet even after setup. Other exercises can run without internet after all their requirements are installed. No downloads run implicitly from q1–q14. Missing packages/data raise their real installation errors rather than producing fake results.
|
|
68
|
+
|
|
69
|
+
## Output fidelity
|
|
70
|
+
|
|
71
|
+
The original algorithms and sample input are preserved. Downloads are moved to explicit setup. HTTP errors are checked. BERT uses evaluation mode and local cached model files. The raw Good–Turing demonstration is not a normalized probability estimator. The document's classifier fits its vocabulary before splitting and is an educational example, not an unbiased evaluation pipeline. Model outputs, parse trees, POS tags and similarity values can differ from the commented reference output. The document's B5 reference omits POS lines that the code actually prints. Read TEST_RESULTS.md for exactly which programs were executed.
|
nlpkit14-0.3.0/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# nlpkit14 0.3.0
|
|
2
|
+
|
|
3
|
+
Run the fourteen programs from the supplied IA1 question/code/output document.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
import nlpkit14 as n
|
|
7
|
+
n.q1() # Actually runs question 1 and prints computed output
|
|
8
|
+
n.source(1) # Shows the code, question and expected output as comments
|
|
9
|
+
n.questions()
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Question numbers 1–7 are B1–B7. Numbers 8–14 are C1–C7. The question, expected output, and extra notes are comments in each bundled standalone Python program. Exercise calls print only the program's output. No expected-output text is substituted for model computation.
|
|
13
|
+
|
|
14
|
+
## Install and prepare online once
|
|
15
|
+
|
|
16
|
+
Install the shared wheel, then prepare the basic data and spaCy model:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
python -m pip install ./nlpkit14-0.3.0-py3-none-any.whl
|
|
20
|
+
python -c "import nlpkit14 as n; n.setup()"
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
For all exercises, install the model extra and run the complete setup (large downloads):
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
python -m pip install './nlpkit14-0.3.0-py3-none-any.whl[models]'
|
|
27
|
+
python -c "import nlpkit14 as n; n.setup(models=True)"
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
This is a local release of the new nlpkit14 project, not yet uploaded to PyPI. Do not use pip install nlpkit14 until publication succeeds.
|
|
31
|
+
|
|
32
|
+
## Offline installation
|
|
33
|
+
|
|
34
|
+
On an internet-connected machine with the SAME OS, architecture and Python version as the offline machine, download the wheel and dependencies:
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
python -m pip download --dest wheelhouse './nlpkit14-0.3.0-py3-none-any.whl[models]'
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Install and run setup online on that matching machine. Copy the wheelhouse, both installed spaCy model packages (or their installation wheels), and the full data/cache folder to the offline machine. Model data defaults to ~/.nlpkit14; set NLPKIT14_DATA before setup/import to choose a portable folder. Copying the entire prepared Python environment is platform specific; do not copy a Mac environment to Windows.
|
|
41
|
+
|
|
42
|
+
On the offline computer:
|
|
43
|
+
|
|
44
|
+
```sh
|
|
45
|
+
python -m pip install --no-index --find-links=wheelhouse nlpkit14==0.3.0
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Install the spaCy model wheels from local storage too. Keep the copied data folder at ~/.nlpkit14 or point NLPKIT14_DATA to it. Model and dependency archives are not included in this small library wheel.
|
|
49
|
+
|
|
50
|
+
q8 fetches https://www.bnmit.org/ and requires internet even after setup. Other exercises can run without internet after all their requirements are installed. No downloads run implicitly from q1–q14. Missing packages/data raise their real installation errors rather than producing fake results.
|
|
51
|
+
|
|
52
|
+
## Output fidelity
|
|
53
|
+
|
|
54
|
+
The original algorithms and sample input are preserved. Downloads are moved to explicit setup. HTTP errors are checked. BERT uses evaluation mode and local cached model files. The raw Good–Turing demonstration is not a normalized probability estimator. The document's classifier fits its vocabulary before splitting and is an educational example, not an unbiased evaluation pipeline. Model outputs, parse trees, POS tags and similarity values can differ from the commented reference output. The document's B5 reference omits POS lines that the code actually prints. Read TEST_RESULTS.md for exactly which programs were executed.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Verification of version 0.3.0
|
|
2
|
+
|
|
3
|
+
- All fourteen document programs were extracted, reviewed, compiled, and bundled with their question and expected output as Python comments.
|
|
4
|
+
- The wheel built with Python 3.12 and passed `twine check`.
|
|
5
|
+
- A local no-index, no-dependency installation into a Python 3.12 virtual environment succeeded. The installed q9() computed the document's bigram probability. This is not a complete dependency-resolution test.
|
|
6
|
+
- The execution suite ran under an existing Python 3.13 Anaconda environment with NLTK, scikit-learn, requests and BeautifulSoup. Ten tests passed; one was skipped because WordNet data was not fully downloaded. Programs q1, q8 (controlled HTML response), q9, q10, q11 and q12 executed. Numeric/classification exercises were also run with socket connections blocked.
|
|
7
|
+
- q4 has not completed an end-to-end test because the WordNet download was stopped to keep delivery quick. The incomplete test archive is outside the deliverables.
|
|
8
|
+
- q2, q3, q5, q6, q7, q13 and q14 were syntax-checked but not executed with their required models. spaCy/Benepar/BERT model downloads were not completed. These are not asserted to be error-free across all dependency versions.
|
|
9
|
+
- q8's HTML extraction and real NLTK POS tagging were tested with a controlled HTTP response. Fetching the live BNMIT website was not tested.
|
|
10
|
+
- Windows and Linux were not tested. Full setup(), model extras dependency resolution, and transfer of an offline wheelhouse/model cache have not been end-to-end tested.
|
|
11
|
+
- This release has not been uploaded to PyPI. The previously published version remains separate.
|
|
12
|
+
|
|
13
|
+
Model exercises require their real packages and data. No static sample answer is printed in place of model inference. Unexpected errors are not suppressed.
|
|
14
|
+
|
|
15
|
+
Rename: public distribution and import are now nlpkit14. No upload has been performed.
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "nlpkit14"
|
|
7
|
+
version = "0.3.0"
|
|
8
|
+
description = "Execute fourteen NLP practical programs with commented source and expected outputs"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
dependencies = ["nltk>=3.9,<4", "spacy>=3.8,<4", "scikit-learn>=1.5,<2", "requests>=2.32,<3", "beautifulsoup4>=4.12,<5"]
|
|
12
|
+
|
|
13
|
+
[project.optional-dependencies]
|
|
14
|
+
models = ["torch>=2.4,<3", "transformers>=4.45,<5", "benepar>=0.2.0,<0.3", "sentencepiece>=0.2,<1"]
|
|
15
|
+
|
|
16
|
+
[tool.setuptools.packages.find]
|
|
17
|
+
where = ["src"]
|
|
18
|
+
|
|
19
|
+
[tool.setuptools.package-data]
|
|
20
|
+
nlpkit14 = ["questions.json", "programs/*.py"]
|
nlpkit14-0.3.0/setup.cfg
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Run the fourteen supplied NLP practicals, with source available separately."""
|
|
2
|
+
from importlib.resources import files
|
|
3
|
+
import json
|
|
4
|
+
import os
|
|
5
|
+
|
|
6
|
+
__version__ = "0.3.0"
|
|
7
|
+
|
|
8
|
+
def _resource(number):
|
|
9
|
+
if number not in range(1, 15):
|
|
10
|
+
raise ValueError("Choose a question from 1 to 14")
|
|
11
|
+
return files(__package__).joinpath("programs", f"q{number}.py")
|
|
12
|
+
|
|
13
|
+
def _configure():
|
|
14
|
+
path = os.path.expanduser(os.environ.get("NLPKIT14_DATA", "~/.nlpkit14"))
|
|
15
|
+
data = os.path.join(path, "nltk_data")
|
|
16
|
+
os.environ.setdefault("HF_HOME", os.path.join(path, "huggingface"))
|
|
17
|
+
try:
|
|
18
|
+
import nltk
|
|
19
|
+
except ModuleNotFoundError:
|
|
20
|
+
return
|
|
21
|
+
if data not in nltk.data.path:
|
|
22
|
+
nltk.data.path.insert(0, data)
|
|
23
|
+
|
|
24
|
+
def source(number):
|
|
25
|
+
"""Print runnable source, including the commented question and expected output."""
|
|
26
|
+
print(_resource(number).read_text(encoding="utf-8"), end="")
|
|
27
|
+
|
|
28
|
+
def questions():
|
|
29
|
+
for row in json.loads(files(__package__).joinpath("questions.json").read_text(encoding="utf-8")):
|
|
30
|
+
print(f"q{row['number']}(): {row['question']}")
|
|
31
|
+
|
|
32
|
+
def _run(number):
|
|
33
|
+
_configure()
|
|
34
|
+
resource = _resource(number)
|
|
35
|
+
namespace = {"__name__": f"nlpkit14.question{number}"}
|
|
36
|
+
exec(compile(resource.read_text(encoding="utf-8"), str(resource), "exec"), namespace)
|
|
37
|
+
|
|
38
|
+
def _make(number):
|
|
39
|
+
def question():
|
|
40
|
+
_run(number)
|
|
41
|
+
question.__name__ = f"q{number}"
|
|
42
|
+
question.__qualname__ = question.__name__
|
|
43
|
+
question.__doc__ = f"Execute question {number}. Use source({number}) to see code and comments."
|
|
44
|
+
return question
|
|
45
|
+
|
|
46
|
+
for _number in range(1, 15):
|
|
47
|
+
globals()[f"q{_number}"] = _make(_number)
|
|
48
|
+
|
|
49
|
+
def setup(models=False):
|
|
50
|
+
"""Explicit online preparation. models=True also downloads large parsing/BERT models."""
|
|
51
|
+
_configure()
|
|
52
|
+
import nltk
|
|
53
|
+
import subprocess
|
|
54
|
+
import sys
|
|
55
|
+
directory = os.path.join(os.path.expanduser(os.environ.get("NLPKIT14_DATA", "~/.nlpkit14")), "nltk_data")
|
|
56
|
+
os.makedirs(directory, exist_ok=True)
|
|
57
|
+
for name in ("punkt_tab", "stopwords", "averaged_perceptron_tagger_eng", "wordnet", "omw-1.4"):
|
|
58
|
+
if not nltk.download(name, download_dir=directory, quiet=True):
|
|
59
|
+
raise RuntimeError(f"Could not download {name}; check internet connectivity")
|
|
60
|
+
subprocess.run([sys.executable, "-m", "spacy", "download", "en_core_web_sm"], check=True)
|
|
61
|
+
if models:
|
|
62
|
+
subprocess.run([sys.executable, "-m", "spacy", "download", "en_core_web_md"], check=True)
|
|
63
|
+
import benepar
|
|
64
|
+
if not benepar.download("benepar_en3", download_dir=directory):
|
|
65
|
+
raise RuntimeError("Could not download benepar_en3; check internet connectivity")
|
|
66
|
+
from transformers import BertTokenizer, BertModel
|
|
67
|
+
BertTokenizer.from_pretrained("bert-base-uncased")
|
|
68
|
+
BertModel.from_pretrained("bert-base-uncased")
|
|
69
|
+
|
|
70
|
+
__all__ = ["questions", "source", "setup"] + [f"q{i}" for i in range(1, 15)]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Question 1 (B1): Tokenization and Stop-word Removal using NLTK
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# Sentences: ['This is a simple example demonstrating stopword removal in NLP.', 'NLP is interesting.']
|
|
5
|
+
# Words: ['This', 'is', 'a', 'simple', 'example', 'demonstrating', 'stopword', 'removal', 'in', 'NLP', '.', 'NLP', 'is', 'interesting', '.']
|
|
6
|
+
# Filtered Tokens: ['simple', 'example', 'demonstrating', 'stopword', 'removal', 'NLP', 'NLP', 'interesting']
|
|
7
|
+
|
|
8
|
+
import nltk
|
|
9
|
+
from nltk.tokenize import word_tokenize, sent_tokenize
|
|
10
|
+
from nltk.corpus import stopwords
|
|
11
|
+
|
|
12
|
+
# Download required resources
|
|
13
|
+
# Resource download moved to n.setup().
|
|
14
|
+
# Resource download moved to n.setup().
|
|
15
|
+
# Input text
|
|
16
|
+
text = "This is a simple example demonstrating stopword removal in NLP. NLP is interesting."
|
|
17
|
+
|
|
18
|
+
# Sentence tokenization
|
|
19
|
+
sentences = sent_tokenize(text)
|
|
20
|
+
|
|
21
|
+
# Word tokenization
|
|
22
|
+
words = word_tokenize(text)
|
|
23
|
+
|
|
24
|
+
# Stop-word removal
|
|
25
|
+
stop_words = set(stopwords.words('english'))
|
|
26
|
+
filtered = [w for w in words if w.lower() not in stop_words and w.isalnum()]
|
|
27
|
+
|
|
28
|
+
print("Sentences:", sentences)
|
|
29
|
+
print("Words:", words)
|
|
30
|
+
print("Filtered Tokens:", filtered)
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Question 10 (C3): Add-One (Laplace) Smoothing for an N-gram Model
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# P(i|<s>) = 0.272727
|
|
5
|
+
# P(like|i) = 0.300000
|
|
6
|
+
# P(apples|like) = 0.200000
|
|
7
|
+
# P(</s>|apples) = 0.300000
|
|
8
|
+
# Vocabulary Size = 8
|
|
9
|
+
# Add-One Sentence Probability = 0.00490909
|
|
10
|
+
|
|
11
|
+
from collections import Counter
|
|
12
|
+
|
|
13
|
+
corpus = [
|
|
14
|
+
['i', 'like', 'apples'],
|
|
15
|
+
['i', 'like', 'bananas'],
|
|
16
|
+
['you', 'eat', 'apples']
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
unigrams = Counter()
|
|
20
|
+
bigrams = Counter()
|
|
21
|
+
|
|
22
|
+
for sentence in corpus:
|
|
23
|
+
tokens = ['<s>'] + sentence + ['</s>']
|
|
24
|
+
unigrams.update(tokens)
|
|
25
|
+
bigrams.update(zip(tokens[:-1], tokens[1:]))
|
|
26
|
+
|
|
27
|
+
V = len(unigrams) # vocabulary size including boundary tokens
|
|
28
|
+
|
|
29
|
+
def add_one(w1, w2):
|
|
30
|
+
return (bigrams[(w1, w2)] + 1) / (unigrams[w1] + V)
|
|
31
|
+
|
|
32
|
+
test = ['<s>', 'i', 'like', 'apples', '</s>']
|
|
33
|
+
probability = 1.0
|
|
34
|
+
|
|
35
|
+
for w1, w2 in zip(test[:-1], test[1:]):
|
|
36
|
+
p = add_one(w1, w2)
|
|
37
|
+
probability *= p
|
|
38
|
+
print(f"P({w2}|{w1}) = {p:.6f}")
|
|
39
|
+
|
|
40
|
+
print("Vocabulary Size =", V)
|
|
41
|
+
print("Add-One Sentence Probability =", round(probability, 8))
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Question 11 (C4): Calculate Good-Turing Frequency
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Raw Good-Turing adjusted frequencies only; this is not a normalized probability model.
|
|
4
|
+
# Expected output:
|
|
5
|
+
# r C*(r)
|
|
6
|
+
# -------------
|
|
7
|
+
# 0 0.0
|
|
8
|
+
# 1 1.3333
|
|
9
|
+
# 2 1.5
|
|
10
|
+
# 3 0.0
|
|
11
|
+
|
|
12
|
+
from collections import Counter
|
|
13
|
+
|
|
14
|
+
def good_turing(counts):
|
|
15
|
+
# counts contains observed frequencies of different events
|
|
16
|
+
freq_of_freq = Counter(counts)
|
|
17
|
+
max_r = max(freq_of_freq.keys())
|
|
18
|
+
adjusted_counts = {}
|
|
19
|
+
|
|
20
|
+
for r in range(0, max_r + 1):
|
|
21
|
+
Nr = freq_of_freq.get(r, 0)
|
|
22
|
+
Nr_plus_1 = freq_of_freq.get(r + 1, 0)
|
|
23
|
+
|
|
24
|
+
if Nr > 0:
|
|
25
|
+
c_star = (r + 1) * (Nr_plus_1 / Nr)
|
|
26
|
+
adjusted_counts[r] = round(c_star, 4)
|
|
27
|
+
else:
|
|
28
|
+
adjusted_counts[r] = 0.0
|
|
29
|
+
|
|
30
|
+
return adjusted_counts
|
|
31
|
+
|
|
32
|
+
# 3 events occur once, 2 events occur twice, 1 event occurs 3 times
|
|
33
|
+
sample_counts = [1, 1, 1, 2, 2, 3]
|
|
34
|
+
result = good_turing(sample_counts)
|
|
35
|
+
|
|
36
|
+
print(f"{'r':<5}{'C*(r)':<10}")
|
|
37
|
+
print("-" * 13)
|
|
38
|
+
for r in sorted(result):
|
|
39
|
+
print(f"{r:<5}{result[r]:<10}")
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Question 12 (C5): Text Classification
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Preserves the document example; fit the vectorizer on training data only for unbiased evaluation.
|
|
4
|
+
# Expected output:
|
|
5
|
+
# precision recall f1-score support
|
|
6
|
+
#
|
|
7
|
+
# sports 0.00 0.00 0.00 2
|
|
8
|
+
# technology 0.33 1.00 0.50 1
|
|
9
|
+
#
|
|
10
|
+
# accuracy 0.33 3
|
|
11
|
+
# macro avg 0.17 0.50 0.25 3
|
|
12
|
+
# weighted avg 0.11 0.33 0.17 3
|
|
13
|
+
|
|
14
|
+
from sklearn.feature_extraction.text import CountVectorizer
|
|
15
|
+
from sklearn.model_selection import train_test_split
|
|
16
|
+
from sklearn.linear_model import LogisticRegression
|
|
17
|
+
from sklearn.metrics import classification_report
|
|
18
|
+
|
|
19
|
+
texts = [
|
|
20
|
+
"The CPU and memory are important in a computer",
|
|
21
|
+
"Basketball is a popular sport",
|
|
22
|
+
"Python and Java are programming languages",
|
|
23
|
+
"Football players need strength and speed",
|
|
24
|
+
"Hard disk and RAM are types of hardware",
|
|
25
|
+
"Tennis is played with a racket",
|
|
26
|
+
"Motherboard connects all components",
|
|
27
|
+
"He scored a goal in the last minute"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
labels = [
|
|
31
|
+
"technology", "sports", "technology", "sports",
|
|
32
|
+
"technology", "sports", "technology", "sports"
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
# Convert text into Bag-of-Words vectors
|
|
36
|
+
vectorizer = CountVectorizer()
|
|
37
|
+
X = vectorizer.fit_transform(texts)
|
|
38
|
+
|
|
39
|
+
# Train-test split
|
|
40
|
+
X_train, X_test, y_train, y_test = train_test_split(
|
|
41
|
+
X, labels, test_size=0.3, random_state=42
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Train classifier
|
|
45
|
+
clf = LogisticRegression()
|
|
46
|
+
clf.fit(X_train, y_train)
|
|
47
|
+
|
|
48
|
+
# Predict and evaluate
|
|
49
|
+
y_pred = clf.predict(X_test)
|
|
50
|
+
print(classification_report(y_test, y_pred, zero_division=0))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Question 13 (C6): Calculate Vector Similarity in Semantic Space
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# Semantic similarity between:
|
|
5
|
+
# "Apples are tasty" and "Bananas are delicious" = 0.8661
|
|
6
|
+
|
|
7
|
+
import spacy
|
|
8
|
+
from sklearn.metrics.pairwise import cosine_similarity
|
|
9
|
+
|
|
10
|
+
# Medium model contains pretrained vectors
|
|
11
|
+
nlp = spacy.load("en_core_web_md")
|
|
12
|
+
|
|
13
|
+
text1 = "Apples are tasty"
|
|
14
|
+
text2 = "Bananas are delicious"
|
|
15
|
+
|
|
16
|
+
doc1 = nlp(text1)
|
|
17
|
+
doc2 = nlp(text2)
|
|
18
|
+
|
|
19
|
+
vec1 = doc1.vector.reshape(1, -1)
|
|
20
|
+
vec2 = doc2.vector.reshape(1, -1)
|
|
21
|
+
|
|
22
|
+
similarity = cosine_similarity(vec1, vec2)[0][0]
|
|
23
|
+
|
|
24
|
+
print(f'Semantic similarity between:')
|
|
25
|
+
print(f'"{text1}" and "{text2}" = {similarity:.4f}')
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Question 14 (C7): Identify Context of Ambiguous Words using BERT
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# Sentence 1: He sat on the river bank and watched the water flow.
|
|
5
|
+
# Sentence 2: She went to the bank to deposit some money.
|
|
6
|
+
# Contextual similarity of 'bank': 0.4972
|
|
7
|
+
|
|
8
|
+
from transformers import BertTokenizer, BertModel
|
|
9
|
+
import torch
|
|
10
|
+
from sklearn.metrics.pairwise import cosine_similarity
|
|
11
|
+
|
|
12
|
+
# Load pretrained BERT
|
|
13
|
+
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased', local_files_only=True)
|
|
14
|
+
model = BertModel.from_pretrained('bert-base-uncased', local_files_only=True)
|
|
15
|
+
model.eval()
|
|
16
|
+
|
|
17
|
+
sent1 = "He sat on the river bank and watched the water flow."
|
|
18
|
+
sent2 = "She went to the bank to deposit some money."
|
|
19
|
+
|
|
20
|
+
def get_word_embedding(sentence, target_word):
|
|
21
|
+
inputs = tokenizer(sentence, return_tensors='pt')
|
|
22
|
+
|
|
23
|
+
with torch.no_grad():
|
|
24
|
+
outputs = model(**inputs)
|
|
25
|
+
|
|
26
|
+
tokens = tokenizer.convert_ids_to_tokens(inputs['input_ids'][0])
|
|
27
|
+
embeddings = outputs.last_hidden_state.squeeze(0)
|
|
28
|
+
|
|
29
|
+
# Find token position
|
|
30
|
+
idx = tokens.index(target_word)
|
|
31
|
+
return embeddings[idx].numpy()
|
|
32
|
+
|
|
33
|
+
embedding1 = get_word_embedding(sent1, "bank")
|
|
34
|
+
embedding2 = get_word_embedding(sent2, "bank")
|
|
35
|
+
|
|
36
|
+
similarity = cosine_similarity([embedding1], [embedding2])[0][0]
|
|
37
|
+
|
|
38
|
+
print("Sentence 1:", sent1)
|
|
39
|
+
print("Sentence 2:", sent2)
|
|
40
|
+
print("Contextual similarity of 'bank':", round(similarity, 4))
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Question 2 (B2): Tokenization and Stop-word Removal using spaCy
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# Sentences: ['This is an example sentence, demonstrating tokenization and stop word removal.']
|
|
5
|
+
# Tokens: ['This', 'is', 'an', 'example', 'sentence', ',', 'demonstrating', 'tokenization', 'and', 'stop', 'word', 'removal', '.']
|
|
6
|
+
# Filtered Tokens: ['example', 'sentence', 'demonstrating', 'tokenization', 'stop', 'word', 'removal']
|
|
7
|
+
|
|
8
|
+
import spacy
|
|
9
|
+
|
|
10
|
+
# Load spaCy English model
|
|
11
|
+
nlp = spacy.load("en_core_web_sm")
|
|
12
|
+
|
|
13
|
+
# Sample text
|
|
14
|
+
text = "This is an example sentence, demonstrating tokenization and stop word removal."
|
|
15
|
+
|
|
16
|
+
# Process text
|
|
17
|
+
Doc = nlp(text)
|
|
18
|
+
|
|
19
|
+
# Sentence tokenization
|
|
20
|
+
sentences = [sent.text for sent in Doc.sents]
|
|
21
|
+
|
|
22
|
+
# Word tokenization
|
|
23
|
+
tokens = [token.text for token in Doc]
|
|
24
|
+
|
|
25
|
+
# Remove stop words and punctuation
|
|
26
|
+
filtered_tokens = [
|
|
27
|
+
token.text for token in Doc
|
|
28
|
+
if not token.is_stop and not token.is_punct
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
print("Sentences:", sentences)
|
|
32
|
+
print("Tokens:", tokens)
|
|
33
|
+
print("Filtered Tokens:", filtered_tokens)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Question 3 (B3): Stemming and Lemmatization using spaCy
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# Original Words : ['Studies', 'studying', 'cries', 'cried', 'flying', 'flies']
|
|
5
|
+
# Lemmatized Words : ['study', 'study', 'cry', 'cry', 'fly', 'fly']
|
|
6
|
+
# Stemmed Words : ['studi', 'studi', 'cri', 'cri', 'fli', 'fli']
|
|
7
|
+
|
|
8
|
+
import spacy
|
|
9
|
+
from nltk.stem import PorterStemmer
|
|
10
|
+
|
|
11
|
+
# Load spaCy model and create stemmer
|
|
12
|
+
nlp = spacy.load("en_core_web_sm")
|
|
13
|
+
stemmer = PorterStemmer()
|
|
14
|
+
|
|
15
|
+
sentence = "Studies studying cries cried flying flies"
|
|
16
|
+
doc = nlp(sentence)
|
|
17
|
+
|
|
18
|
+
# Original tokens
|
|
19
|
+
original_words = [token.text for token in doc]
|
|
20
|
+
|
|
21
|
+
# Lemmatization using spaCy
|
|
22
|
+
lemmatized_words = [token.lemma_ for token in doc]
|
|
23
|
+
|
|
24
|
+
# Stemming on spaCy tokens
|
|
25
|
+
stemmed_words = [stemmer.stem(token.text) for token in doc]
|
|
26
|
+
|
|
27
|
+
print("Original Words :", original_words)
|
|
28
|
+
print("Lemmatized Words :", lemmatized_words)
|
|
29
|
+
print("Stemmed Words :", stemmed_words)
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Question 4 (B4): Stemming and Lemmatization using NLTK
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# Original Words: ['Studies', 'studying', 'cries', 'cried', 'flying', 'flies']
|
|
5
|
+
# Stemmed Words : ['studi', 'studi', 'cri', 'cri', 'fli', 'fli']
|
|
6
|
+
# Lemmatized Words: ['Studies', 'study', 'cry', 'cry', 'fly', 'fly']
|
|
7
|
+
|
|
8
|
+
import nltk
|
|
9
|
+
from nltk.tokenize import word_tokenize
|
|
10
|
+
from nltk.stem import PorterStemmer, WordNetLemmatizer
|
|
11
|
+
from nltk.corpus import wordnet
|
|
12
|
+
|
|
13
|
+
# Resource download moved to n.setup().
|
|
14
|
+
# Resource download moved to n.setup().
|
|
15
|
+
# Resource download moved to n.setup().
|
|
16
|
+
# Resource download moved to n.setup().
|
|
17
|
+
stemmer = PorterStemmer()
|
|
18
|
+
lemmatizer = WordNetLemmatizer()
|
|
19
|
+
|
|
20
|
+
# Map Treebank POS tag to WordNet POS
|
|
21
|
+
def get_wordnet_pos(tag):
|
|
22
|
+
if tag.startswith('J'):
|
|
23
|
+
return wordnet.ADJ
|
|
24
|
+
elif tag.startswith('V'):
|
|
25
|
+
return wordnet.VERB
|
|
26
|
+
elif tag.startswith('N'):
|
|
27
|
+
return wordnet.NOUN
|
|
28
|
+
elif tag.startswith('R'):
|
|
29
|
+
return wordnet.ADV
|
|
30
|
+
return wordnet.NOUN
|
|
31
|
+
|
|
32
|
+
text = "Studies studying cries cried flying flies"
|
|
33
|
+
tokens = word_tokenize(text)
|
|
34
|
+
tagged = nltk.pos_tag(tokens)
|
|
35
|
+
|
|
36
|
+
stems = [stemmer.stem(word) for word in tokens]
|
|
37
|
+
lemmas = [
|
|
38
|
+
lemmatizer.lemmatize(word, get_wordnet_pos(tag))
|
|
39
|
+
for word, tag in tagged
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
print("Original Words:", tokens)
|
|
43
|
+
print("Stemmed Words :", stems)
|
|
44
|
+
print("Lemmatized Words:", lemmas)
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Question 5 (B5): Design a Python Program to Illustrate Corpus
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# --- Document 1 ---
|
|
5
|
+
# Tokens: ['The', 'quick', 'brown', 'fox', 'jumps', 'over', 'the', 'lazy', 'dog', '.']
|
|
6
|
+
# POS Tags: [('The', 'DET'), ('quick', 'ADJ'), ('brown', 'ADJ'), ('fox', 'NOUN'), ('jumps', 'VERB'), ('over', 'ADP'), ('the', 'DET'), ('lazy', 'ADJ'), ('dog', 'NOUN'), ('.', 'PUNCT')]
|
|
7
|
+
#
|
|
8
|
+
# --- Document 2 ---
|
|
9
|
+
# Tokens: ['SpaCy', 'is', 'a', 'popular', 'NLP', 'library', 'in', 'Python', '.']
|
|
10
|
+
#
|
|
11
|
+
# --- Document 3 ---
|
|
12
|
+
# Tokens: ['Natural', 'Language', 'Processing', 'enables', 'machines', 'to', 'understand', 'human', 'language', '.']
|
|
13
|
+
|
|
14
|
+
import spacy
|
|
15
|
+
|
|
16
|
+
nlp = spacy.load("en_core_web_sm")
|
|
17
|
+
|
|
18
|
+
# A small corpus: collection of documents
|
|
19
|
+
corpus = [
|
|
20
|
+
"The quick brown fox jumps over the lazy dog.",
|
|
21
|
+
"SpaCy is a popular NLP library in Python.",
|
|
22
|
+
"Natural Language Processing enables machines to understand human language."
|
|
23
|
+
]
|
|
24
|
+
|
|
25
|
+
for i, text in enumerate(corpus, start=1):
|
|
26
|
+
print(f"\n--- Document {i} ---")
|
|
27
|
+
doc = nlp(text)
|
|
28
|
+
|
|
29
|
+
tokens = [token.text for token in doc]
|
|
30
|
+
pos_tags = [(token.text, token.pos_) for token in doc]
|
|
31
|
+
|
|
32
|
+
print("Tokens:", tokens)
|
|
33
|
+
print("POS Tags:", pos_tags)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Question 6 (B6): Generate a Constituency Parse Tree
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# Parse String:
|
|
5
|
+
# (S (NP (DT The) (JJ quick) (JJ brown) (NN fox))
|
|
6
|
+
# (VP (VBZ jumps)
|
|
7
|
+
# (PP (IN over) (NP (DT the) (JJ lazy) (NN dog))))
|
|
8
|
+
# (. .))
|
|
9
|
+
#
|
|
10
|
+
# Pretty Tree:
|
|
11
|
+
# S
|
|
12
|
+
# _______________|__________________________
|
|
13
|
+
# | VP |
|
|
14
|
+
# | _________|___ |
|
|
15
|
+
# NP | PP |
|
|
16
|
+
# ____|__________ | ________|___ |
|
|
17
|
+
# DT JJ JJ NN VBZ IN DT JJ NN .
|
|
18
|
+
# The quick brown fox jumps over the lazy dog .
|
|
19
|
+
|
|
20
|
+
# Run once if required:
|
|
21
|
+
# !pip install spacy benepar
|
|
22
|
+
# !python -m spacy download en_core_web_sm
|
|
23
|
+
|
|
24
|
+
import spacy
|
|
25
|
+
import benepar
|
|
26
|
+
import nltk
|
|
27
|
+
|
|
28
|
+
# Model download moved to n.setup(models=True).
|
|
29
|
+
nlp = spacy.load("en_core_web_sm")
|
|
30
|
+
|
|
31
|
+
if not nlp.has_pipe("benepar"):
|
|
32
|
+
nlp.add_pipe("benepar", config={"model": "benepar_en3"})
|
|
33
|
+
|
|
34
|
+
sentence = "The quick brown fox jumps over the lazy dog."
|
|
35
|
+
doc = nlp(sentence)
|
|
36
|
+
|
|
37
|
+
for sent in doc.sents:
|
|
38
|
+
parse_string = sent._.parse_string
|
|
39
|
+
print("Parse String:\n", parse_string)
|
|
40
|
+
|
|
41
|
+
tree = nltk.Tree.fromstring(parse_string)
|
|
42
|
+
print("\nPretty Tree:")
|
|
43
|
+
tree.pretty_print()
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Question 7 (B7): Generate a Dependency Parse Tree
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# Word: The POS: DET Head: team Dep: det
|
|
5
|
+
# Word: cricket POS: NOUN Head: team Dep: compound
|
|
6
|
+
# Word: team POS: NOUN Head: won Dep: nsubj
|
|
7
|
+
# Word: won POS: VERB Head: won Dep: ROOT
|
|
8
|
+
# Word: the POS: DET Head: match Dep: det
|
|
9
|
+
# Word: match POS: NOUN Head: won Dep: dobj
|
|
10
|
+
# Word: in POS: ADP Head: won Dep: prep
|
|
11
|
+
# Word: Mumbai POS: PROPN Head: in Dep: pobj
|
|
12
|
+
# Word: . POS: PUNCT Head: won Dep: punct
|
|
13
|
+
|
|
14
|
+
import spacy
|
|
15
|
+
from spacy import displacy
|
|
16
|
+
|
|
17
|
+
nlp = spacy.load("en_core_web_sm")
|
|
18
|
+
sentence = "The cricket team won the match in Mumbai."
|
|
19
|
+
doc = nlp(sentence)
|
|
20
|
+
|
|
21
|
+
# Print dependency information
|
|
22
|
+
for token in doc:
|
|
23
|
+
print(
|
|
24
|
+
f"Word: {token.text:8} "
|
|
25
|
+
f"POS: {token.pos_:6} "
|
|
26
|
+
f"Head: {token.head.text:8} "
|
|
27
|
+
f"Dep: {token.dep_}"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
# In Jupyter / Colab
|
|
31
|
+
# displacy.render(doc, style="dep", jupyter=True)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# Question 8 (C1): POS Tagging on Text Scraped from a Website
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# POS Tags (sample):
|
|
5
|
+
# [('B.N.M', 'NNP'), ('Institute', 'NNP'), ('of', 'IN'),
|
|
6
|
+
# ('Technology', 'NNP'), ('is', 'VBZ'), ('one', 'CD'),
|
|
7
|
+
# ('of', 'IN'), ('the', 'DT'), ('top', 'JJ'),
|
|
8
|
+
# ('engineering', 'NN'), ('colleges', 'NNS'), ...]
|
|
9
|
+
|
|
10
|
+
import requests
|
|
11
|
+
from bs4 import BeautifulSoup
|
|
12
|
+
import nltk
|
|
13
|
+
|
|
14
|
+
# Resource download moved to n.setup().
|
|
15
|
+
# Resource download moved to n.setup().
|
|
16
|
+
def scrape_text(url):
|
|
17
|
+
response = requests.get(url, timeout=10)
|
|
18
|
+
response.raise_for_status()
|
|
19
|
+
soup = BeautifulSoup(response.content, 'html.parser')
|
|
20
|
+
|
|
21
|
+
# Remove scripts and styles
|
|
22
|
+
for item in soup(['script', 'style']):
|
|
23
|
+
item.extract()
|
|
24
|
+
|
|
25
|
+
return soup.get_text(separator=' ')
|
|
26
|
+
|
|
27
|
+
def pos_tag_text(text):
|
|
28
|
+
tokens = nltk.word_tokenize(text)
|
|
29
|
+
return nltk.pos_tag(tokens)
|
|
30
|
+
|
|
31
|
+
url = "https://www.bnmit.org/"
|
|
32
|
+
scraped_text = scrape_text(url)
|
|
33
|
+
pos_tags = pos_tag_text(scraped_text)
|
|
34
|
+
|
|
35
|
+
print("Scraped Text (first 300 characters):")
|
|
36
|
+
print(scraped_text[:300])
|
|
37
|
+
|
|
38
|
+
print("\nPOS Tags (first 30 tokens):")
|
|
39
|
+
print(pos_tags[:30])
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Question 9 (C2): Implement a Bigram Model and Calculate Test-Sentence Probability
|
|
2
|
+
# Output below is the document example; actual model and website results may differ.
|
|
3
|
+
# Expected output:
|
|
4
|
+
# P(i|<s>) = 2/3 = 0.666667
|
|
5
|
+
# P(like|i) = 2/2 = 1.000000
|
|
6
|
+
# P(apples|like) = 1/2 = 0.500000
|
|
7
|
+
# P(</s>|apples) = 2/2 = 1.000000
|
|
8
|
+
# Sentence Probability = 0.33333333
|
|
9
|
+
|
|
10
|
+
from collections import Counter
|
|
11
|
+
|
|
12
|
+
# Training corpus
|
|
13
|
+
corpus = [
|
|
14
|
+
['i', 'like', 'apples'],
|
|
15
|
+
['i', 'like', 'bananas'],
|
|
16
|
+
['you', 'eat', 'apples']
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
unigrams = Counter()
|
|
20
|
+
bigrams = Counter()
|
|
21
|
+
|
|
22
|
+
for sentence in corpus:
|
|
23
|
+
tokens = ['<s>'] + sentence + ['</s>']
|
|
24
|
+
unigrams.update(tokens)
|
|
25
|
+
bigrams.update(zip(tokens[:-1], tokens[1:]))
|
|
26
|
+
|
|
27
|
+
# Test sentence
|
|
28
|
+
test = ['<s>', 'i', 'like', 'apples', '</s>']
|
|
29
|
+
probability = 1.0
|
|
30
|
+
|
|
31
|
+
for w1, w2 in zip(test[:-1], test[1:]):
|
|
32
|
+
p = bigrams[(w1, w2)] / unigrams[w1]
|
|
33
|
+
probability *= p
|
|
34
|
+
print(f"P({w2}|{w1}) = {bigrams[(w1,w2)]}/{unigrams[w1]} = {p:.6f}")
|
|
35
|
+
|
|
36
|
+
print("Sentence Probability =", round(probability, 8))
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"number": 1,
|
|
4
|
+
"label": "B1",
|
|
5
|
+
"question": "Tokenization and Stop-word Removal using NLTK"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
"number": 2,
|
|
9
|
+
"label": "B2",
|
|
10
|
+
"question": "Tokenization and Stop-word Removal using spaCy"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"number": 3,
|
|
14
|
+
"label": "B3",
|
|
15
|
+
"question": "Stemming and Lemmatization using spaCy"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"number": 4,
|
|
19
|
+
"label": "B4",
|
|
20
|
+
"question": "Stemming and Lemmatization using NLTK"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"number": 5,
|
|
24
|
+
"label": "B5",
|
|
25
|
+
"question": "Design a Python Program to Illustrate Corpus"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"number": 6,
|
|
29
|
+
"label": "B6",
|
|
30
|
+
"question": "Generate a Constituency Parse Tree"
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
"number": 7,
|
|
34
|
+
"label": "B7",
|
|
35
|
+
"question": "Generate a Dependency Parse Tree"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"number": 8,
|
|
39
|
+
"label": "C1",
|
|
40
|
+
"question": "POS Tagging on Text Scraped from a Website"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"number": 9,
|
|
44
|
+
"label": "C2",
|
|
45
|
+
"question": "Implement a Bigram Model and Calculate Test-Sentence Probability"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"number": 10,
|
|
49
|
+
"label": "C3",
|
|
50
|
+
"question": "Add-One (Laplace) Smoothing for an N-gram Model"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"number": 11,
|
|
54
|
+
"label": "C4",
|
|
55
|
+
"question": "Calculate Good-Turing Frequency"
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"number": 12,
|
|
59
|
+
"label": "C5",
|
|
60
|
+
"question": "Text Classification"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"number": 13,
|
|
64
|
+
"label": "C6",
|
|
65
|
+
"question": "Calculate Vector Similarity in Semantic Space"
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"number": 14,
|
|
69
|
+
"label": "C7",
|
|
70
|
+
"question": "Identify Context of Ambiguous Words using BERT"
|
|
71
|
+
}
|
|
72
|
+
]
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nlpkit14
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Execute fourteen NLP practical programs with commented source and expected outputs
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: nltk<4,>=3.9
|
|
8
|
+
Requires-Dist: spacy<4,>=3.8
|
|
9
|
+
Requires-Dist: scikit-learn<2,>=1.5
|
|
10
|
+
Requires-Dist: requests<3,>=2.32
|
|
11
|
+
Requires-Dist: beautifulsoup4<5,>=4.12
|
|
12
|
+
Provides-Extra: models
|
|
13
|
+
Requires-Dist: torch<3,>=2.4; extra == "models"
|
|
14
|
+
Requires-Dist: transformers<5,>=4.45; extra == "models"
|
|
15
|
+
Requires-Dist: benepar<0.3,>=0.2.0; extra == "models"
|
|
16
|
+
Requires-Dist: sentencepiece<1,>=0.2; extra == "models"
|
|
17
|
+
|
|
18
|
+
# nlpkit14 0.3.0
|
|
19
|
+
|
|
20
|
+
Run the fourteen programs from the supplied IA1 question/code/output document.
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import nlpkit14 as n
|
|
24
|
+
n.q1() # Actually runs question 1 and prints computed output
|
|
25
|
+
n.source(1) # Shows the code, question and expected output as comments
|
|
26
|
+
n.questions()
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Question numbers 1–7 are B1–B7. Numbers 8–14 are C1–C7. The question, expected output, and extra notes are comments in each bundled standalone Python program. Exercise calls print only the program's output. No expected-output text is substituted for model computation.
|
|
30
|
+
|
|
31
|
+
## Install and prepare online once
|
|
32
|
+
|
|
33
|
+
Install the shared wheel, then prepare the basic data and spaCy model:
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
python -m pip install ./nlpkit14-0.3.0-py3-none-any.whl
|
|
37
|
+
python -c "import nlpkit14 as n; n.setup()"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
For all exercises, install the model extra and run the complete setup (large downloads):
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
python -m pip install './nlpkit14-0.3.0-py3-none-any.whl[models]'
|
|
44
|
+
python -c "import nlpkit14 as n; n.setup(models=True)"
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
This is a local release of the new nlpkit14 project, not yet uploaded to PyPI. Do not use pip install nlpkit14 until publication succeeds.
|
|
48
|
+
|
|
49
|
+
## Offline installation
|
|
50
|
+
|
|
51
|
+
On an internet-connected machine with the SAME OS, architecture and Python version as the offline machine, download the wheel and dependencies:
|
|
52
|
+
|
|
53
|
+
```sh
|
|
54
|
+
python -m pip download --dest wheelhouse './nlpkit14-0.3.0-py3-none-any.whl[models]'
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Install and run setup online on that matching machine. Copy the wheelhouse, both installed spaCy model packages (or their installation wheels), and the full data/cache folder to the offline machine. Model data defaults to ~/.nlpkit14; set NLPKIT14_DATA before setup/import to choose a portable folder. Copying the entire prepared Python environment is platform specific; do not copy a Mac environment to Windows.
|
|
58
|
+
|
|
59
|
+
On the offline computer:
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
python -m pip install --no-index --find-links=wheelhouse nlpkit14==0.3.0
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Install the spaCy model wheels from local storage too. Keep the copied data folder at ~/.nlpkit14 or point NLPKIT14_DATA to it. Model and dependency archives are not included in this small library wheel.
|
|
66
|
+
|
|
67
|
+
q8 fetches https://www.bnmit.org/ and requires internet even after setup. Other exercises can run without internet after all their requirements are installed. No downloads run implicitly from q1–q14. Missing packages/data raise their real installation errors rather than producing fake results.
|
|
68
|
+
|
|
69
|
+
## Output fidelity
|
|
70
|
+
|
|
71
|
+
The original algorithms and sample input are preserved. Downloads are moved to explicit setup. HTTP errors are checked. BERT uses evaluation mode and local cached model files. The raw Good–Turing demonstration is not a normalized probability estimator. The document's classifier fits its vocabulary before splitting and is an educational example, not an unbiased evaluation pipeline. Model outputs, parse trees, POS tags and similarity values can differ from the commented reference output. The document's B5 reference omits POS lines that the code actually prints. Read TEST_RESULTS.md for exactly which programs were executed.
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
MANIFEST.in
|
|
2
|
+
README.md
|
|
3
|
+
TEST_RESULTS.md
|
|
4
|
+
pyproject.toml
|
|
5
|
+
src/nlpkit14/__init__.py
|
|
6
|
+
src/nlpkit14/questions.json
|
|
7
|
+
src/nlpkit14.egg-info/PKG-INFO
|
|
8
|
+
src/nlpkit14.egg-info/SOURCES.txt
|
|
9
|
+
src/nlpkit14.egg-info/dependency_links.txt
|
|
10
|
+
src/nlpkit14.egg-info/requires.txt
|
|
11
|
+
src/nlpkit14.egg-info/top_level.txt
|
|
12
|
+
src/nlpkit14/programs/q1.py
|
|
13
|
+
src/nlpkit14/programs/q10.py
|
|
14
|
+
src/nlpkit14/programs/q11.py
|
|
15
|
+
src/nlpkit14/programs/q12.py
|
|
16
|
+
src/nlpkit14/programs/q13.py
|
|
17
|
+
src/nlpkit14/programs/q14.py
|
|
18
|
+
src/nlpkit14/programs/q2.py
|
|
19
|
+
src/nlpkit14/programs/q3.py
|
|
20
|
+
src/nlpkit14/programs/q4.py
|
|
21
|
+
src/nlpkit14/programs/q5.py
|
|
22
|
+
src/nlpkit14/programs/q6.py
|
|
23
|
+
src/nlpkit14/programs/q7.py
|
|
24
|
+
src/nlpkit14/programs/q8.py
|
|
25
|
+
src/nlpkit14/programs/q9.py
|
|
26
|
+
tests/test_programs.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nlpkit14
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
import io
|
|
3
|
+
import unittest
|
|
4
|
+
from zipfile import BadZipFile
|
|
5
|
+
from importlib.resources import files
|
|
6
|
+
from unittest.mock import patch
|
|
7
|
+
|
|
8
|
+
import nlpkit14 as n
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ProgramTests(unittest.TestCase):
|
|
12
|
+
def require_nltk(self, *resources):
|
|
13
|
+
import nltk
|
|
14
|
+
n._configure()
|
|
15
|
+
for resource in resources:
|
|
16
|
+
try:
|
|
17
|
+
nltk.data.find(resource)
|
|
18
|
+
except (LookupError, BadZipFile):
|
|
19
|
+
self.skipTest(f'Install test data: {resource}')
|
|
20
|
+
|
|
21
|
+
def capture(self, number):
|
|
22
|
+
output = io.StringIO()
|
|
23
|
+
with contextlib.redirect_stdout(output):
|
|
24
|
+
getattr(n, f'q{number}')()
|
|
25
|
+
return output.getvalue()
|
|
26
|
+
|
|
27
|
+
def test_all_sources_compile_and_have_comments(self):
|
|
28
|
+
for n in range(1, 15):
|
|
29
|
+
source = files('nlpkit14').joinpath('programs', f'q{n}.py').read_text()
|
|
30
|
+
self.assertTrue(source.startswith(f'# Question {n} '))
|
|
31
|
+
self.assertIn('# Expected output:', source)
|
|
32
|
+
compile(source, f'q{n}.py', 'exec')
|
|
33
|
+
|
|
34
|
+
def test_q9_executes_bigram(self):
|
|
35
|
+
self.assertIn('Sentence Probability = 0.33333333', self.capture(9))
|
|
36
|
+
|
|
37
|
+
def test_q1_executes_tokenization(self):
|
|
38
|
+
self.require_nltk('tokenizers/punkt_tab/english/', 'corpora/stopwords')
|
|
39
|
+
output = self.capture(1)
|
|
40
|
+
self.assertIn("Filtered Tokens: ['simple', 'example', 'demonstrating'", output)
|
|
41
|
+
self.assertNotIn('Expected output', output)
|
|
42
|
+
|
|
43
|
+
def test_q4_executes_stemming(self):
|
|
44
|
+
self.require_nltk('tokenizers/punkt_tab/english/', 'taggers/averaged_perceptron_tagger_eng/', 'corpora/wordnet.zip')
|
|
45
|
+
self.assertIn("['studi', 'studi', 'cri', 'cri', 'fli', 'fli']", self.capture(4))
|
|
46
|
+
|
|
47
|
+
def test_q10_executes_laplace(self):
|
|
48
|
+
output = self.capture(10)
|
|
49
|
+
self.assertIn('Vocabulary Size = 8', output)
|
|
50
|
+
self.assertIn('Add-One Sentence Probability = 0.00490909', output)
|
|
51
|
+
|
|
52
|
+
def test_q11_executes_raw_good_turing(self):
|
|
53
|
+
self.assertIn('1.3333', self.capture(11))
|
|
54
|
+
|
|
55
|
+
def test_q12_trains_classifier(self):
|
|
56
|
+
self.assertIn('accuracy', self.capture(12))
|
|
57
|
+
|
|
58
|
+
def test_source_does_not_execute(self):
|
|
59
|
+
output = io.StringIO()
|
|
60
|
+
with contextlib.redirect_stdout(output):
|
|
61
|
+
n.source(14)
|
|
62
|
+
self.assertIn('# Question 14 ', output.getvalue())
|
|
63
|
+
|
|
64
|
+
def test_all_questions_listed(self):
|
|
65
|
+
output = io.StringIO()
|
|
66
|
+
with contextlib.redirect_stdout(output):
|
|
67
|
+
n.questions()
|
|
68
|
+
self.assertEqual(len(output.getvalue().splitlines()), 14)
|
|
69
|
+
|
|
70
|
+
def test_offline_numeric_exercises(self):
|
|
71
|
+
with patch('socket.socket.connect', side_effect=AssertionError('Network forbidden')):
|
|
72
|
+
for n in (9, 10, 11, 12):
|
|
73
|
+
self.capture(n)
|
|
74
|
+
|
|
75
|
+
def test_q8_tags_supplied_html_without_live_website(self):
|
|
76
|
+
self.require_nltk('tokenizers/punkt_tab/english/', 'taggers/averaged_perceptron_tagger_eng/')
|
|
77
|
+
import requests
|
|
78
|
+
class Response:
|
|
79
|
+
content = b'<p>Cats chase mice.</p>'
|
|
80
|
+
def raise_for_status(self):
|
|
81
|
+
pass
|
|
82
|
+
with patch.object(requests, 'get', return_value=Response()):
|
|
83
|
+
self.assertIn('POS Tags', self.capture(8))
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == '__main__':
|
|
87
|
+
unittest.main()
|