Componentes¶
StatsComponent(nlp, name)
La base de los componentes de spaCy que ponen las estadísticas de un texto en una extensión de Doc: un componente registra la extensión al añadirse a un pipeline y pone las estadísticas de cada documento en doc._.<name>. La escritura de componentes en general se describe en la documentación de spaCy.
Los componentes de esTS son subclases del StatsComponent del núcleo anyTS, una por cada clase de estadísticas.
Nota
Los ejemplos de abajo usan el modelo es_core_news_sm, que se instala aparte: python -m spacy download es_core_news_sm (véase instalación).
import ests
import spacy
nlp = spacy.load("es_core_news_sm")
nlp.add_pipe("ests_basic", name="basic")
doc = nlp("El gato duerme en la ventana. Los niños juegan en el parque.")
doc._.basic.n_words, doc._.basic.c_letters
nlp("?!")._.basic is None
(12, {2: 5, 3: 1, 4: 1, 5: 1, 6: 3, 7: 1})
True
Parámetros¶
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
nlp |
Language |
- | Pipeline al que se añade el componente |
name |
str |
- | Nombre del componente en el pipeline y de la extensión |
spaCy fija ambos en nlp.add_pipe(factory, name=...); los demás parámetros de un componente se pasan en el diccionario config de la misma llamada.
Nombres¶
Las fábricas llevan el prefijo de la biblioteca: ests_basic, ests_readability, ests_unadapted_readability, ests_diversity, ests_morph, ests_syntax, ests_cohesion, ests_lexical, ests_style, ests_phon, ests_verse, y el componente de los límites de oración ests_blank_lines. Están declaradas como entry points de spacy_factories, así que un pipeline guardado con estos componentes (nlp.to_disk(path), spacy package) se carga con spacy.load(path) sin importar la biblioteca. import ests no carga los componentes mientras spaCy no está cargado - los hallan los puntos de entrada, y ests.StyleStatsComponent los carga al usarlo por primera vez; desde las fuentes sin el paquete instalado, import ests.components va antes de add_pipe.
El nombre del paso del pipeline es el nombre de la extensión: nlp.add_pipe(factory, name="basic") pone las estadísticas en doc._.basic. Sin name ambos toman el nombre de la fábrica. La extensión sigue al paso cuando el pipeline lo renombra (nlp.rename_pipe). Un nombre ocupado por una extensión de otro paquete lanza ParameterError en lugar de reemplazarla: en add_pipe, o con el primer documento después de rename_pipe, que renombra el paso antes de que el componente conozca su nombre. Un componente tomado de otro pipeline (add_pipe(name, source=other)) es el mismo objeto en ambos, así que con un nombre nuevo escribe también en esa extensión del otro pipeline; un componente independiente sale de la fábrica, add_pipe(factory, name=...). El mismo componente puede añadirse dos veces con nombres distintos, con parámetros distintos. Un documento sin palabras - una cadena vacía, espacios, pura puntuación - pasa por un componente sin cambios, con su extensión en None.
En ests_lexical también pasa intacto un documento solo de números, y en ests_verse un documento sin letras.
Serialización
Un componente guarda un objeto de estadísticas en doc._.<name>, y spaCy no sabe serializarlo: Doc.to_bytes(), DocBin(store_user_data=True) y nlp.pipe(..., n_process>1) fallan con estos componentes en el pipeline. Para guardar un documento, deje fuera los datos de usuario (doc.to_bytes(exclude=["user_data"])) o guarde doc._.<name>.get_stats() por separado; para el multiproceso, calcule las estadísticas en el proceso principal después de nlp.pipe, sin los componentes.
Añadir un componente amplía el tokenizador de su pipeline con las reglas de las rayas de un diálogo pegadas a las palabras y de las abreviaturas en cualquier caja (add_dash_rules), como en la API de cadenas: sí--dijo son dos palabras y una raya, SR. una palabra. Un tokenizador que no es el Tokenizer de spaCy se queda como está.
Componentes de las clases de estadísticas¶
| Componente | Fábrica | Clase de estadísticas | Parámetros |
|---|---|---|---|
BasicStatsComponent |
ests_basic |
BasicStats |
- |
ReadabilityStatsComponent |
ests_readability |
ReadabilityStats |
preset, basic |
UnadaptedReadabilityStatsComponent |
ests_unadapted_readability |
UnadaptedReadabilityStats |
basic |
DiversityStatsComponent |
ests_diversity |
DiversityStats |
window_len, mtld_threshold, mtld_min_len, hdd_sample_size, log_base |
MorphStatsComponent |
ests_morph |
MorphStats |
- |
SyntaxStatsComponent |
ests_syntax |
SyntaxStats |
- |
CohesionStatsComponent |
ests_cohesion |
CohesionStats |
blank_lines |
LexicalStatsComponent |
ests_lexical |
LexicalStats |
data_dir |
StyleStatsComponent |
ests_style |
StyleStats |
stopwords, top_n, nausea_stopwords, cliches |
PhonStatsComponent |
ests_phon |
PhonStats |
window_len |
VerseStatsComponent |
ests_verse |
VerseStats |
seseo |
Las estadísticas básicas, de legibilidad, de diversidad, fonéticas y del verso y las fórmulas de otros idiomas no necesitan ninguna anotación de un modelo. En el pipeline de es_core_news_sm las categorías gramaticales vienen del morphologizer (o de un tagger con un attribute_ruler; un tagger solo no las da), el análisis del parser y los lemas del lemmatizer. Un componente al que le falta la anotación, también con componentes excluded, lanza SourceError cuando el documento pasa por él; ests_lexical solo necesita las categorías gramaticales, y ests_style lanza el error cuando se lee verbal_nouns o markers().
Estadísticas básicas¶
BasicStatsComponent(nlp, name)
BasicStatsComponent pone las estadísticas básicas de un documento en su extensión.
Métricas de legibilidad¶
ReadabilityStatsComponent(nlp, name, preset=None, basic=None)
ReadabilityStatsComponent pone en la extensión las métricas de legibilidad, calculadas sobre el documento o, con basic, sobre las estadísticas básicas que otro componente puso en él. Una biblioteca fija basic_factory, la fábrica de su componente de las estadísticas básicas, que el error nombra cuando esa extensión no las tiene.
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
preset |
str |
None |
Preajuste de los coeficientes, uno de los preajustes de la clase; el de la clase por defecto si es None |
basic |
str |
None |
Extensión de un componente de las estadísticas básicas que se reutilizan en lugar de calcularlas otra vez |
Con preset en None la configuración de un pipeline guardado no lleva preajuste, y el pipeline toma el de la clase por defecto al cargarse; una biblioteca que quiere su valor por defecto escrito en la configuración lo da en la firma de su subclase.
Excepciones:
ParameterError- unastats_classque no es concreta, un preajuste que no es una cadena o no es de la clase, una extensión no nombrada por una cadena;SourceTypeError- una clase sinbasic_stats_classy sinbasic;SourceError- un documento cuya extensiónbasicno tiene estadísticas básicas de la clase.
Los preajustes de esTS son general y classic, el de la clase general. En esTS la clase de estadísticas y su basic_stats_class están fijadas, así que los errores de stats_class y SourceTypeError no se dan. El componente nombrado por basic va antes que este en el pipeline; el mensaje de SourceError nombra el componente ests_basic (basic_factory) que hay que añadir allí.
nlp.add_pipe("ests_readability", name="readability")
config = {"preset": "classic", "basic": "basic"}
nlp.add_pipe("ests_readability", name="readability_classic", config=config)
doc = nlp("El gato duerme en la ventana. Los niños juegan en el parque.")
round(doc._.readability.flesch_reading_easy, 2)
round(doc._.readability_classic.flesch_reading_easy, 2)
102.19
105.72
Fórmulas de otros idiomas¶
UnadaptedReadabilityStatsComponent(nlp, name, basic=None)
UnadaptedReadabilityStatsComponent pone en la extensión las fórmulas de legibilidad de otros idiomas, calculadas sobre el documento o, con basic, sobre las estadísticas básicas que otro componente puso en él. Una biblioteca fija basic_factory, como para ReadabilityStatsComponent.
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
basic |
str |
None |
Extensión de un componente de las estadísticas básicas que se reutilizan en lugar de calcularlas otra vez |
Excepciones:
ParameterError- unastats_classque no es concreta, una extensión no nombrada por una cadena;SourceTypeError- una clase sinbasic_stats_classy sinbasic;SourceError- un documento cuya extensiónbasicno tiene estadísticas básicas de la clase.
Las fórmulas son las de UnadaptedReadabilityStats, con sus propios coeficientes y sin calibración para el español. Como en ReadabilityStatsComponent, los errores de stats_class y SourceTypeError no se dan en esTS, y el mensaje de SourceError nombra el componente ests_basic que hay que añadir antes que este.
nlp.add_pipe("ests_unadapted_readability", name="unadapted", config={"basic": "basic"})
doc = nlp(
"El gato estaba en la ventana y miraba a los pájaros que volaban "
"sobre los tejados de las casas."
)
doc._.unadapted.gulpease, doc._.unadapted.forcast
doc._.unadapted.bs is doc._.basic
(64.78947368421052, 12.105263157894736)
True
Métricas de diversidad léxica¶
DiversityStatsComponent(nlp, name, window_len=50, mtld_threshold=0.72, mtld_min_len=10, hdd_sample_size=42, log_base=10)
DiversityStatsComponent pone en la extensión las métricas de diversidad léxica, mediante una clase de la biblioteca que lee un Doc. Sus parámetros son los de DiversityStats, con los mismos valores por defecto.
Excepciones:
ParameterError- un parámetro erróneo (check_paramsde la diversidad).
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
window_len |
int |
50 |
Tamaño de la ventana de MATTR y del segmento de MSTTR |
mtld_threshold |
float |
0.72 |
Umbral de TTR para MTLD, MA-MTLD y MTLD-W |
mtld_min_len |
int |
10 |
Longitud mínima del factor para MTLD, MA-MTLD y MTLD-W |
hdd_sample_size |
int |
42 |
Tamaño de la muestra de HD-D |
log_base |
float |
10 |
Base del logaritmo de las métricas de Summer, Maas y Dugast |
config = {"window_len": 100, "log_base": 2.718281828459045}
nlp.add_pipe("ests_diversity", name="diversity", config=config)
doc = nlp("El gato duerme en la ventana. Los niños juegan en el parque.")
round(doc._.diversity.ttr, 3), round(doc._.diversity.sttr, 3)
(0.833, 0.916)
Estadísticas morfológicas¶
MorphStatsComponent(nlp, name)
MorphStatsComponent pone las estadísticas morfológicas en la extensión; por defecto necesitan las categorías gramaticales antes de él.
En esTS el pipeline necesita además un lemmatizer antes del componente; la fábrica requiere token.pos y token.lemma, así que nlp.analyze_pipes() señala un pipeline sin alguno de ellos.
Excepciones:
SourceError- un documento sin las categorías gramaticales o sin los lemas.
nlp.add_pipe("ests_morph", name="morph")
doc = nlp("El gato duerme en la ventana. Los niños juegan en el parque.")
doc._.morph.pos[:4]
('DET', 'NOUN', 'VERB', 'ADP')
Estadísticas sintácticas¶
SyntaxStatsComponent(nlp, name)
SyntaxStatsComponent pone las estadísticas sintácticas en la extensión; necesitan un parser y las categorías gramaticales antes de él.
En esTS necesitan también un lemmatizer antes de él; la fábrica requiere token.dep, token.head, token.pos y token.lemma, así que nlp.analyze_pipes() señala un pipeline sin alguno de ellos.
Excepciones:
SourceError- un documento sin análisis de dependencias, sin las categorías gramaticales o sin los lemas.
nlp.add_pipe("ests_syntax", name="syntax")
doc = nlp("El gato duerme en la ventana. Los niños juegan en el parque.")
doc._.syntax.tree_depth, doc._.syntax.mean_dependency_distance
(2.0, 1.6)
Estadísticas de cohesión¶
CohesionStatsComponent(nlp, name, blank_lines=False)
CohesionStatsComponent pone las estadísticas de cohesión en la extensión; por defecto necesitan las categorías gramaticales y los lemas antes de él. Con blank_lines los párrafos empiezan solo tras las líneas en blanco, como en CohesionStats, para un texto con líneas cortadas dentro de sus párrafos.
Excepciones:
ParameterError- unblank_linesque no es unbool.
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
blank_lines |
bool |
False |
Empezar los párrafos solo tras las líneas en blanco, para un texto con líneas cortadas dentro de sus párrafos; por defecto, tras cada salto de línea |
En el pipeline de es_core_news_sm las categorías gramaticales y los lemas vienen del morphologizer y del lemmatizer; la fábrica requiere token.pos y token.lemma, así que nlp.analyze_pipes() señala un pipeline sin alguno de ellos, y un documento sin ellos lanza SourceError. Los textos de SpanishLiterature tienen las líneas cortadas dentro de sus párrafos y necesitan blank_lines.
nlp.add_pipe("ests_cohesion", name="cohesion")
nlp.add_pipe("ests_cohesion", name="paragraphs", config={"blank_lines": True})
doc = nlp("El informe fue aprobado. Sin embargo, el informe\nno resuelve el problema.")
(
doc._.cohesion.noun_overlap_adjacent,
round(doc._.cohesion.connectors, 2),
doc._.cohesion.n_paragraphs,
doc._.paragraphs.n_paragraphs,
)
(1.0, 83.33, 2, 1)
Estadísticas de complejidad léxica¶
LexicalStatsComponent(nlp, name, data_dir=None)
LexicalStatsComponent pone en la extensión las estadísticas de complejidad léxica, con el diccionario de frecuencias de su atributo freq_dict: None por defecto, para el diccionario de la clase, y fijado por una biblioteca en el constructor de su componente. Un documento recibe las estadísticas cuando tiene una palabra de iter_doc_words (con join_hyphens) que no es un número del método is_number, anyts.utils.is_number por defecto; una biblioteca da los números que su clase deja fuera, así que un documento solo de números pasa intacto.
En esTS freq_dict es el diccionario de frecuencias FreqDict del directorio data_dir, e is_number toma los números del NUMBER_PATTERN del español (2020, 1.500,50, 3.º). El pipeline necesita un morphologizer antes del componente, y la fábrica requiere token.pos; los lemas del modelo no se usan. Las bandas de frecuencia y la densidad léxica se calculan sin el diccionario, las estadísticas por el diccionario lo necesitan descargado.
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
data_dir |
str |
None |
Directorio del diccionario de frecuencias; el de por defecto si no se indica |
Excepciones:
SourceError- un documento sin las categorías gramaticales;DatasetNotFoundError- las estadísticas por el diccionario yget_stats()cuando el diccionario no está descargado;ConfigValidationErrorde spaCy - undata_dirque no es una cadena, enadd_pipe.
nlp.add_pipe("ests_lexical", name="lexical")
doc = nlp("El felinólogo examinaba al minino con parsimonia.")
round(doc._.lexical.coverage, 3), round(doc._.lexical.p_top1000, 3)
nlp("2020 1.500,50 3.º")._.lexical is None
(0.857, 0.429)
True
Métricas de estilo¶
StyleStatsComponent(nlp, name, stopwords=None, top_n=10, nausea_stopwords=None, cliches=None)
StyleStatsComponent pone las métricas de estilo en la extensión.
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
stopwords |
list[str] |
None |
Palabras vacías del contenido de agua; las de la clase si es None |
top_n |
int |
10 |
Número de las palabras más frecuentes de la náusea académica y de la naturalidad según la ley de Zipf (NAUSEA_TOP_N) |
nausea_stopwords |
list[str] |
None |
Palabras que se dejan fuera de las palabras más frecuentes de la náusea académica; las de la clase si es None |
cliches |
list[str] |
None |
Clichés; los de la clase (cliches_list) si es None |
Excepciones:
SourceTypeError- palabras vacías, palabras vacías de la náusea o clichés que no son una lista de cadenas;ParameterError- untop_nque no es un entero de al menos uno.
Sin las listas, el contenido de agua toma las palabras vacías de STOPWORDS y las expresiones parentéticas de una palabra, la náusea académica deja fuera las palabras de is_stopword, y los clichés vienen de OFFICIALESE_CLICHES; NAUSEA_TOP_N es una constante de anyts.constants. Los sustantivos deverbales necesitan un morphologizer y un lemmatizer antes del componente, y sin ellos leer verbal_nouns, markers() o get_stats() lanza SourceError; las demás métricas solo leen las palabras.
nlp.add_pipe("ests_style", name="style")
doc = nlp("Se procedió a la revisión del expediente a la mayor brevedad.")
round(doc._.style.cliches, 2), round(doc._.style.verbal_nouns, 2)
nlp.add_pipe("ests_style", name="style_cliches", config={"cliches": ["se procedió a"]})
doc = nlp("Se procedió a la revisión del expediente a la mayor brevedad.")
round(doc._.style_cliches.cliches, 2)
(18.18, 33.33)
9.09
Fonoestadística¶
PhonStatsComponent(nlp, name, window_len=3)
PhonStatsComponent pone las estadísticas fonéticas en la extensión; window_len (PHON_WINDOW_LEN por defecto) es la ventana en palabras de la aliteración y la asonancia.
Excepciones:
ParameterError- unwindow_lenque no es un entero de al menos 2.
nlp.add_pipe("ests_phon", name="phon", config={"window_len": 5})
doc = nlp("Tres tristes tigres tragaban trigo en un trigal")
round(doc._.phon.hardness, 3), round(doc._.phon.alliteration, 3)
(0.458, 0.975)
Estadísticas del verso¶
VerseStatsComponent(nlp, name, seseo=False)
VerseStatsComponent pone las estadísticas del verso en la extensión. Las estadísticas leen los saltos de línea y las líneas en blanco del documento, así que pase el texto de un poema a nlp sin unir los versos; el componente no necesita ninguna anotación de un modelo. Un documento sin letras pasa intacto, y un texto con letras pero sin sílabas españolas da estadísticas vacías.
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
seseo |
bool |
False |
Pronunciar c y z ante e e i como s en la rima |
Excepciones:
ConfigValidationErrorde spaCy - unseseoque no es un booleano, enadd_pipe.
nlp.add_pipe("ests_verse", name="verse")
doc = nlp(
"Que por mayo era, por mayo,\ncuando hace la calor,\ncuando los trigos encañan\ny están los campos en flor,"
)
doc._.verse.meter, doc._.verse.c_clausulas
('octosílabo', {'aguda': 2, 'llana': 2})
Oraciones tras líneas en blanco¶
start_sents_after_blank_lines(doc)
Un componente que inicia una oración en el primer token tras una línea en blanco - un salto de línea, espacios opcionales y otro salto de línea -, para que un título, un elemento de una lista o un párrafo sin signo final sean una oración propia, como en el extractor de oraciones. Va antes del parser, senter o sentencizer, que conserva sus inicios y coloca los demás. Los espacios ante tal inicio se quedan con la oración anterior, y los signos que abren un párrafo (una raya de diálogo, ¡, «) se quedan con su primera palabra. Por sí solo, el componente no divide las oraciones dentro de un párrafo y fija límites parciales (has_sents), así que las estadísticas toman las oraciones de tal documento de su texto. Un documento ya analizado, como uno que vuelve a pasar por el pipeline, pasa intacto, porque spaCy conserva sus oraciones. Una biblioteca del idioma registra el componente con su prefijo, Language.component("<prefix>_blank_lines", func=start_sents_after_blank_lines).
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
doc |
Doc |
- | Objeto Doc |
En esTS el componente está registrado como ests_blank_lines. Sin él, el modelo es_core_news_sm pega un párrafo sin signo final a la oración siguiente, y las estadísticas de un Doc difieren de las de la misma cadena. El pipeline de ests.utils.get_nlp, que analiza las cadenas de las estadísticas morfológicas, sintácticas, de cohesión y léxicas, lo tiene antes del parser.
nlp = spacy.load("es_core_news_sm")
nlp.add_pipe("ests_blank_lines", before="parser")
doc = nlp("Novedades\n\nImportación rápida. Menos errores")
[sent.text.strip() for sent in doc.sents]
['Novedades', 'Importación rápida.', 'Menos errores']
Todo en un pipeline¶
Los once componentes pueden compartir un pipeline.
import ests
import spacy
nlp = spacy.load("es_core_news_sm")
nlp.add_pipe("ests_blank_lines", before="parser")
factories = (
"basic",
"readability",
"unadapted_readability",
"diversity",
"morph",
"syntax",
"cohesion",
"lexical",
"style",
"phon",
"verse",
)
for factory in factories:
nlp.add_pipe(f"ests_{factory}", name=factory)
doc = nlp("El gato duerme en la ventana. Los niños juegan en el parque.")
(
doc._.basic.n_words,
round(doc._.readability.flesch_reading_easy, 2),
round(doc._.unadapted_readability.gulpease, 2),
round(doc._.diversity.ttr, 3),
doc._.morph.pos[:2],
doc._.syntax.tree_depth,
doc._.cohesion.p_given,
round(doc._.lexical.p_top1000, 3),
round(doc._.style.water, 2),
round(doc._.phon.p_vowels, 3),
doc._.verse.n_lines,
)
(12, 102.19, 99.83, 0.833, ('DET', 'NOUN'), 2.0, 0.0, 0.667, 50.0, 0.457, 1)