Skip to content

Phonostatistics

PhonStats(source, words_extractor=None, window_len=3)

The phonetic statistics of a text: its sounds by class, their clusters, sequences and repetitions, and its syllables. A sound is a letter of a word by default, or a sound of its transcription when a library gives one. The data source is a text or a Doc object of spaCy; the words are taken in lower case, and an extractor passed explicitly is used on the text of a Doc.

Raises:

  • SourceTypeError - a source that is neither a string nor a Doc, an extractor of another type;
  • SourceError - a source without words;
  • ParameterError - a window that is not an integer of at least 2.

Besides the errors above, a string with a character without a UTF-8 form raises SourceError from the Spanish tokenizer.

The class extends the PhonStats of the anyTS core with the sounds of Spanish. The sounds are those of the transcription of the words (transcribe), not their letters: ch, ll, rr and qu are one sound, h and the u of que and gui none, and x two. The pronunciation is the one of the standard of Spain: yeísmo (ll and y are one sound) and distinción (c before e and i and z are θ, apart from s). The classes of the sounds are the constants of ests.constants in the table below. The syllables are those of syllabify, by the orthographic rules, and a hiatus is two vowels in two neighbouring syllables of a word (po-e-ta, dí-a, bú-ho). The words of a string are extracted by the Spanish WordsExtractor; without an extractor the words of a Doc come from its tokens. No trained model is needed. The print_stats table has the English descriptions of the core, anyts.constants.PHON_STATS_DESC.

Class Sounds Constant
Vowels a, e, i, o, u VOWEL_SOUNDS
Sonorants m, n, ɲ (ñ), l, r (the tap and the trill are one sound) SONORANT_SOUNDS
Voiced obstruents b (b, v), d, g, ʝ (y, ll) VOICED_SOUNDS
Voiceless obstruents p, t, k (c, qu, k), f, θ (c, z), s, x (j, g), tʃ (ch) VOICELESS_SOUNDS
from ests import PhonStats

# The first stanza of Sonatina by Rubén Darío (Prosas profanas, 1896)
sonatina = (
    "La princesa está triste... ¿qué tendrá la princesa?\n"
    "Los suspiros se escapan de su boca de fresa,\n"
    "que ha perdido la risa, que ha perdido el color.\n"
    "La princesa está pálida en su silla de oro,\n"
    "está mudo el teclado de su clave sonoro;\n"
    "y en un vaso olvidada se desmaya una flor."
)
ps = PhonStats(sonatina)
ps.print_stats()
                 Statistic                 |  Value
------------------------------------------------------
Share of vowels                            |   0.46
Share of sonorant consonants               |   0.19
Share of voiced obstruents                 |   0.10
Share of voiceless obstruents              |   0.25
Ratio of consonants to vowels              |   1.19
Share of clusters of 3 consonants or more  |   0.01
Hiatuses per word                          |   0.00
Entropy of the CV patterns of words (bits) |   3.55
Hardness                                   |   0.39
Alliteration index                         |   0.87
Assonance index                            |   0.87
Share of open syllables                    |   0.74
Mean length of a syllable (sounds)         |   2.19

Parameters

Parameter Type Default Description
source str / Doc - Data source
words_extractor WordsExtractor None Word extraction tool; used for a Doc too, on its text
window_len int 3 Window in words of the alliteration and the assonance (PHON_WINDOW_LEN)

PHON_WINDOW_LEN is a constant of anyts.constants.

check_params(window_len, *, messages=MESSAGES)

Checks the window of the alliteration and the assonance: one that is not an integer of at least 2 raises ParameterError.

Attributes

Attribute Type Description
words tuple[str] Words in lower case
window_len int Window of the alliteration and the assonance
syllables, sounds tuple Syllables (syllabify) and sounds (transcribe) of every word
n_vowels, n_sonorants, n_voiced, n_voiceless, n_consonants int Numbers of the sounds by class
c_clusters dict[int, int] Number of the consonant clusters by length (consonant_clusters)
c_syllable_patterns dict[str, int] Number of the syllables by CV pattern
ps.syllables[:4]
ps.sounds[:2]
ps.c_clusters
ps.c_syllable_patterns
(('la',), ('prin', 'ce', 'sa'), ('es', 'tá'), ('tris', 'te'))
(('l', 'a'), ('p', 'r', 'i', 'n', 'θ', 'e', 's', 'a'))
{1: 66, 2: 21, 3: 1}
{'CCV': 4, 'CCVC': 5, 'CV': 60, 'CVC': 9, 'V': 5, 'VC': 10}

Transcription

transcribe(word)

Transcribes a word into its sounds, those PhonStats counts. The word is split into syllables (syllabify) and every syllable is read by the rules of the Spanish orthography; the characters that are no Spanish letters (digits, hyphens) are left out.

Spelling Sound Example
a, á; e, é; i, í; o, ó; u, ú, ü a, e, i, o, u canción - k a n θ i o n
h none; hi before a vowel at the start of a syllable is ʝ ahora - a o r a, hielo - ʝ e l o
ch tʃ hechizo - e tʃ i θ o
c before e, i; z θ cena - θ e n a
c elsewhere, qu before e, i, k k queso - k e s o
g before e, i; j x gente - x e n t e
g elsewhere, gu before e, i g guerra - g e r a
ll; y before a vowel ʝ calle - k a ʝ e
y at the end of a syllable i hoy - o i
r, rr r perro - p e r o
ñ ɲ niño - n i ɲ o
v b vaca - b a k a
x; x at the start of a word k s; s examen - e k s a m e n, xilófono - s i l o f o n o
w u whisky - u i s k i

The pronunciation is the one of the standard of Spain, with yeísmo and distinción. A rule reads the spelling of a word, not its history: the x of México is k s, as in examen.

Parameter Type Default Description
word str - Word

Raises:

  • SourceTypeError - a word that is not a string.
from ests.phon_stats import transcribe

transcribe("hechizo")
transcribe("guerrilla")
transcribe("examen")
('e', 'tʃ', 'i', 'θ', 'o')
('g', 'e', 'r', 'i', 'ʝ', 'a')
('e', 'k', 's', 'a', 'm', 'e', 'n')

Metrics

Every metric is an attribute of the object, computed when it is created, and get_stats gives them all.

Metric Measures Range Higher means
p_vowels Share of the vowels among the sounds of the classes 0-1, nan without sounds A more vocalic text
p_sonorants Share of the sonorants among the sounds of the classes 0-1, nan without sounds A more sonorous text
p_voiced Share of the voiced obstruents among the sounds of the classes 0-1, nan without sounds More voiced obstruents
p_voiceless Share of the voiceless obstruents among the sounds of the classes 0-1, nan without sounds More voiceless obstruents
consonant_vowel_ratio Ratio of the consonants to the vowels 0 and above, nan without vowels Denser consonants
p_heavy_clusters Share of the clusters of three consonants or more 0-1, nan without clusters Heavier clusters
p_hiatus Hiatuses of word_hiatus per word 0 and above, nan without sounds More vowels in a row
cv_entropy Shannon entropy of the CV patterns of the words, in bits 0 and above, nan without sounds More varied shapes of the words
hardness Voiceless obstruents to the vowels and the sonorants 0 and above, nan without vowels and sonorants A harder sound
alliteration Repetition index of the consonants in windows of window_len words 0 and above, nan for a text shorter than the window or with no consonant shared by two words Consonants repeated closer together
assonance Repetition index of the vowels in windows of window_len words 0 and above, nan for a text shorter than the window or with no vowel shared by two words Vowels repeated closer together
p_open_syllables Share of the syllables that end in a vowel 0-1, nan without syllables More open syllables
mean_syllable_len Mean length of a syllable in sounds 1 and above, nan without syllables Longer syllables

The functions of the cards are imported from ests.phon_stats; they take words as strings and count over the sounds of their transcription.

Shares of the classes of the sounds

p_vowels · p_sonorants · p_voiced · p_voiceless

The share of the sounds of every class - the vowels, the sonorants and the voiced and voiceless obstruents - among the sounds of all of them; a sound of skipped or of no class (a digit, a letter of another script) counts in none.

\[ \frac{\textrm{Number of sounds of the class}}{\textrm{Number of vowels and consonants}} \]

Ratio of the consonants to the vowels

consonant_vowel_ratio

The number of the consonants n_consonants to the number of the vowels n_vowels.

\[ \frac{\textrm{Number of consonants}}{\textrm{Number of vowels}} \]

Consonant clusters

p_heavy_clusters · c_clusters

calc_consonant_clusters(text)

The distribution of the consonant clusters of the words by length, the attribute c_clusters. A cluster is a run of consonant sounds inside a word, across the syllables, a single consonant between vowels or at the edge of a word included: instrumento has the clusters n s t r (4), m (1) and n t (2). The digraphs are one sound (calle, perro, chico), and x is two (extra - k s t r). p_heavy_clusters is the share of the heavy clusters:

\[ \frac{\textrm{Number of clusters of 3 consonants or more}}{\textrm{Number of clusters}} \]
Parameter Type Default Description
text list[str] - List of words

Raises:

  • SourceTypeError - words that are not a list of strings.
from ests.phon_stats import calc_consonant_clusters

calc_consonant_clusters(["instrumento", "calle"])
{1: 3, 2: 1, 4: 1}

Hiatuses

p_hiatus

calc_hiatus(text)

The number of hiatuses: two vowels next to each other in two syllables of a word, as syllabify splits them - po-e-ta, dí-a, le-er, a-é-re-o (two). A silent h between the vowels does not break the hiatus (bú-ho, a-ho-ra), and the vowels of a diphthong are one syllable and no hiatus (cie-lo, ciu-dad). p_hiatus is the number of hiatuses of the text per word.

Parameter Type Default Description
text list[str] - List of words

Raises:

  • SourceTypeError - words that are not a list of strings.
from ests.phon_stats import calc_hiatus

calc_hiatus(["poeta", "búho", "cielo", "aéreo"])
4

Entropy of the CV patterns

cv_entropy

The Shannon entropy of the CV patterns of the words (cv_pattern), in bits, where \(P(p)\) is the share of the words with the pattern \(p\) among the words that have one.

\[ -\sum_{p} P(p) \log_2 P(p) \]
calc_cv_entropy(text)

The entropy of the CV patterns of a list of words: the higher it is, the more varied the phonetic shape of the words of the text. Words without sounds (numbers) are left out; nan for a text without other words.

cv_pattern(word)

The CV pattern of a word or a syllable: the vowels are written V and the consonants C, over the sounds of the transcription - queso is CVCV, hora VCV, examen VCCVCVC. A syllable is read as a word of its own, so its initial x is s, as at the start of a word: xi is CV, while the syllable xi of México counts as CCV in PhonStats.

Parameter Type Default Description
text list[str] - List of words (calc_cv_entropy)
word str - Word or syllable (cv_pattern)

Raises:

  • SourceTypeError - words that are not a list of strings (calc_cv_entropy), a word that is not a string (cv_pattern).
from ests.phon_stats import calc_cv_entropy, cv_pattern

cv_pattern("queso"), cv_pattern("examen")
calc_cv_entropy(["poeta", "búho", "cielo", "aéreo"])
('CVCV', 'VCCVCVC')
1.5

Hardness

hardness

The number of the voiceless obstruents to the number of the vowels and the sonorants.

\[ \frac{\textrm{Number of voiceless obstruents}}{\textrm{Number of vowels} + \textrm{Number of sonorants}} \]

A text of p, t, k, s and θ sounds harder than a text of vowels and m, n, l, r.

Alliteration and assonance

alliteration · assonance

calc_alliteration(text, window_len=3)
calc_assonance(text, window_len=3)

The alliteration and assonance indices of a list of words: the repetition index calc_repetition_index of anyts.phon_stats over the consonant and over the vowel sounds of the transcription of the words. The sounds count, not the letters: casa and queso repeat k, cena and casa do not; every vowel counts, stressed or not.

Parameter Type Default Description
text list[str] - List of words
window_len int 3 Window in words (PHON_WINDOW_LEN)

Raises:

  • SourceTypeError - words that are not a list of strings;
  • ParameterError - a window that is not an integer of at least 2.
calc_repetition_index(words, window_len, features=None)

The repetition index: the number of windows of window_len neighbouring words where a feature (a letter or a sound) occurs in two words or more, summed over the features, divided by the number expected if the words stood in random order. A window of shuffled words is a sample without replacement, so for a feature found in \(K\) of the \(N\) words, a window of \(w\) words holds it in two words or more with the hypergeometric probability

\[ P = 1 - \frac{\binom{N-K}{w} + K \binom{N-K}{w-1}}{\binom{N}{w}} \]

and the expected number is the sum of these probabilities over the features times the \(N - w + 1\) windows. Since the expectation comes from the text itself, the index shows whether the repetitions gather in neighbouring words, not how frequent a feature is: it averages to 1 over the orders of the words and is well above 1 when the repetitions come closer than chance. A word counts a feature once; the index is nan for a text shorter than the window or with no feature shared by two words.

Parameter Type Default Description
words list[str] / list[list[str]] - Features of every word: a string of its letters or a collection of its sounds
window_len int - Window in words, at least 2
features Collection[str] None Features to count, all of them by default

Words that are not a list of strings or of collections of strings and features that are not a collection of strings raise SourceTypeError, and a window_len that is not an integer of at least 2 ParameterError.

For words in random order the indices average to 1: the 150 books of the corpus of literature with their words shuffled give 0.98 to 1.02. On the books as written the index of alliteration is a little below 1 for verse and prose alike, 0.90 to 0.99 with a median of 0.95, and the index of assonance about 1, 0.99 to 1.01: over a whole book neighbouring words share a consonant a little less often than chance. The 4,259 sonnets give medians of 0.92 and 0.98, with a wide spread over such short texts (0.59 to 1.30 for alliteration). The repetitions of a poem are local, and the places where they gather are shown by the layer alliteration of the highlighting.

from ests.phon_stats import calc_alliteration, calc_assonance

# Garcilaso de la Vega, Égloga III
words = "en el silencio sólo se escuchaba un susurro de abejas que sonaba".split()
calc_alliteration(words), calc_assonance(words)
(1.0232558139534884, 1.115942028985507)

Syllables

p_open_syllables · mean_syllable_len

The syllables are the sounds of every syllable of a word by syllable_sounds; a syllable without a sound of the classes (a number) is no syllable, in c_syllable_patterns too. An open syllable ends in a vowel by its CV pattern (cv_pattern), and the length of a syllable is the length of that pattern: the sounds of the classes, without skipped and the signs out of them.

The sounds of a syllable are its transcription, the first syllable of a word read as the start of the word: the xi of xilófono is s i, the xi of México k s i.

is_open_syllable(syllable)

Checks whether a syllable is open: an open syllable ends in a vowel sound - ca, que, hoy (the final y is the vowel i); car and pan are closed. The syllable is read as a word of its own.

Parameter Type Default Description
syllable str - Syllable

Raises:

  • SourceTypeError - a syllable that is not a string.
from ests.phon_stats import is_open_syllable

is_open_syllable("hoy"), is_open_syllable("car")
(True, False)

Methods

The methods get_stats, to_dataframe, print_stats and describe are those of the statistics interface of the anyTS core; the phonostatistics have no scales, so describe gives None for the statistics of get_stats.

from ests import PhonStats

PhonStats("Tres tristes tigres tragaban trigo en un trigal").get_stats()
{'p_vowels': 0.35,
 'p_sonorants': 0.25,
 'p_voiced': 0.125,
 'p_voiceless': 0.275,
 'consonant_vowel_ratio': 1.8571428571428572,
 'p_heavy_clusters': 0.0,
 'p_hiatus': 0.0,
 'cv_entropy': 2.75,
 'hardness': 0.4583333333333333,
 'alliteration': 0.9333333333333333,
 'assonance': 0.7526881720430108,
 'p_open_syllables': 0.42857142857142855,
 'mean_syllable_len': 2.857142857142857}