Analyzer¶
Analyzer(path=None)
Morphological analyzer: for a word form it finds all analyses in a dictionary built from Wiktionary - the lemma, the part of speech and the Universal Dependencies features - and orders them by probability. A token that the dictionary does not have gets the analyses of rules, and an unknown lowercase word is guessed. The dictionary is loaded when the analyzer is created.
Exceptions:
FileNotFoundError- the dictionary file does not exist;OSError- the dictionary file cannot be read: no access, the path points to a directory, a pipe or a device;ValueError- the file is not an esMorph dictionary or is damaged, the path has a NUL character;TypeError- a path that is neither a string norPathLike.
from esmorph import Analyzer
morph = Analyzer()
morph.analyze("hablamos")[0]
Analysis(word='hablamos', lemma='hablar', pos='VERB', feats={'Mood': 'Ind', 'Number': 'Plur', 'Person': '1', 'Tense': 'Pres', 'VerbForm': 'Fin'}, prob=0.978261, words=('hablamos',), source='dictionary')
Parameters¶
| Parameter | Type | Default | Description |
|---|---|---|---|
path |
str / PathLike |
None |
Path to the dictionary file; by default, the dictionary of the package |
The object keeps the absolute dictionary path in path of type Path, read-only. The dictionary file is mapped into memory, so processes with the same file share its memory. While an analyzer exists, the file must not be overwritten in place, but it can be replaced with a new file; on Windows an open file can be neither replaced nor deleted. A dictionary is trusted data, like code: loading rejects a damaged file but not every deliberately crafted one, so dictionaries from untrusted sources should not be loaded.
Methods¶
Analyses of a word form¶
analyze(word)
Analyses of the word form, the most probable first; the probabilities sum to 1. Case does not matter for finding the word in the dictionary, though a token with a capital letter may also be a name, and a word absent as written is looked for without its accents and with a lost diaeresis (spelling). A verb with enclitic pronouns is analyzed as its verb (clitics), a token that the dictionary does not have - a sign, a number, a name - by rules, and an unknown lowercase word is guessed. A token that nothing analyzes - with a space or a control character, a lowercase word without a sample such as qzxw - has no analyses.
| Parameter | Type | Default | Description |
|---|---|---|---|
word |
str |
- | Word form |
Exceptions:
TypeError- a word that is not a string.
[(a.lemma, a.pos, round(a.prob, 3)) for a in morph.analyze("casa")]
[(a.lemma, a.source) for a in morph.analyze("zumbeábamos")][:1]
[('casa', 'NOUN', 0.986), ('casar', 'VERB', 0.013), ('casar', 'VERB', 0.0)]
[('zumbear', 'guess')]
Analyses of a list of word forms¶
analyze_many(words)
Analyses of every word form, as with analyze.
| Parameter | Type | Default | Description |
|---|---|---|---|
words |
Iterable[str] |
- | Word forms: a list, a tuple, a generator |
Exceptions:
TypeError- a string or bytes instead of a collection of words, a word that is not a string.
[len(analyses) for analyses in morph.analyze_many(["el", "gato", "come"])]
[2, 1, 2]
Lemmatization¶
lemmatize(words)
Lemmas of the most probable analyses of the word forms; a token without analyses comes back in lower case. Equal lemmas are one string object, so the lemmas of a large text take little memory; the method releases the GIL.
| Parameter | Type | Default | Description |
|---|---|---|---|
words |
Iterable[str] |
- | Word forms: a list, a tuple, a generator |
Exceptions:
TypeError- a string or bytes instead of a collection of words, a word that is not a string.
morph.lemmatize(["Los", "niños", "cantaban", "canciones"])
['el', 'niño', 'cantar', 'canción']
Word form in the dictionary¶
is_known(word)
Whether the dictionary has the word form, as written or as a verb of the dictionary with clitics; as with analyze, case and lost accents do not matter. Tokens analyzed by rules and guessed words are not in the dictionary.
| Parameter | Type | Default | Description |
|---|---|---|---|
word |
str |
- | Word form |
Exceptions:
TypeError- a word that is not a string.
morph.is_known("Gatos"), morph.is_known("zumbeábamos")
(True, False)
Dictionary¶
The dictionary of the package is built from the English Wiktionary of October 2026: 676 thousand word forms of 117 thousand lexemes. Symbols of units (km, kg) come from a table of their own, and determiners, pronouns, prepositions, conjunctions and numerals in words from a table after the treebank UD Spanish AnCora, whose conventions the lemmas and features follow (Word analysis). The probabilities of analyses come from the training parts of UD Spanish AnCora and UD Spanish GSD; word forms they do not have get their order by their ending and the most common features. The dictionary is distributed under the CC BY-SA 4.0 license.
Threads and processes¶
One analyzer can be used from several threads. lemmatize releases the GIL, so threads speed it up. analyze_many creates the analyses as Python objects, so threads speed it up little on any Python, the free-threaded 3.14t included: for a large text, lemmatize or processes are faster. The analyzer and analyses are pickled, so they work with multiprocessing and joblib: processes share the dictionary mapped into memory. Pickling an analysis costs more than finding it, so workers that return lemmas or tuples of fields are faster than workers that return analyses. A pickle keeps the absolute path of the dictionary file (none for the dictionary of the package) and the place of the analysis in the tables of that dictionary, which is looked up anew only with another dictionary: unpickling loads each dictionary once per process, so analyses unpickled one by one share one analyzer, an analysis whose dictionary file is gone takes the dictionary of the package, and a damaged file raises ValueError. An analysis that the dictionary does not have, as one pickled with another version of it, keeps its fields, but forms() gives an empty list and inflect raises FormNotFoundError.
from concurrent.futures import ThreadPoolExecutor
texts = [["los", "niños", "cantaban"], ["el", "gato", "come"]]
with ThreadPoolExecutor(2) as pool:
lemmas = list(pool.map(morph.lemmatize, texts))
lemmas
[['el', 'niño', 'cantar'], ['el', 'gato', 'comer']]