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