De machine learning-benadering om een computer de (natuurlijke) taal van een tekst te leren herkennen, bestaat er in modellen te trainen op basis van referentieteksten voor elke bestaande taal. De vermoedelijke taal van een gegeven tekst correspondeert dan met het model dat best aansluit bij die tekst. In de praktijk is het al mogelijk om betrouwbare taalherkenning te bekomen op basis van eenvoudige statistische modellen.

Het eenvoudige taalmodel dat we hier zullen gebruiken, bestaat uit de frequentietabel van alle $$n$$-grammen van een tekstbestand. Een $$n$$-gram is niets anders dan een reeks van $$n$$ opeenvolgende karakters die op eenzelfde regel voorkomen. Vóór de $$n$$-grammen van een regel bepaald worden, moet men eerst alle hoofdletters omzetten in kleine letters, witruimte vooraan en achteraan verwijderen, en witruimte tussen woorden telkens vervangen door één enkele spatie. Als witruimte beschouwen we een reeks opeenvolgende spaties en tabs. Eventuele newlines op het einde van een regel wordt nooit in een $$n$$-gram opgenomen. Merk op dat spaties en leestekens wel deel kunnen uitmaken van $$n$$-grammen.

n-grammen
De regel tekst "een BaNaaN." bestaat in totaal uit tien $$2$$-grammen, die hier voor de duidelijkheid genummerd zijn. Analoog bestaat diezelfde tekst uit negen $$3$$-grammen, acht $$4$$-grammen, enzovoort.

Om te bepalen hoe dicht het $$n$$-gram gebaseerde taalmodel van een tekst $$t$$ aansluit bij het $$n$$-gram gebaseerde taalmodel van een referentietekst $$r$$ (merk dus op dat in beide gevallen dezelfde lengte voor de $$n$$-grammen moet gebruikt worden), wordt de volgende score berekend: \[ s_r^n(t) = \sum_{m \in \mathcal{N}_t^n} f_t^n(m) \log\left(\frac{1 + f_r^n(m)}{c_r^n}\right) \] Hierbij stelt $$\mathcal{N}_t^n$$ de verzameling van alle $$n$$-grammen van de tekst $$t$$ voor, stelt $$f_t^n(m)$$ (resp. $$f_r^n(m)$$) het aantal voorkomens van het $$n$$-gram $$m$$ in de tekst $$t$$ (resp. $$r$$) voor, en stelt $$c_r^n$$ het totaal aantal $$n$$-grammen in de referentietekst $$r$$ voor. $$\log$$ staat voor de natuurlijke logaritme. Hoe hoger de score, hoe beter het taalmodel van de tekst aansluit bij het taalmodel van de referentietekst.

Opgave

Voorbeeld

Klik hier1 om een ZIP bestand te downloaden dat alle bestanden bevat die in onderstaande voorbeelden gebruikt worden. Het eerste voorbeeld werkt met kleine bestanden, zodat je makkelijk kunt volgen wat er moet gebeuren.

>>> taalmodel('fruit.nl')
{' b': 1, 'aa': 1, 'en': 1, 'ba': 1, 'n.': 1, 'ee': 1, 'na': 1, 'an': 2, 'n ': 1}
>>> taalmodel('fruit.en', 3)
{' ba': 1, 'ana': 2, 'a b': 1, 'na.': 1, 'nan': 1, 'ban': 1}
>>> taalmodel('fruit.fr', 4)
{'ne b': 1, 'une ': 1, 'e ba': 1, 'ane.': 1, 'nane': 1, 'bana': 1, 'anan': 1, ' ban': 1}

>>> model_nl = taalmodel('fruit.nl')
>>> model_en = taalmodel('fruit.en')
>>> model_fr = taalmodel('fruit.fr')
>>> overeenkomst(model_nl, model_en)
-16.11228418967414
>>> overeenkomst(model_nl, model_fr)
-18.7491848109244
>>> overeenkomst(model_en, model_nl)
-13.450867444376364

>>> modellen = {'en':model_en, 'fr':model_fr}
>>> taalherkenning(model_nl, modellen)
('en', -16.11228418967414)

In onderstaand voorbeeld worden taalmodellen getraind op basis van de tekst van de Universele verklaring van de rechten van de mens. Volgens het Guinness Recordboek is dit het document dat naar het meest aantal talen werd vertaald. Hieruit leiden we af dat het bigram "e•" (hierbij stelt een spatie voor) resp. 352 en 330 keer voorkomt in de Nederlandse en Engelse vertaling van de tekst. Het trigram dat het vaakst voorkomt in de Engelse vertaling is "the", zijnde 151 keer. Ondanks de eenvoud van de methode, stellen we toch vast dat de taal van alle testbestanden correct herkend wordt.

>>> model_en = taalmodel('training.en', 3)
>>> [(trigram, aantal) for trigram, aantal in model_en.items() if aantal == max(model_en.values())][0]
('the', 151)

>>> model_en = taalmodel('training.en')
>>> model_nl = taalmodel('training.nl')
>>> model_fr = taalmodel('training.fr')
>>> model_en['e '], model_fr['e '], model_nl['e ']
(330, 509, 352)

>>> tekst_en = taalmodel('test.en')
>>> overeenkomst(tekst_en, model_en)
-230.33674380150703
>>> overeenkomst(tekst_en, model_fr)
-259.04854263587083
>>> overeenkomst(tekst_en, model_nl)
-261.7988606708526

>>> modellen = {'en':model_en, 'fr':model_fr, 'nl':model_nl}
>>> taalherkenning(tekst_en, modellen)
('en', -230.33674380150703)
>>> tekst_fr = taalmodel('test.fr')
>>> taalherkenning(tekst_fr, modellen)
('fr', -129.8597104636806)
>>> tekst_nl = taalmodel('test.nl')
>>> taalherkenning(tekst_nl, modellen)
('nl', -185.44606662491037)