speechmetryflow 0.2.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- speechmetryflow/__init__.py +25 -0
- speechmetryflow/_version.py +34 -0
- speechmetryflow/cli.py +131 -0
- speechmetryflow/lexical/__init__.py +17 -0
- speechmetryflow/lexical/assets/__init__.py +103 -0
- speechmetryflow/lexical/assets/concreteness.tsv +39955 -0
- speechmetryflow/lexical/assets/familiarity_imageability.tsv +5554 -0
- speechmetryflow/lexical/assets/frequency.tsv +74289 -0
- speechmetryflow/lexical/assets/valence.tsv +13916 -0
- speechmetryflow/lexical/database.py +143 -0
- speechmetryflow/lexical/part_of_speech.py +172 -0
- speechmetryflow/lexical/utils.py +119 -0
- speechmetryflow/pragmatic/__init__.py +60 -0
- speechmetryflow/pragmatic/assets.py +62 -0
- speechmetryflow/pragmatic/database.py +113 -0
- speechmetryflow/semantic/__init__.py +23 -0
- speechmetryflow/semantic/assets.py +285 -0
- speechmetryflow/semantic/icu.py +33 -0
- speechmetryflow/semantic/idea_density.py +78 -0
- speechmetryflow/speech_production/__init__.py +62 -0
- speechmetryflow/speech_production/assets/__init__.py +58 -0
- speechmetryflow/speech_production/assets/words_fr.json +1 -0
- speechmetryflow/speech_production/fluency.py +42 -0
- speechmetryflow/speech_production/fragment.py +76 -0
- speechmetryflow/syntactic/__init__.py +119 -0
- speechmetryflow/syntactic/assets.py +40 -0
- speechmetryflow/syntactic/dependency.py +47 -0
- speechmetryflow/syntactic/sentences.py +189 -0
- speechmetryflow/ucsf_disfluency/__init__.py +23 -0
- speechmetryflow/utils.py +53 -0
- speechmetryflow-0.2.2.dist-info/METADATA +764 -0
- speechmetryflow-0.2.2.dist-info/RECORD +35 -0
- speechmetryflow-0.2.2.dist-info/WHEEL +4 -0
- speechmetryflow-0.2.2.dist-info/entry_points.txt +3 -0
- speechmetryflow-0.2.2.dist-info/licenses/LICENSE +674 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import pandas as pd
|
|
2
|
+
import numpy as np
|
|
3
|
+
import importlib_resources
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def load_database(tag, lang):
|
|
7
|
+
assets_folder = importlib_resources.files(__name__) / "assets"
|
|
8
|
+
|
|
9
|
+
if lang == "en":
|
|
10
|
+
tag2df = {
|
|
11
|
+
"concreteness": pd.read_csv(
|
|
12
|
+
assets_folder / "concreteness.tsv",
|
|
13
|
+
sep="\t",
|
|
14
|
+
usecols=["Word", "Conc.M"],
|
|
15
|
+
index_col="Word",
|
|
16
|
+
).squeeze(),
|
|
17
|
+
"familiarity": pd.read_csv(
|
|
18
|
+
assets_folder / "familiarity_imageability.tsv",
|
|
19
|
+
sep="\t",
|
|
20
|
+
usecols=["Words", "FAM_M"],
|
|
21
|
+
index_col="Words",
|
|
22
|
+
).squeeze(),
|
|
23
|
+
"imageability": pd.read_csv(
|
|
24
|
+
assets_folder / "familiarity_imageability.tsv",
|
|
25
|
+
sep="\t",
|
|
26
|
+
usecols=["Words", "IMAG_M"],
|
|
27
|
+
index_col="Words",
|
|
28
|
+
).squeeze(),
|
|
29
|
+
"frequency": pd.read_csv(
|
|
30
|
+
assets_folder / "frequency.tsv",
|
|
31
|
+
sep="\t",
|
|
32
|
+
usecols=["Word", "SUBTLWF"],
|
|
33
|
+
index_col="Word",
|
|
34
|
+
).squeeze(),
|
|
35
|
+
"valence": pd.read_csv(
|
|
36
|
+
assets_folder / "valence.tsv",
|
|
37
|
+
sep="\t",
|
|
38
|
+
usecols=["Word", "V.Mean.Sum"],
|
|
39
|
+
index_col="Word",
|
|
40
|
+
).squeeze(),
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
else:
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
return tag2df.get(tag)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def compute_database(tokens, lang, tag):
|
|
50
|
+
"""
|
|
51
|
+
Compute the concreteness of words in a list from a concreteness database.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
tokens (list): A list of words from which the average concreteness will be calculated.
|
|
55
|
+
lang (str): language of the text.
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
numpy.array: concreteness of the words.
|
|
59
|
+
"""
|
|
60
|
+
data = load_database(tag, lang)
|
|
61
|
+
if data is None:
|
|
62
|
+
return
|
|
63
|
+
|
|
64
|
+
return np.array(list(map(data.get, tokens))).astype(float)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def compute_concreteness(tokens, lang):
|
|
68
|
+
"""
|
|
69
|
+
Compute the concreteness of words in a list from a concreteness database.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
tokens (list): A list of words from which the average concreteness will be calculated.
|
|
73
|
+
lang (str): language of the text.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
numpy.array: concreteness of the words.
|
|
77
|
+
"""
|
|
78
|
+
return compute_database(tokens, lang, "concreteness")
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
def compute_familiarity(tokens, lang):
|
|
82
|
+
"""
|
|
83
|
+
Compute the familiarity of words in a list from a familiarity database.
|
|
84
|
+
|
|
85
|
+
Args:
|
|
86
|
+
tokens (list): A list of words from which the average familiarity will be calculated.
|
|
87
|
+
lang (str): language of the text.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
numpy.array: familiarity of the words.
|
|
91
|
+
"""
|
|
92
|
+
return compute_database(tokens, lang, "familiarity")
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def compute_imageability(tokens, lang):
|
|
96
|
+
"""
|
|
97
|
+
Compute the imageability of words in a list from a imageability database.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
tokens (list): A list of words from which the average imageability will be calculated.
|
|
101
|
+
lang (str): language of the text.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
numpy.array: imageability of the words.
|
|
105
|
+
"""
|
|
106
|
+
return compute_database(tokens, lang, "imageability")
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def compute_frequency(tokens, lang):
|
|
110
|
+
"""
|
|
111
|
+
Compute the frequency of words in a list from a frequency database.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
tokens (list): A list of words from which the average frequency will be calculated.
|
|
115
|
+
lang (str): language of the text.
|
|
116
|
+
|
|
117
|
+
Returns:
|
|
118
|
+
numpy.array: frequency of the words.
|
|
119
|
+
"""
|
|
120
|
+
return compute_database(tokens, lang, "frequency")
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def compute_valence(tokens, lang):
|
|
124
|
+
"""
|
|
125
|
+
Compute the valence of words in a list from a valence database.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
tokens (list): A list of words from which the average valence will be calculated.
|
|
129
|
+
lang (str): language of the text.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
numpy.array: valence of the words.
|
|
133
|
+
"""
|
|
134
|
+
return compute_database(tokens, lang, "valence")
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
TAG2FUNC = {
|
|
138
|
+
"concreteness": compute_concreteness,
|
|
139
|
+
"familiarity": compute_familiarity,
|
|
140
|
+
"imageability": compute_imageability,
|
|
141
|
+
"frequency": compute_frequency,
|
|
142
|
+
"valence": compute_valence,
|
|
143
|
+
}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
import numpy as np
|
|
3
|
+
from numpy.lib.stride_tricks import sliding_window_view
|
|
4
|
+
from collections import Counter
|
|
5
|
+
|
|
6
|
+
from speechmetryflow.lexical.assets import pos_mapping
|
|
7
|
+
from speechmetryflow.lexical.database import TAG2FUNC
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class POS:
|
|
11
|
+
def __init__(self, doc, lang):
|
|
12
|
+
self.doc = doc
|
|
13
|
+
self.lang = lang
|
|
14
|
+
self.mapping = pos_mapping
|
|
15
|
+
self.pos = [token.pos_ for token in self.doc]
|
|
16
|
+
self.text = np.array([token.text for token in self.doc])
|
|
17
|
+
self.counts = self._counts()
|
|
18
|
+
self.len_text = len(doc)
|
|
19
|
+
self.metrics = {}
|
|
20
|
+
self._compute_metrics()
|
|
21
|
+
|
|
22
|
+
def _counts(self):
|
|
23
|
+
counts = Counter(pos_mapping.keys())
|
|
24
|
+
counts.subtract(pos_mapping.keys())
|
|
25
|
+
counts.update(self.pos)
|
|
26
|
+
return counts
|
|
27
|
+
|
|
28
|
+
def _compute_metrics(self):
|
|
29
|
+
self.counter()
|
|
30
|
+
self.proportions()
|
|
31
|
+
self.count_open_class_words()
|
|
32
|
+
self.count_closed_class_words()
|
|
33
|
+
self.count_verb_inflection()
|
|
34
|
+
self.count_verb_gerondif()
|
|
35
|
+
self.compute_ratios()
|
|
36
|
+
for window_shape in [10, 25, 40]:
|
|
37
|
+
self.compute_mattr(window_shape)
|
|
38
|
+
self.compute_database("concreteness")
|
|
39
|
+
self.compute_database("familiarity")
|
|
40
|
+
self.compute_database("imageability")
|
|
41
|
+
self.compute_database("frequency")
|
|
42
|
+
self.compute_database("valence")
|
|
43
|
+
|
|
44
|
+
def proportions(self):
|
|
45
|
+
for tag, count in self.counts.items():
|
|
46
|
+
self.metrics[f"pos_prop_{tag}"] = (
|
|
47
|
+
count / self.len_text if self.len_text > 0 else None
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
def counter(self):
|
|
51
|
+
for tag, count in self.counts.items():
|
|
52
|
+
self.metrics[f"pos_count_{tag}"] = count
|
|
53
|
+
|
|
54
|
+
def count_open_class_words(self):
|
|
55
|
+
open_classes = ["NOUN", "VERB", "ADJ", "ADV"]
|
|
56
|
+
num = sum(self.counts[pos] for pos in open_classes)
|
|
57
|
+
self.metrics["pos_count_open_words"] = num
|
|
58
|
+
self.metrics["pos_prop_open_words"] = (
|
|
59
|
+
num / self.len_text if self.len_text > 0 else None
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
def count_closed_class_words(self):
|
|
63
|
+
closed_classes = ["CONJ", "PRON", "DET", "ADP"]
|
|
64
|
+
num = sum(self.counts[pos] for pos in closed_classes)
|
|
65
|
+
self.metrics["pos_count_closed_words"] = num
|
|
66
|
+
self.metrics["pos_prop_closed_words"] = (
|
|
67
|
+
num / self.len_text if self.len_text > 0 else None
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
def count_verb_inflection(self):
|
|
71
|
+
"""Verb inflection is the modification of a verb's form to express grammatical features such as tense."""
|
|
72
|
+
num = sum(
|
|
73
|
+
1 for token in self.doc if token.pos_ == "VERB" and token.tag_ != "VB"
|
|
74
|
+
)
|
|
75
|
+
self.metrics["pos_count_verb_inflection"] = num
|
|
76
|
+
self.metrics["pos_prop_verb_inflection"] = (
|
|
77
|
+
num / self.len_text if self.len_text > 0 else None
|
|
78
|
+
)
|
|
79
|
+
|
|
80
|
+
def count_verb_gerondif(self):
|
|
81
|
+
"""
|
|
82
|
+
The gérondif is a French verb form expressing an action occurring in relation to another action.
|
|
83
|
+
Example: Il écoute de la musique en travaillant.
|
|
84
|
+
"""
|
|
85
|
+
num = sum(1 for token in self.doc if token.tag_ != "VBG")
|
|
86
|
+
self.metrics["pos_count_verb_gerondif"] = num
|
|
87
|
+
self.metrics["pos_prop_verb_gerondif"] = (
|
|
88
|
+
num / self.len_text if self.len_text > 0 else None
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def compute_ratios(self):
|
|
92
|
+
"""
|
|
93
|
+
Computing the following ratios:
|
|
94
|
+
- PRON / (NOUN + PRON)
|
|
95
|
+
- NOUN / (NOUN + PRON)
|
|
96
|
+
- NOUN / (NOUN + VERB)
|
|
97
|
+
- VERB / (NOUN + VERB)
|
|
98
|
+
- VERB_INFLECTION / VERB
|
|
99
|
+
- VERB_GERONDIF / VERB
|
|
100
|
+
"""
|
|
101
|
+
n_verb = self.counts["VERB"]
|
|
102
|
+
n_noun = self.counts["NOUN"]
|
|
103
|
+
n_pron = self.counts["PRON"]
|
|
104
|
+
n_inflection = self.metrics["pos_count_verb_inflection"]
|
|
105
|
+
n_gerondif = self.metrics["pos_count_verb_gerondif"]
|
|
106
|
+
# Calcul des ratios
|
|
107
|
+
self.metrics["PRON/(NOUN+PRON)"] = (
|
|
108
|
+
n_pron / (n_noun + n_pron) if (n_noun + n_pron) > 0 else None
|
|
109
|
+
)
|
|
110
|
+
self.metrics["NOUN/(NOUN+PRON)"] = (
|
|
111
|
+
n_noun / (n_noun + n_pron) if (n_noun + n_pron) > 0 else None
|
|
112
|
+
)
|
|
113
|
+
self.metrics["NOUN/(NOUN+VERB)"] = (
|
|
114
|
+
n_noun / (n_noun + n_verb) if (n_noun + n_verb) > 0 else None
|
|
115
|
+
)
|
|
116
|
+
self.metrics["VERB/(NOUN+VERB)"] = (
|
|
117
|
+
n_verb / (n_noun + n_verb) if (n_noun + n_verb) > 0 else None
|
|
118
|
+
)
|
|
119
|
+
self.metrics["VERB_INFLECTION/VERB"] = (
|
|
120
|
+
n_inflection / n_verb if n_verb > 0 else None
|
|
121
|
+
)
|
|
122
|
+
self.metrics["VERB_GERONDIF/VERB"] = n_gerondif / n_verb if n_verb > 0 else None
|
|
123
|
+
|
|
124
|
+
def compute_mattr(self, window_shape):
|
|
125
|
+
"""
|
|
126
|
+
Compute the MATTR (Moving-Average Type-Token Ratio) using a window of specified size.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
window_shape (int): The size of the text window to use.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
float: MATTR value.
|
|
133
|
+
"""
|
|
134
|
+
try:
|
|
135
|
+
windows = sliding_window_view(self.pos, window_shape=window_shape)
|
|
136
|
+
except ValueError:
|
|
137
|
+
# if window_shape is larger than input array shape
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
# Compute the TTR (Type-Token Ratio) for each window
|
|
141
|
+
ttr_values = [len(set(window)) / window_shape for window in windows]
|
|
142
|
+
|
|
143
|
+
self.metrics[f"pos_mattr_{window_shape}"] = np.mean(ttr_values)
|
|
144
|
+
|
|
145
|
+
def compute_database(self, tag):
|
|
146
|
+
""""""
|
|
147
|
+
scores = TAG2FUNC[tag](self.text, self.lang)
|
|
148
|
+
|
|
149
|
+
if scores is None:
|
|
150
|
+
for pos_type in ["NOUN", "VERB", "ADJ"]:
|
|
151
|
+
self.metrics[f"{tag}_mean_{pos_type}"] = None
|
|
152
|
+
self.metrics[f"{tag}_mean_all_tokens"] = None
|
|
153
|
+
return
|
|
154
|
+
|
|
155
|
+
warnings.filterwarnings("error")
|
|
156
|
+
for pos_type in ["NOUN", "VERB", "ADJ"]:
|
|
157
|
+
pos_positions = np.nonzero(np.array(self.pos) == pos_type)[0]
|
|
158
|
+
sub_scores = scores[pos_positions]
|
|
159
|
+
try:
|
|
160
|
+
score = np.nanmean(sub_scores)
|
|
161
|
+
except RuntimeWarning:
|
|
162
|
+
score = 0.0
|
|
163
|
+
self.metrics[f"{tag}_mean_{pos_type}"] = score
|
|
164
|
+
|
|
165
|
+
# For all tokens
|
|
166
|
+
try:
|
|
167
|
+
score = np.nanmean(scores)
|
|
168
|
+
except RuntimeWarning:
|
|
169
|
+
score = 0.0
|
|
170
|
+
self.metrics[f"{tag}_mean_all_tokens"] = score
|
|
171
|
+
|
|
172
|
+
warnings.resetwarnings()
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
from speechmetryflow.lexical.assets import deictic_pronouns, indefinite_terms
|
|
4
|
+
from speechmetryflow.speech_production import compute_counts
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def count_deictic_pronouns(tokens, lang):
|
|
8
|
+
"""
|
|
9
|
+
Counts deictic pronouns in a text in English or French.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
- tokens list[(str)]: The text to be analysed.
|
|
13
|
+
- lang (str): The language of the text ("fr", "en").
|
|
14
|
+
|
|
15
|
+
Returns:
|
|
16
|
+
- dict: A dictionary with the counts of spatial, personal, temporal pronouns and the total.
|
|
17
|
+
"""
|
|
18
|
+
deictic_pronouns_data = deictic_pronouns.get(lang)
|
|
19
|
+
|
|
20
|
+
if deictic_pronouns_data is None:
|
|
21
|
+
return {
|
|
22
|
+
"n_deictic_pronouns_spatial": None,
|
|
23
|
+
"n_deictic_pronouns_personal": None,
|
|
24
|
+
"n_deictic_pronouns_temporal": None,
|
|
25
|
+
"n_deictic_pronouns_total": None,
|
|
26
|
+
"prop_deictic_pronouns_spatial": None,
|
|
27
|
+
"prop_deictic_pronouns_personal": None,
|
|
28
|
+
"prop_deictic_pronouns_temporal": None,
|
|
29
|
+
"prop_deictic_pronouns_total": None,
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
len_text = len(tokens)
|
|
33
|
+
n_spatial = sum(token in deictic_pronouns_data["spatial"] for token in tokens)
|
|
34
|
+
n_personal = sum(token in deictic_pronouns_data["personal"] for token in tokens)
|
|
35
|
+
n_temporal = sum(token in deictic_pronouns_data["temporal"] for token in tokens)
|
|
36
|
+
n_total = n_spatial + n_personal + n_temporal
|
|
37
|
+
|
|
38
|
+
return {
|
|
39
|
+
"n_deictic_pronouns_spatial": n_spatial,
|
|
40
|
+
"n_deictic_pronouns_personal": n_personal,
|
|
41
|
+
"n_deictic_pronouns_temporal": n_temporal,
|
|
42
|
+
"n_deictic_pronouns_total": n_total,
|
|
43
|
+
"prop_deictic_pronouns_spatial": n_spatial / len_text if len_text > 0 else None,
|
|
44
|
+
"prop_deictic_pronouns_personal": (
|
|
45
|
+
n_personal / len_text if len_text > 0 else None
|
|
46
|
+
),
|
|
47
|
+
"prop_deictic_pronouns_temporal": (
|
|
48
|
+
n_temporal / len_text if len_text > 0 else None
|
|
49
|
+
),
|
|
50
|
+
"prop_deictic_pronouns_total": n_total / len_text if len_text > 0 else None,
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def count_indefinite_terms(tokens, lang):
|
|
55
|
+
"""
|
|
56
|
+
Counts the number of indefinite terms in a text based on the language.
|
|
57
|
+
|
|
58
|
+
Args:
|
|
59
|
+
- tokens list[(str)]: The text to be analysed.
|
|
60
|
+
- lang (str): The language of the text ("fr", "en").
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
int: The number of indefinite terms found in the text.
|
|
64
|
+
"""
|
|
65
|
+
indefinite_terms_data = indefinite_terms.get(lang)
|
|
66
|
+
|
|
67
|
+
if indefinite_terms_data is None:
|
|
68
|
+
return
|
|
69
|
+
|
|
70
|
+
len_text = len(tokens)
|
|
71
|
+
num = sum(token in indefinite_terms_data for token in tokens)
|
|
72
|
+
return {
|
|
73
|
+
"n_indefinite_terms": num,
|
|
74
|
+
"prop_indefinite_terms": num / len_text if len_text > 0 else None,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def compute_honore_r_stat(stems):
|
|
79
|
+
"""
|
|
80
|
+
Compute Honore's R statistic.
|
|
81
|
+
100*log(N)/(1-(n_unique/n_different))
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
stems list(str): list of stems to compute.
|
|
85
|
+
|
|
86
|
+
Returns:
|
|
87
|
+
float: value of Honore's R statistic.
|
|
88
|
+
"""
|
|
89
|
+
if stems is None:
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
N, n_different, n_unique, _ = compute_counts(stems)
|
|
93
|
+
return (100 * math.log(N)) / (1 - (n_unique / n_different)) if N else None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def compute_brunet_index(stems):
|
|
97
|
+
"""
|
|
98
|
+
Compute the Brunet index
|
|
99
|
+
A measure of lexical diversity linking the length of the sample to the number of different words used in it.
|
|
100
|
+
Lower values of W correspond to richer texts.
|
|
101
|
+
Stemming is done on words and only the stems are considered.
|
|
102
|
+
|
|
103
|
+
Formula: W = N ^ (V ^ (-0.165))
|
|
104
|
+
W (float): Brunet's index.
|
|
105
|
+
N (int): total number of stems.
|
|
106
|
+
V (int): number of different stems.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
stems list(str): list of stems to compute.
|
|
110
|
+
|
|
111
|
+
Returns:
|
|
112
|
+
float: value of Brunet index.
|
|
113
|
+
"""
|
|
114
|
+
if stems is None:
|
|
115
|
+
return
|
|
116
|
+
|
|
117
|
+
N, n_different, _, _ = compute_counts(stems)
|
|
118
|
+
|
|
119
|
+
return math.pow(N, math.pow(n_different, -0.165)) if N else None
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from transformers import AutoTokenizer, AutoModelWithLMHead, pipeline
|
|
4
|
+
|
|
5
|
+
from speechmetryflow.semantic.idea_density import compute_idea_density
|
|
6
|
+
from speechmetryflow.pragmatic.database import compute_database
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def coherence_locale(doc):
|
|
10
|
+
similarities = []
|
|
11
|
+
for sent in doc.sents:
|
|
12
|
+
tokens = [token for token in sent]
|
|
13
|
+
(similarity,) = compute_idea_density(tokens, [len(tokens)]).values()
|
|
14
|
+
similarities.append(similarity)
|
|
15
|
+
return np.nanmean(similarities)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def compute_emotion(text):
|
|
19
|
+
tokenizer = AutoTokenizer.from_pretrained("mrm8488/t5-base-finetuned-emotion")
|
|
20
|
+
model = AutoModelWithLMHead.from_pretrained("mrm8488/t5-base-finetuned-emotion")
|
|
21
|
+
input_ids = tokenizer.encode(text + "</s>", return_tensors="pt")
|
|
22
|
+
output = model.generate(input_ids=input_ids, max_length=2)
|
|
23
|
+
dec = [tokenizer.decode(ids) for ids in output]
|
|
24
|
+
label = dec[0]
|
|
25
|
+
# Supprimer le token <pad> de la sortie
|
|
26
|
+
return label.replace("<pad>", "").strip()
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def compute_sentiment(text):
|
|
30
|
+
"""
|
|
31
|
+
Analyses the sentiment of a text using the mrm8488/t5-base-finetuned-emotion model.
|
|
32
|
+
:param text: Text to be analysed.
|
|
33
|
+
:return: Sentiment label.
|
|
34
|
+
"""
|
|
35
|
+
model_path = "cardiffnlp/twitter-xlm-roberta-base-sentiment"
|
|
36
|
+
# Creation of the sentiment analysis pipeline
|
|
37
|
+
sentiment_task = pipeline(
|
|
38
|
+
"sentiment-analysis",
|
|
39
|
+
model=model_path,
|
|
40
|
+
tokenizer=model_path,
|
|
41
|
+
max_length=512,
|
|
42
|
+
truncation=True,
|
|
43
|
+
)
|
|
44
|
+
# Sentiment analysis
|
|
45
|
+
result = sentiment_task(text)
|
|
46
|
+
# Sentiment label retrieval
|
|
47
|
+
label = result[0]["label"]
|
|
48
|
+
return label
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def metrics(doc, lang, n_tokens):
|
|
52
|
+
metrics = compute_database(doc, lang, n_tokens, "uncertainty_words")
|
|
53
|
+
metrics.update(compute_database(doc, lang, n_tokens, "formulaic_expressions"))
|
|
54
|
+
metrics.update(compute_database(doc, lang, n_tokens, "modal_expressions"))
|
|
55
|
+
metrics.update(compute_database(doc, lang, n_tokens, "filler_expressions"))
|
|
56
|
+
metrics.update(compute_database(doc, lang, n_tokens, "difficulty_words"))
|
|
57
|
+
metrics["coherence_locale"] = coherence_locale(doc)
|
|
58
|
+
metrics["emotion"] = compute_emotion(doc.text)
|
|
59
|
+
metrics["sentiment"] = compute_sentiment(doc.text)
|
|
60
|
+
return metrics
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pragmatic characteristics
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
# Uncertainty words
|
|
6
|
+
uncertainty_words = {
|
|
7
|
+
"en": {"think", "look", "like", "kind", "seem", "maybe", "can", "something"},
|
|
8
|
+
"fr": {
|
|
9
|
+
"penser",
|
|
10
|
+
"sembler",
|
|
11
|
+
"comme",
|
|
12
|
+
"genre",
|
|
13
|
+
"peut-être",
|
|
14
|
+
"peut",
|
|
15
|
+
"quelque",
|
|
16
|
+
"chose",
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# Formulaic expressions
|
|
21
|
+
formulaic_expressions = {
|
|
22
|
+
"en": {"well", "so", "i guess", "you know", "as it is", "as it were"},
|
|
23
|
+
"fr": {"bien", "alors", "je suppose", "tu sais", "comme il est", "comme il serait"},
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
# Modal expressions
|
|
27
|
+
modal_expressions = {
|
|
28
|
+
"en": {
|
|
29
|
+
"i think",
|
|
30
|
+
"in my opinion",
|
|
31
|
+
"of course",
|
|
32
|
+
"naturally",
|
|
33
|
+
"unsure",
|
|
34
|
+
"likely",
|
|
35
|
+
"could be that",
|
|
36
|
+
"unfortunately",
|
|
37
|
+
"surely",
|
|
38
|
+
},
|
|
39
|
+
"fr": {
|
|
40
|
+
"je pense",
|
|
41
|
+
"à mon avis",
|
|
42
|
+
"bien sûr",
|
|
43
|
+
"naturellement",
|
|
44
|
+
"incertain",
|
|
45
|
+
"probablement",
|
|
46
|
+
"ça pourrait être que",
|
|
47
|
+
"malheureusement",
|
|
48
|
+
"sûrement",
|
|
49
|
+
},
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
# Filler expressions
|
|
53
|
+
filler_expressions = {
|
|
54
|
+
"en": {"you know", "i mean"},
|
|
55
|
+
"fr": {"tu sais", "je veux dire"},
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
# Words indicating lexical access difficulties
|
|
59
|
+
difficulty_words = {
|
|
60
|
+
"en": {"know", "remember", "unable"},
|
|
61
|
+
"fr": {"savoir", "se souvenir", "incapable"},
|
|
62
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
from speechmetryflow.pragmatic import assets
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def compute_database(doc, lang, n_tokens, tag):
|
|
5
|
+
"""
|
|
6
|
+
Compute the concreteness of words in a list from a concreteness database.
|
|
7
|
+
|
|
8
|
+
Args:
|
|
9
|
+
tokens (list): A list of words from which the average concreteness will be calculated.
|
|
10
|
+
lang (str): language of the text.
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
numpy.array: concreteness of the words.
|
|
14
|
+
"""
|
|
15
|
+
tag2database = {
|
|
16
|
+
"uncertainty_words": assets.uncertainty_words,
|
|
17
|
+
"formulaic_expressions": assets.formulaic_expressions,
|
|
18
|
+
"modal_expressions": assets.modal_expressions,
|
|
19
|
+
"filler_expressions": assets.filler_expressions,
|
|
20
|
+
"difficulty_words": assets.difficulty_words,
|
|
21
|
+
}
|
|
22
|
+
data = tag2database[tag].get(lang)
|
|
23
|
+
if data is None:
|
|
24
|
+
return {
|
|
25
|
+
f"n_{tag}": None,
|
|
26
|
+
f"prop_{tag}": None,
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
text = doc.text.lower()
|
|
30
|
+
count = sum(text.count(expression) for expression in data)
|
|
31
|
+
return {
|
|
32
|
+
f"n_{tag}": count,
|
|
33
|
+
f"prop_{tag}": count / n_tokens if n_tokens else None,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def compute_concreteness(tokens, lang):
|
|
38
|
+
"""
|
|
39
|
+
Compute the concreteness of words in a list from a concreteness database.
|
|
40
|
+
|
|
41
|
+
Args:
|
|
42
|
+
tokens (list): A list of words from which the average concreteness will be calculated.
|
|
43
|
+
lang (str): language of the text.
|
|
44
|
+
|
|
45
|
+
Returns:
|
|
46
|
+
numpy.array: concreteness of the words.
|
|
47
|
+
"""
|
|
48
|
+
return compute_database(tokens, lang, "concreteness")
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def compute_familiarity(tokens, lang):
|
|
52
|
+
"""
|
|
53
|
+
Compute the familiarity of words in a list from a familiarity database.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
tokens (list): A list of words from which the average familiarity will be calculated.
|
|
57
|
+
lang (str): language of the text.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
numpy.array: familiarity of the words.
|
|
61
|
+
"""
|
|
62
|
+
return compute_database(tokens, lang, "familiarity")
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def compute_imageability(tokens, lang):
|
|
66
|
+
"""
|
|
67
|
+
Compute the imageability of words in a list from a imageability database.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
tokens (list): A list of words from which the average imageability will be calculated.
|
|
71
|
+
lang (str): language of the text.
|
|
72
|
+
|
|
73
|
+
Returns:
|
|
74
|
+
numpy.array: imageability of the words.
|
|
75
|
+
"""
|
|
76
|
+
return compute_database(tokens, lang, "imageability")
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def compute_frequency(tokens, lang):
|
|
80
|
+
"""
|
|
81
|
+
Compute the frequency of words in a list from a frequency database.
|
|
82
|
+
|
|
83
|
+
Args:
|
|
84
|
+
tokens (list): A list of words from which the average frequency will be calculated.
|
|
85
|
+
lang (str): language of the text.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
numpy.array: frequency of the words.
|
|
89
|
+
"""
|
|
90
|
+
return compute_database(tokens, lang, "frequency")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def compute_valence(tokens, lang):
|
|
94
|
+
"""
|
|
95
|
+
Compute the valence of words in a list from a valence database.
|
|
96
|
+
|
|
97
|
+
Args:
|
|
98
|
+
tokens (list): A list of words from which the average valence will be calculated.
|
|
99
|
+
lang (str): language of the text.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
numpy.array: valence of the words.
|
|
103
|
+
"""
|
|
104
|
+
return compute_database(tokens, lang, "valence")
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
TAG2FUNC = {
|
|
108
|
+
"concreteness": compute_concreteness,
|
|
109
|
+
"familiarity": compute_familiarity,
|
|
110
|
+
"imageability": compute_imageability,
|
|
111
|
+
"frequency": compute_frequency,
|
|
112
|
+
"valence": compute_valence,
|
|
113
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
from speechmetryflow.semantic.icu import compute_icu
|
|
2
|
+
from speechmetryflow.semantic.idea_density import compute_idea_density
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def metrics(text, tokens, lang, task, n_tokens):
|
|
6
|
+
metrics = compute_idea_density(tokens, [3, 10, 25, 40])
|
|
7
|
+
|
|
8
|
+
icu_data = compute_icu(text, lang, task)
|
|
9
|
+
|
|
10
|
+
# Total number of True ICU anf ICU efficacity
|
|
11
|
+
if icu_data is None:
|
|
12
|
+
n_icu_true = None
|
|
13
|
+
icu_efficacity = None
|
|
14
|
+
|
|
15
|
+
else:
|
|
16
|
+
metrics.update(icu_data)
|
|
17
|
+
n_icu_true = sum(icu_data.values())
|
|
18
|
+
icu_efficacity = n_tokens / n_icu_true if n_icu_true else None
|
|
19
|
+
|
|
20
|
+
metrics["n_icu_true"] = n_icu_true
|
|
21
|
+
metrics["icu_efficacity"] = icu_efficacity
|
|
22
|
+
|
|
23
|
+
return metrics
|