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