你的德語詞表沒有 ß,統計結果可能因此失準
Your German word list has no ß (and your stats may be lying because of it)
wordfreq 3.1.1 的德語詞表不含 ß,會把 weiß、saß 等詞折疊成 ss 拼法,導致純字串比對錯報詞表遺漏。俄語的 ё/е 也可能令頻率統計偏差;土耳其語則不能只用 Python 的 lower() 處理大寫 I。建議比較時按語言正規化,並分開儲存比對用字串和顯示文字。
Here is a one-liner that broke a report of ours:
>>> from wordfreq import tokenize
>>> tokenize("Er weiß, dass die Straße groß ist", "de")
['er', 'weiss', 'dass', 'die', 'strasse', 'gross', 'ist']
wordfreq is a good library and this isn't a bug: it looks like ordinary case-folding, since "ß".casefold() gives "ss". It still surprised us, because the output is spelled in a way a German book never spells these words.
How far it goes
We were using version 3.1.1, and the list has no ß in it at all:
>>> from wordfreq import top_n_list, word_frequency
>>> sum("ß" in w for w in top_n_list("de", 50_000))
0
>>> word_frequency("weiß", "de") == word_frequency("weiss", "de")
True
>>> top_n_list("de", 200).index("weiss")
166
So asking about either spelling works. The trouble starts when you take the list out of the library and compare it with text as plain strings, which is what happens the moment you publish a word list or measure coverage against a set.
The symptom
We had a job that measures how much of a book a frequency list covers, and it prints the commonest words the list does not know. For German, the top of that report was:
weiß
saß
ließ
These are some of the most ordinary verbs in the language. If you read the report without thinking, you conclude that frequency lists miss basic German. That is a bug of ours reported as a fact about the language.
Why you can't just put the ß back
The tempting fix is to restore the letter in the list. That can't work, because the fold is lossy:
>>> tokenize("in Maßen, in Massen", "de")
['in', 'massen', 'in', 'massen']
"In Maßen" means in moderation and "in Massen" means in huge quantities. After the fold they are one token, and nothing in the list tells you which one you are holding. The information is gone before you get the data.
So we left the list alone and fold the other side at the moment of comparison:
_MATCH_FOLD = {
"de": lambda w: w.replace("ß", "ss"),
"ru": lambda w: w.replace("ё", "е"),
"uk": lambda w: w.replace("ё", "е"),
}
def fold(word, lang):
f = _MATCH_FOLD.get(lang)
return f(word) if f else word
The comparison key changes and the text you show people does not.
Russian is the same bug in a softer form
Russian print usually drops the dots on ё, and the corpus has both spellings as separate entries, with very different weights:
>>> word_frequency("ещё", "ru"), word_frequency("еще", "ru")
(0.000513, 0.00195)
Nothing is missing here, but a book that prints ё gets matched against the rarer entry, and your numbers shift by a factor of about four for one of the commonest words in the language.
Turkish breaks plain lower()
While we were in there, we checked the other side of the comparison, our own lowercasing:
>>> "KIZ".lower()
'kiz'
>>> tokenize("KIZ", "tr")
['kız']
Python's str.lower() doesn't know the language, so the Turkish capital I becomes the wrong letter. kiz is not the word at all. The library gets it right, so a homemade tokenizer in front of it quietly disagrees with it. Our fix is two replacements before lowering:
if lang == "tr":
text = text.replace("İ", "i").replace("I", "ı")
text = text.lower().replace("̇", "")
What we'd do from the start
Three habits would have caught all of this earlier:
-
Print the commonest misses, not just the coverage number. A coverage of 94% looks fine whether or not it is wrong. A list of misses starting with
weißdoes not. - Treat normalisation as part of the data's schema. Write down what the source folds, per language, and apply the same fold to anything you compare with it.
- Keep two strings. A comparison key and a display form are different things, and one field can't be both.
If you want the longer version of what these lists leave out, once the spelling is sorted, we wrote it up here: what a frequency list misses.
This article was written with the help of AI. The code comes from our own pipeline, and every output above was run against wordfreq 3.1.1 before publishing.
來源:DEV Community · dev.to