55
66import re
77import sys
8- from typing import TYPE_CHECKING , Union
8+ from collections .abc import Mapping
9+ from typing import TYPE_CHECKING , Any , TypedDict , Union , overload
910
1011if TYPE_CHECKING :
1112 import numpy as np
2930TAILING_SEP_RX : re .Pattern [str ] = re .compile (f"{ re .escape (SEPARATOR )} $" )
3031
3132
33+ class CharLevelStat (TypedDict ):
34+ """Character-level confusion matrix statistics for tokenization."""
35+
36+ tp : int
37+ fp : int
38+ tn : int
39+ fn : int
40+
41+
42+ class WordLevelStat (TypedDict ):
43+ """Word-level tokenization statistics."""
44+
45+ correctly_tokenized_words : int
46+ total_words_in_sample : int
47+ total_words_in_ref_sample : int
48+
49+
50+ class GlobalStat (TypedDict ):
51+ """Global tokenization indicator as a binary indicator string."""
52+
53+ tokenization_indicators : str
54+
55+
56+ class TokenizationStat (TypedDict ):
57+ """Tokenization quality statistics at character, word, and global level."""
58+
59+ char_level : CharLevelStat
60+ word_level : WordLevelStat
61+ global_ : GlobalStat
62+
63+
3264def _f1 (precision : float , recall : float ) -> float :
3365 """Compute f1.
3466
@@ -43,8 +75,21 @@ def _f1(precision: float, recall: float) -> float:
4375 return 2 * precision * recall / (precision + recall )
4476
4577
78+ @overload
79+ def _flatten_result (
80+ my_dict : TokenizationStat , sep : str = ...
81+ ) -> dict [str , Union [int , str ]]: ...
82+
83+
84+ @overload
85+ def _flatten_result (
86+ my_dict : Mapping [str , Mapping [str , Union [int , str ]]], sep : str = ...
87+ ) -> dict [str , Union [int , str ]]: ...
88+
89+
4690def _flatten_result (
47- my_dict : dict [str , dict [str , Union [int , str ]]], sep : str = ":"
91+ my_dict : Any ,
92+ sep : str = ":" ,
4893) -> dict [str , Union [int , str ]]:
4994 """Flatten two-dimension dictionary.
5095
@@ -55,8 +100,9 @@ def _flatten_result(
55100 { "a:b": 7 }
56101
57102
58- :param dict[str, dict[str, Union[int, str]]] my_dict: dictionary
59- containing stats
103+ :param my_dict: dictionary containing stats
104+ :type my_dict: TokenizationStat or
105+ collections.abc.Mapping[str, collections.abc.Mapping[str, Union[int, str]]]
60106 :param str sep: separator between the two keys (default: ":")
61107
62108 :return: a one-dimension dictionary with keys combined
@@ -139,7 +185,7 @@ def preprocessing(txt: str, remove_space: bool = True) -> str:
139185
140186def compute_stats (
141187 ref_sample : str , raw_sample : str
142- ) -> dict [ str , dict [ str , Union [ int , str ]]] :
188+ ) -> TokenizationStat :
143189 """Compute statistics for tokenization quality
144190
145191 These statistics include:
@@ -156,7 +202,7 @@ def compute_stats(
156202 :param str samples: samples that we want to evaluate
157203
158204 :return: metrics at character- and word-level and indicators of correctly tokenized words
159- :rtype: dict[str, dict[str, Union[int, str]]]
205+ :rtype: TokenizationStat
160206 """
161207 import numpy as np
162208
@@ -185,29 +231,29 @@ def compute_stats(
185231
186232 # Find correctly tokenized words in the sample
187233 ss_boundaries = _find_word_boundaries (sample_arr )
188- tokenization_indicators = _find_words_correctly_tokenised (
234+ tokenization_indicators = _find_words_correctly_tokenized (
189235 word_boundaries , ss_boundaries
190236 )
191237
192- correctly_tokenised_words : int = int (np .sum (tokenization_indicators ))
238+ correctly_tokenized_words : int = int (np .sum (tokenization_indicators ))
193239
194240 tokenization_indicators_str = list (map (str , tokenization_indicators ))
195241
196242 return {
197- "char_level" : {
198- "tp" : c_tp ,
199- "fp" : c_fp ,
200- "tn" : c_tn ,
201- "fn" : c_fn ,
202- } ,
203- "word_level" : {
204- "correctly_tokenised_words" : correctly_tokenised_words ,
205- " total_words_in_sample" : int (np .sum (sample_arr )),
206- " total_words_in_ref_sample" : int (np .sum (ref_sample_arr )),
207- } ,
208- "global " : {
209- "tokenisation_indicators" : "" .join (tokenization_indicators_str )
210- } ,
243+ "char_level" : CharLevelStat (
244+ tp = c_tp ,
245+ fp = c_fp ,
246+ tn = c_tn ,
247+ fn = c_fn ,
248+ ) ,
249+ "word_level" : WordLevelStat (
250+ correctly_tokenized_words = correctly_tokenized_words ,
251+ total_words_in_sample = int (np .sum (sample_arr )),
252+ total_words_in_ref_sample = int (np .sum (ref_sample_arr )),
253+ ) ,
254+ "global_ " : GlobalStat (
255+ tokenization_indicators = "" .join (tokenization_indicators_str ),
256+ ) ,
211257 }
212258
213259
@@ -271,7 +317,7 @@ def _find_word_boundaries(
271317 return list (zip (start_idx , end_idx ))
272318
273319
274- def _find_words_correctly_tokenised (
320+ def _find_words_correctly_tokenized (
275321 ref_boundaries : list [tuple [int , int ]],
276322 predicted_boundaries : list [tuple [int , int ]],
277323) -> tuple [int , ...]:
0 commit comments