diff --git a/languedoc.py b/languedoc.py --- a/languedoc.py +++ b/languedoc.py @@ -3,11 +3,12 @@ import re import random import itertools +from shared import identify, extract_ngram_freqs, TOP_NGRAM_COUNT + random.seed(19181028) CROSSVALIDATION_SOURCE_COUNT = 5 TEST_LENS = [8, 16, 32, 64] -TOP_NGRAM_COUNT = 6000 def preprocess(text): @@ -15,22 +16,6 @@ def preprocess(text): return text.lower() -def extract_ngram_freqs(text, k): - n = len(text) - d = dict() - - for i in range(0, n-k+1): - key = text[i:i+k] - if key.isspace(): - continue - - d[key] = d.get(key, 0) + 1 - - count = sum(d.values()) - - return {key: val/count for (key, val) in d.items()} - - def merge_ngram_freqs(freqs): n = len(freqs) res = dict() @@ -141,12 +126,6 @@ def cross_validate(sample_sets): return score / max_score, (score, max_score) -def identify(text, models): - sample = Sample(text=text) - - return min(map(lambda m: (m.compare(sample), m.language), models))[1] - - DATA_DIR = os.path.join(os.path.dirname(__file__), "data") LANG_DIRS = sorted([x.path for x in os.scandir(DATA_DIR)]) diff --git a/shared.py b/shared.py new file mode 100644 --- /dev/null +++ b/shared.py @@ -0,0 +1,70 @@ +import itertools + +TOP_NGRAM_COUNT = 5000 + + +def extract_ngram_freqs(text, k): + n = len(text) + d = dict() + + for i in range(0, n-k+1): + key = text[i:i+k] + if key.isspace(): + continue + + d[key] = d.get(key, 0) + 1 + + count = sum(d.values()) + + return {key: val/count for (key, val) in d.items()} + + +class Sample: + def __init__(self, language="??", text=""): + self.language = language + self.frequencies = dict() + self._ranked_ngrams = dict() + + if text: + self._extract(text) + + def _extract(self, text): + for k in range(1, 4): + self.frequencies.update(extract_ngram_freqs(text, k)) + + @property + def ranked_ngrams(self): + if not self._ranked_ngrams: + ordered_ngrams = sorted(self.frequencies.items(), key=lambda kv: -kv[1])[:TOP_NGRAM_COUNT] + self._ranked_ngrams = dict(zip([key for (key, freq) in ordered_ngrams], itertools.count(0))) + + return self._ranked_ngrams + + def compare(self, other): + """take k most common + use frequencies x order + use letter, digrams, trigrams + use absolute x square""" + """make a set difference of keys, multiply its size by the max score""" + res = sum(abs(v-other.ranked_ngrams.get(k, len(other.ranked_ngrams))) for (k, v) in self.ranked_ngrams.items()) + \ + sum(abs(v-self.ranked_ngrams.get(k, len(self.ranked_ngrams))) for (k, v) in other.ranked_ngrams.items()) + + return res + + def print_overview(self): + print(f"Sample({self.language}):") + + for freqs in self.frequencies: + x = [ + (k, round(v, 3)) + for (k, v) in sorted(freqs.items(), key=lambda kv: -kv[1]) + ] + print(" ", x[:8], "...", x[-8:]) + + print() + + +def identify(text, models): + sample = Sample(text=text) + + return sorted(models, key=lambda m: m.compare(sample))[0].language