Estadísticas de complejidad léxica¶
LexicalStats(source, freq_dict=None, nlp=None)
Complejidad léxica a la manera de TAALES (Kyle, Crossley y Berger, 2018) - cuán raras son las palabras de un texto: estadísticas según un diccionario de frecuencias y su modelo de unigramas, las proporciones de las bandas de frecuencia de una lista de los lemas más frecuentes y la densidad léxica. Las estadísticas según el diccionario se calculan la primera vez que se leen, así que las bandas y la densidad léxica no necesitan los datos del diccionario.
Excepciones:
SourceTypeError- un diccionario de otra clase que la de la biblioteca o, sinfreq_dict_class, uno sinlookupeipmo ninguno; unanalyzeque no da objetosLexicalWord;SourceError- una fuente sin palabras.
En esTS una fuente que no es ni una cadena ni un Doc y un pipeline en nlp que no es un Language de spaCy también lanzan SourceTypeError; una fuente sin las categorías gramaticales, una cadena más larga que el max_length del pipeline y una cadena con un carácter sin forma UTF-8, SourceError; y las métricas según el diccionario sin el diccionario descargado, DatasetNotFoundError.
A diferencia de las métricas de diversidad léxica, que comparan las palabras de un texto entre sí, aquí las palabras se comparan con las frecuencias de la lengua (TAALES). La fuente de datos es un texto o un objeto Doc de la biblioteca spaCy.
La clase extiende el LexicalStats del núcleo anyTS con la capa del español: el diccionario es el FreqDict de Google Books Ngram (freq_dict_class), y las posiciones de los lemas y el tamaño de la lista (rank, top_size) salen de la lista integrada de sus 10 000 lemas más frecuentes (get_rank). Si una palabra es un nombre propio, y si es una palabra con contenido, sale de la anotación, así que la fuente tiene que estar anotada: una cadena se analiza con es_core_news_sm o con el pipeline pasado en nlp, sin el parser, el lematizador ni las entidades nombradas, y un Doc debe llevar las categorías gramaticales (un morphologizer, o un tagger con un attribute_ruler). Los números (2020, 5,5, 3.º) no son palabras. Los lemas salen de lemma_key, el lema de simplemma en minúsculas, no del modelo; un nombre propio conserva su forma en minúsculas. Una palabra con contenido se define como en CohesionStats: una de CONTENT_UD_POS (sustantivos, nombres propios, adjetivos, verbos, adverbios) y no demostrativa. La tabla de print_stats lleva las descripciones de LEXICAL_STATS_DESC de ests.constants, con el rango en años de 40.
El max_length del pipeline es de un millón de caracteres por defecto: divida un texto más largo en partes, o suba max_length en un pipeline propio y páselo en nlp.
from ests import LexicalStats
from ests.datasets import FreqDict
FreqDict().download()
ls = LexicalStats("El gato estaba en la ventana y miraba a los pájaros")
ls.print_stats()
Statistic | Value
------------------------------------------------------------
Share of words found in the frequency dictionary | 1.00
Mean frequency (ipm) | 34283.75
Mean frequency of content words (ipm) | 956.33
Mean log frequency (lg ipm) | 3.56
Mean log frequency of content words | 2.19
Mean range (years out of 40) | 40.00
Mean dispersion (D) | 97.64
Mean surprisal (bits) | 8.11
Unigram perplexity | 275.44
Share of words in the top 1000 | 0.73
Share of words in the top 2000 | 0.82
Share of words in the top 5000 | 1.00
Share of words in the top 10000 | 1.00
Share of words beyond the top 10000 | 0.00
Lexical density | 0.45
Parámetros¶
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
source |
str / Doc |
- | Fuente de datos |
freq_dict |
FreqDict |
None |
Diccionario de frecuencias; FreqDict() del directorio por defecto si no se indica |
nlp |
Language |
None |
Pipeline de spaCy que analiza una cadena; sin él se carga el modelo es_core_news_sm |
Atributos¶
| Atributo | Tipo | Descripción |
|---|---|---|
freq_dict |
FrequencyDictionary |
Diccionario de frecuencias |
words, lemmas |
tuple[str] |
Palabras y sus lemas; las bandas se cuentan por los lemas |
keys |
tuple[str] |
Claves de las palabras en el diccionario |
entries |
tuple[FrequencyEntry / None] |
Entradas del diccionario, None para una palabra fuera de él |
ranks |
tuple[int / None] |
Posiciones de los lemas, None fuera de la lista |
n_words, n_content_words, n_found |
int |
Número de palabras, de palabras con contenido y de palabras encontradas en el diccionario |
En esTS el diccionario es un FreqDict, y sus entradas son las tuplas con nombre Entry. Las claves de las palabras en el diccionario (keys, dictionary_keys) son sus lemas, y un nombre propio se busca por su forma cuando el diccionario la tiene (París como parís, no como el verbo parir) y por su lema si no (Estados de Estados Unidos como estado, un Miró a principio de oración etiquetado PROPN como mirar). Una palabra se busca sin el punto de una abreviatura (Sr. como sr, pág. como página); una inicial (D., J.) lo conserva y queda fuera del diccionario.
ls = LexicalStats("Miró desde París hacia los Estados Unidos")
ls.lemmas
ls.keys
('miró', 'desde', 'parís', 'hacia', 'el', 'estados', 'unidos')
('mirar', 'desde', 'parís', 'hacia', 'el', 'estado', 'unidos')
Métricas¶
Cada métrica es un atributo o una propiedad del objeto, y get_stats las da todas. Una media se toma sobre las palabras encontradas en el diccionario, y sin ellas es nan.
| Métrica | Qué mide | Rango | Un valor mayor indica |
|---|---|---|---|
coverage |
Proporción de las palabras encontradas en el diccionario | 0-1 | Más palabras conocidas por el diccionario |
mean_ipm, mean_ipm_content |
Frecuencia media por millón de palabras de las palabras encontradas, de las palabras con contenido encontradas | Más de 0 | Palabras más frecuentes |
mean_log_ipm, mean_log_ipm_content |
Media del logaritmo decimal de la frecuencia de las palabras encontradas, de las palabras con contenido encontradas | Hasta 6 | Palabras más frecuentes |
mean_range |
Rango medio de las palabras encontradas | 0 o más | Palabras usadas en más partes del corpus |
mean_dispersion |
Dispersión media de las palabras encontradas | La del diccionario | Según la medida del diccionario |
surprisal |
Sorpresa media de las palabras según el modelo de unigramas del diccionario, en bits | 0 o más | Palabras más raras |
perplexity |
2 elevado a la sorpresa | 1 o más | Palabras más raras |
p_top1000, p_top2000, p_top5000, p_top10000 |
Proporción de las palabras con un lema en el top 1000, 2000, 5000 y 10000 de la lista | 0-1, nan para una banda más allá de top_size |
Palabras más frecuentes |
p_beyond_top10000 |
Proporción de las palabras con un lema fuera del top 10000 | 0-1, nan para una lista de menos de 10000 |
Palabras más raras |
lexical_density |
Proporción de las palabras con contenido | 0-1 | Más palabras con contenido |
Las métricas se apoyan en dos recursos; lea siempre las medias según el diccionario junto a coverage.
| Recurso | Métricas | Disponibilidad |
|---|---|---|
FreqDict - 83 785 lemas de Google Books Ngram (1980-2019) con ipm, rango y dispersión |
coverage, mean_ipm*, mean_log_ipm*, mean_range, mean_dispersion, surprisal, perplexity |
se descarga una vez con FreqDict().download() |
La lista integrada de los 10 000 lemas más frecuentes del mismo diccionario (ests/resources/google_books_top10000.txt, CC BY 3.0) |
p_top1000, p_top2000, p_top5000, p_top10000, p_beyond_top10000, band_coverage |
siempre |
Frecuencia según el diccionario¶
Las métricas se calculan a partir de las entradas del FreqDict para las claves de las palabras (keys, entries): las medias se toman sobre las palabras encontradas en el diccionario, sobre todas ellas o solo sobre las palabras con contenido. El rango es el número de años, de 40 (1980-2019), en que el lema aparece en los libros, y la dispersión es la D de Juilland sobre los años, de 0 a 100. La frecuencia media en ipm es sensible a las palabras funcionales (el - 98 000 ipm, de - 71 000), así que para comparar textos conviene más la frecuencia logarítmica o la media sobre las palabras con contenido.
Las palabras raras bajan la cobertura y la frecuencia logarítmica y suben la sorpresa y la proporción fuera del top 10000:
from ests import LexicalStats
ls = LexicalStats("El felinólogo examinaba al minino con parsimonia")
ls.coverage, ls.mean_log_ipm, ls.surprisal, ls.p_beyond_top10000
(0.8571428571428571, 2.3529196195453976, 13.70650419215419, 0.4285714285714286)
Sorpresa y perplejidad¶
calc_surprisal(lemmas, freq_dict)
La sorpresa media de las palabras según el modelo de unigramas de un diccionario de frecuencias, en bits; una palabra fuera del diccionario recibe su frecuencia más baja min_ipm. La perplejidad es 2 elevado a ella.
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
lemmas |
list[str] |
- | Claves de las palabras en el diccionario |
freq_dict |
FrequencyDictionary |
- | Diccionario de frecuencias |
Sin palabras da nan; unas claves que no son una lista de cadenas y un diccionario sin ipm y min_ipm lanzan SourceTypeError, una frecuencia más baja que no es mayor que cero, ParameterError.
En esTS el diccionario es un FreqDict con la frecuencia más baja de 0,1 ipm: un diccionario de otra clase lanza SourceTypeError.
from ests.datasets import FreqDict
from ests.lexical_stats import calc_surprisal
calc_surprisal(["gato", "estar", "felinólogo"], FreqDict())
15.392368319318606
Bandas de frecuencia¶
La proporción de las palabras cuyo lema tiene una posición (rank) dentro del top \(N\) de la lista, para los límites 1000, 2000, 5000 y 10000 de FREQUENCY_BANDS; la proporción fuera del top 10000 es el resto, incluidas las palabras fuera de la lista. Una banda más allá del tamaño de la lista (top_size) es nan, y también la proporción fuera del top 10000 para una lista de menos de 10000.
Así se construye un perfil de bandas de frecuencia a la manera del Lexical Frequency Profile. Las bandas toman la forma en minúsculas de un nombre propio: un nombre propio cuya forma es un lema común recibe su posición (Gobierno 106), mientras que los nombres y sus partes flexionadas (Madrid, Estados) quedan fuera del top 10000, así que un texto lleno de nombres tiene una proporción mayor ahí.
get_rank(lemma)
La posición de un lema según la lista integrada, None para un lema fuera de la lista; el lema puede ir en cualquier caja.
| Parámetro | Tipo | Por defecto | Descripción |
|---|---|---|---|
lemma |
str |
- | Lema - la clave de lemma_key |
load_top_lemmas()
La lista entera del fichero ests/resources/google_books_top10000.txt, derivado de Google Books Ngram con licencia CC BY 3.0: la posición de cada lema, empezando por 1. La lista recoge los 10 000 lemas más frecuentes del diccionario de frecuencias por frecuencia decreciente, con las categorías gramaticales de un lema sumadas; deja fuera los nombres propios, las letras sueltas salvo las palabras del español a, e, o, u, y, á, é, ó, y los lemas de dos letras y los números romanos que simplemma no conoce (pp, xix), mientras que las abreviaturas de las referencias (cit) y las palabras inglesas de las bibliografías (the) se quedan.
from ests.lexical_stats import get_rank, load_top_lemmas
get_rank("el"), get_rank("gato"), get_rank("felinólogo")
len(load_top_lemmas())
(1, 2851, None)
10000
Densidad léxica¶
La proporción de palabras con contenido entre todas las palabras; una palabra con contenido es una de CONTENT_UD_POS (sustantivos, nombres propios, adjetivos, verbos, adverbios) y no demostrativa, como en CohesionStats, así que los auxiliares (es, ha) no son palabras con contenido.
Métodos¶
band_coverage(bands, unique) da la proporción de las palabras con un lema en el top N de la lista para cada límite N de bands (FREQUENCY_BANDS por defecto), o con unique=True la proporción de los lemas distintos. Unos límites que no son una lista de enteros o un límite fuera de 1 y top_size() lanzan ParameterError.
from ests import LexicalStats
ls = LexicalStats("El gato estaba en la ventana y miraba a los pájaros")
ls.band_coverage(unique=True)
ls.band_coverage(bands=(100, 500))
{1000: 0.6666666666666666, 2000: 0.7777777777777778, 5000: 1.0, 10000: 1.0}
{100: 0.6363636363636364, 500: 0.7272727272727273}
Los demás métodos, get_stats, to_dataframe, print_stats y describe, son los de la interfaz de estadísticas del núcleo anyTS; las estadísticas de complejidad léxica no tienen escalas, así que describe da None para las estadísticas de get_stats.
ls.get_stats()
{'coverage': 1.0,
'mean_ipm': 34283.74818181818,
'mean_ipm_content': 956.3320000000001,
'mean_log_ipm': 3.559971676175293,
'mean_log_ipm_content': 2.1916598821626314,
'mean_range': 40.0,
'mean_dispersion': 97.63636363636364,
'surprisal': 8.105598641234213,
'perplexity': 275.4408334528846,
'p_top1000': 0.7272727272727273,
'p_top2000': 0.8181818181818182,
'p_top5000': 1.0,
'p_top10000': 1.0,
'p_beyond_top10000': 0.0,
'lexical_density': 0.45454545454545453}