# pywsd: Lesk and Similarity-Based Word Sense Disambiguation in Python

> pywsd packages classic WSD algorithms (Lesk variants, maximum similarity, random and first-sense baselines) behind a small Python API, backed by Open English WordNet 2024. It is a teaching and prototyping library, not a supervised WSD system.

**alvations/pywsd** — Python Implementations of Word Sense Disambiguation (WSD) Technologies.

- Repository: https://github.com/alvations/pywsd
- Stars: 748 · Forks: 130
- Language: Python
- License: MIT
- Published: 2026-09-17 · Updated: 2026-09-17 · Language: en
- Canonical page: https://hysenlabs.com/projects/alvations-pywsd

## What problem pywsd solves, and who it is for

Most WSD research code is published as one-off scripts tied to a specific Senseval or SemEval run. pywsd takes the opposite approach: it collects the classical algorithms under one importable package. The README lists Lesk algorithms (Original Lesk from 1986, Adapted/Extended Lesk from Banerjee and Pedersen, Simple Lesk, Cosine Lesk), maximum similarity metrics (path, Wu-Palmer, Leacock-Chodorow, Resnik, Jiang-Conrath, Lin) and three baselines (random sense, first WordNet sense, highest lemma counts).

The audience is narrow and worth naming. This is for people who need a working WSD call inside a script today, or who need to compare a new method against a Lesk baseline. It is not for building a production sense tagger: the README's own list contains no supervised or neural model, and the classifiers section in pyproject.toml marks the project as Development Status 4 - Beta.

## How pywsd works: WordNet lookups, signatures and similarity metrics

The mechanism is dictionary overlap. For a target word and a part of speech, pywsd enumerates the candidate synsets in WordNet, builds a context signature for each candidate, and scores the overlap against the sentence context. Simple Lesk builds signatures from definitions, examples and lemma names; Cosine Lesk replaces raw overlap counts with cosine similarity. The README states that signatures are computed on demand and memoized with functools.lru_cache, so repeated calls in the same process are essentially free.

The similarity branch is separate. Maximum similarity picks the sense whose synset is most similar to the senses of the surrounding words, and the metric is selectable. Path, Wu-Palmer and Leacock-Chodorow are graph-based; Resnik, Jiang-Conrath and Lin use information content. The README says the IC files are bundled with the package (Brown plus Wikipedia, computed against oewn:2024), so those metrics work without extra downloads.

One design decision has downstream consequences. The library targets Open English WordNet oewn:2024, so synsets are identified as oewn-<offset>-<pos>, not the familiar PWN 3.0 form bank.n.01. The README tells readers to use synset.lemmas(), .definition() and .pos for human-readable attributes. If your code or your annotation files are keyed on PWN 3.0 sense keys, that mismatch is your problem to solve, not the library's.

## Installing pywsd and running a first disambiguation

The install is a single pip command. The README states the project requires Python 3.10 or newer; Python 2 users are told the last supported release is pywsd==1.1.7.

```bash
pip install -U pywsd
```

On first use pywsd auto-downloads the Open English WordNet oewn:2024 via the wn package into ~/.wn_data/. If you would rather fetch it ahead of time, the README gives this command.

```bash
python -c "import wn; wn.download('oewn:2024')"
```

A first real call is the classic bank example. Pass the sentence, the target word and the POS tag.

```python
>>> from pywsd.lesk import simple_lesk
>>> sent = 'I went to the bank to deposit my money'
>>> answer = simple_lesk(sent, 'bank', pos='n')
>>> answer
Synset('oewn-08437235-n')
>>> answer.definition()
'a financial institution that accepts deposits and channels the money into lending activities'
```

For whole sentences, disambiguate returns a list of (token, synset) pairs, with None for tokens it does not tag. The README shows function words such as I, to, the and my coming back as None. To switch the metric, pass a different algorithm and similarity option.

```python
>>> from pywsd import disambiguate
>>> from pywsd.similarity import max_similarity as maxsim
>>> disambiguate('I went to the bank to deposit my money',
...              algorithm=maxsim, similarity_option='wup', keepLemmas=True)
```

## Where pywsd breaks down: no training, no rollback, no guarantees

The honest limitation is accuracy. Lesk-style overlap is a knowledge-based heuristic; it has no learned weights and no sense-annotated training data behind it. The README's own algorithm table lists Enhanced Lesk (Basile et al. 2014) as a wishlist item, which is a fair summary of where the library stops. If your task needs state-of-the-art sense accuracy on a benchmark, pywsd is the wrong tool, and the README does not claim otherwise.

There is a second, more mundane failure mode. The first call needs the oewn:2024 data, and the README says pywsd downloads it to ~/.wn_data/ on first use. In an offline build, a container without a writable home directory, or a CI job with no network, that implicit download is where the run fails. Pre-downloading with wn.download is the documented workaround, but it has to be wired into your image or pipeline deliberately.

A third gap is documentation of change. The repository has a CHANGELOG.md and a Benchmark.md at the top level, but the README does not document rollback, deprecation policy, or what happens to code written against older PWN-style identifiers. Treat the oewn:2024 identifier format as a hard boundary in your own code, and pin the version you depend on.

## pywsd against NLTK's own Lesk implementation

The closest alternative is NLTK itself, which ships nltk.wsd.lesk and the WordNet similarity functions that pywsd builds on. The difference is breadth and packaging, not a different algorithm family. NLTK gives you one Lesk function plus the raw similarity measures; pywsd gives you Original, Adapted, Simple and Cosine Lesk side by side, a max_similarity driver that scores a whole sentence, and the three baselines in pywsd.baseline. Note that pywsd depends on nltk>=3.8 and wn>=1.0,<2, so you are not choosing between them: installing pywsd pulls NLTK in.

If you already have an NLTK pipeline and only need one Lesk call, adding pywsd buys you the extra variants and the disambiguate wrapper. If you need supervised WSD, neither library is the answer, and you should look at a trained model or a transformer-based sense inventory instead. The choice here is between a small set of readable heuristics and a model you train yourself.

## Maintenance, licence and the cost of upgrading

The repository is not archived, and the last push was on 2026-04-18, roughly five months before this writing. That is recent enough that the project has not been abandoned, but the README does not state a release cadence, and no releases were retrieved for this review, so you should not read the push date as a promise of ongoing support.

The declared version in pyproject.toml is 1.3.0, and the classifiers cover Python 3.10 through 3.14. The declared dependency range is narrow in one place: wn>=1.0,<2. That upper bound means a future wn 2.x will not be picked up automatically, which is good for stability and bad if you need a fix that only lands there. The IC data is bundled as pywsd/data/*.pkl, so upgrading the package can change the bundled frequency data as well as the code.

The licence is MIT, declared both in pyproject.toml and in the LICENSE.md file at the repository root. MIT is permissive: it allows commercial and closed-source use, and it requires preserving the copyright notice and licence text. If you redistribute pywsd inside a product, keep the licence file with it. That is a description of the terms, not legal advice; your counsel decides what your distribution actually needs.

## Conclusion

Adopt pywsd if you need a readable, dependency-light implementation of Lesk or WordNet similarity for teaching, prototyping or as a baseline in an experiment, and you are comfortable with OEWN 2024 synset identifiers. Do not adopt it if you need supervised, corpus-trained WSD accuracy or stable PWN 3.0 style sense keys. Before committing, verify that the bundled IC files and the wn auto-download work in your offline or air-gapped environment, and check how your downstream code handles oewn-<offset>-<pos> identifiers.

## FAQ

### What does word sense disambiguation (WSD) mean?

WSD is the task of deciding which sense of a word is intended in a given context, for example choosing the financial sense of bank in a sentence about deposits. pywsd implements several classical approaches to that task, including Lesk variants and maximum similarity.

### Which WSD algorithms does pywsd include?

The README lists Original Lesk, Adapted/Extended Lesk, Simple Lesk and Cosine Lesk, plus maximum similarity metrics (path, Wu-Palmer, Leacock-Chodorow, Resnik, Jiang-Conrath, Lin) and three baselines: random sense, first WordNet sense and highest lemma counts.

### How do I install pywsd?

Install it with pip install -U pywsd. It requires Python 3.10 or newer, and on first use it auto-downloads Open English WordNet oewn:2024 into ~/.wn_data/ through the wn package.

### Why does pywsd return synsets like oewn-08437235-n instead of bank.n.01?

The library targets Open English WordNet 2024, so synsets use the oewn-<offset>-<pos> form rather than the PWN 3.0 form. The README suggests using synset.lemmas(), .definition() and .pos when you need readable output.

## Sources

- [alvations/pywsd on GitHub](https://github.com/alvations/pywsd)
- [Issues](https://github.com/alvations/pywsd/issues)
- [License: MIT](https://github.com/alvations/pywsd/blob/master/LICENSE)
- [README](https://github.com/alvations/pywsd/blob/master/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/alvations-pywsd
