Niet Abraham Lincoln1 heeft de zogenoemde Bixbybrief2 uit 1864 geschreven, maar wel zijn secretaris. Tot die conclusie kwam een groep experts in de forensische linguïstiek op basis van een computationele tekstanalyse. De brief geldt als één van de mooiste stukken proza van een Amerikaanse president.

de Bixbybrief
Abraham Lincoln (links) en een latere kopie van de Bixbybrief (rechts).

Boston, 25 november 1864. Bij Lydia Parker Bixby valt een handgeschreven brief in de bus afkomstig van niemand minder dan Abraham Lincoln, de president van de Verenigde Staten van Amerika die op dat moment al dik drie jaar in een burgeroorlog verwikkeld zijn met de Geconfedereerde Staten van Amerika. Liefst vijf zonen van mevrouw Bixby zijn in dat conflict gesneuveld. In een poging om haar lijden te verzachten, schrijft hij haar enkele troostende woorden. Diezelfde dag verschijnt de brief ook in enkele lokale kranten waar hij lezers massaal naar de keel grijpt. Een legende is geboren.

Meteen rijzen echter vragen over de auteur van de brief. Die is dan wel met "A. Lincoln" ondertekend, toch vermoeden velen dat zijn secretaris John Hay3 de tekst heeft geschreven. Deze stelling bewijzen, is schier onmogelijk, ook al omdat de originele brief vrij snel verloren gaat. Andere analysetechnieken op basis van onder meer stijl en woordkeuze schieten eveneens te kort, hoofdzakelijk omdat de Bixbybrief vrij beknopt is en zo te weinig aanknopingspunten biedt.

Met een nieuwe techniek hebben experts in de forensische linguïstiek verbonden aan de universiteit van Manchester de brief nu toch aan een grondige analyse kunnen onderwerpen. Ze concluderen dat Hay de ware auteur is. De techniek heet $$n$$-gram tracing en legt linguïstische sequenties in teksten bloot, ook als die erg kort zijn. Eerst hebben ze 500 teksten van Lincoln en 500 teksten van Hay geanalyseerd. Met die resultaten in het achterhoofd, legden ze vervolgens de Bixbybrief onder de loep. Concreet gingen ze op zoek naar delen van woorden die overeenkwamen met de schrijfstijl van Lincoln en Hay (of juist niet).

Hun onderzoek werpt nieuw licht op de Bixbybrief, die sinds lang bekend staat als een van de mooiste stukken proza van Lincoln en van een Amerikaanse president tout court. Overal in de VS zijn passages uit de brief op standbeelden en monumenten aangebracht. Oud-president George W. Bush4 las de brief op 11 september 2011 voor naar aanleiding van de 10e verjaardag van de aanslagen in New York en de brief komt ook voor in de film Saving private Ryan5 van Steven Spielberg uit 1998.

Overigens is de Bixbybrief mogelijk gedeeltelijk op leugens gebaseerd. Hoewel mevrouw Bixby verklaarde dat vijf van haar zonen in de burgeroorlog waren gesneuveld, zouden in werkelijkheid liefst twee onder hen het conflict overleefd hebben. Volgens sommigen heeft ze dit verzwegen omdat ze voor één van hen een overlevingspensioen trok. Anderen menen dat ze in werkelijkheid sympathieën koesterde voor de Geconfedereerde Staten.

Opgave

Om de auteur van een tekst te ontmaskeren, worden bij $$n$$-gram tracing eerste profielen opgesteld van de tekst en van teksten die met heel grote zekerheid toegeschreven worden aan enkele mogelijke auteurs. We gebruiken het volgende tekstbestand als voorbeeld om uit te leggen hoe zo'n profiel wordt opgebouwd.

Knock-knock.
Who's there?
To.
To who?
No, to whom.

Eerst wordt de tekst opgeschoond door

  1. alle hoofdletters om te zetten naar kleine letters

  2. alle karakters die geen letter zijn te vervangen door een onderstrepingsteken (_)

  3. alle opeenvolgende onderstrepingstekens te vervangen door één enkel onderstrepingsteken

  4. onderstrepingstekens vooraan en achteraan te verwijderen

Bij het opschonen worden enkel de 26 letters van het alfabet (az) als letters beschouwd, dus geen witruimtekarakters6, leestekens of letters met diakritische tekens7. De voorbeeldtekst wordt op die manier opgeschoond tot

knock_knock_who_s_there_to_to_who_no_to_whom

Daarna wordt de opgeschoonde tekst opgesplitst in $$n$$-grammen, waarbij een $$n$$-gram niets anders is dan een reeks van $$n \in \mathbb{N}_0$$ opeenvolgende karakters. De voorbeeldtekst bestaat bijvoorbeeld uit de volgende 3-grammen:

kno   kno   who   the   to_   who   _to
 noc   noc   ho_   her   o_t   ho_   to_
  ock   ock   o_s   ere   _to   o_n   o_w
   ck_   ck_   _s_   re_   to_   _no   _wh
    k_k   k_w   s_t   e_t   o_w   no_   who
     _kn   _wh   _th   _to   _wh   o_t   hom

Deze voorstelling geeft ook expliciet aan dat de $$n$$-grammen elkaar gedeeltelijk overlappen. Het aantal opeenvolgende $$n$$-grammen in de opgeschoonde versie van tekst $$t$$ wordt genoteerd als $$c_n^t$$. Als $$t$$ het voorbeeldbestand is, dan geldt dat $$c_3^t = 42$$. De verzameling van alle $$n$$-grammen in de opgeschoonde versie van tekst $$t$$ wordt genoteerd als $$\Omega_n^t$$.

Het profiel van een tekst $$t$$ is niets anders dan een frequentietabel van de $$n$$-grammen in de opgeschoonde versie van $$t$$. Het aantal keer dat $$n$$-gram $$\omega$$ voorkomt in de opgeschoonde versie van tekst $$t$$ wordt genoteerd als $$p_n^t(\omega)$$. Als $$t$$ het voorbeeldbestand is dan zien we dat $$p_3^t(\texttt{the}) = 1$$ (groen), $$p_3^t(\texttt{_wh}) = 3$$ (blauw) en $$p_3^t(\texttt{o_t}) = 2$$ (oranje).

De laatste stap van $$n$$-gram tracing bestaat erin om het profiel van een tekst $$t$$ waarvan de auteur moet bepaald worden en het profiel van een tekst $$a$$ die worden toegeschreven aan een bekende auteur (dit mag ook een bundeling van teksten van die auteur zijn) te gebruiken om de mogelijke attributie van de auteur aan de tekst te bepalen aan de hand van de formule \[ -\sum_{\omega \in \Omega_n^t}p_n^t(\omega) \ln\left(\frac{1 + p_n^a(\omega)}{c_n^a}\right) \] waarbij $$\ln(x)$$ staat voor de natuurlijke logaritme van $$x$$. Hoe groter de attributie, hoe groter de kans dat tekst $$t$$ geschreven werd door de auteur van tekst $$a$$. Gevraagd wordt:

De profielen die aan de functies aantal_ngrammen en attributie doorgegeven worden zijn dictionaries (dict) zoals die teruggegeven worden door de functie profiel en mogen nooit gewijzigd worden. De tekstbestanden die aan de functie profiel doorgegeven worden, gebruiken de UTF-88 tekencodering. Bij het openen van een tekstbestand bestand.txt kan je de gebruikte tekencodering meegeven aan de parameter encoding van de ingebouwde functie open:

>>> open('bestand.txt', 'r', encoding='utf-8')

Voorbeeld

In onderstaande voorbeeldsessie gaan we ervan uit dat de tekstbestanden knock.txt9, bixby.txt10, lincoln.txt11, hay.txt12 en obama.txt13 zich in de huidige directory bevinden.

>>> opschonen("What's wrong? NOTHING's wrong!")
'what_s_wrong_nothing_s_wrong'
>>> opschonen("Knock-knock. Who's there? To. To who? No, to whom.")
'knock_knock_who_s_there_to_to_who_no_to_whom'
>>> opschonen('The past, the present, and the future walked into a bar. It was tense.')
'the_past_the_present_and_the_future_walked_into_a_bar_it_was_tense'

>>> ngrammen("What's wrong? NOTHING's wrong!")
['w', 'h', 'a', 't', '_', 's', '_', 'w', 'r', 'o', 'n', 'g', '_', 'n', 'o', 't', 'h', 'i', 'n', 'g', '_', 's', '_', 'w', 'r', 'o', 'n', 'g']
>>> ngrammen("Knock-knock. Who's there? To. To who? No, to whom.", 3)
['kno', 'noc', 'ock', 'ck_', 'k_k', '_kn', 'kno', 'noc', 'ock', 'ck_', 'k_w', '_wh', 'who', 'ho_', 'o_s', '_s_', 's_t', '_th', 'the', 'her', 'ere', 're_', 'e_t', '_to', 'to_', 'o_t', '_to', 'to_', 'o_w', '_wh', 'who', 'ho_', 'o_n', '_no', 'no_', 'o_t', '_to', 'to_', 'o_w', '_wh', 'who', 'hom']
>>> ngrammen('The past, the present, and the future walked into a bar. It was tense.', n=2)
['th', 'he', 'e_', '_p', 'pa', 'as', 'st', 't_', '_t', 'th', 'he', 'e_', '_p', 'pr', 're', 'es', 'se', 'en', 'nt', 't_', '_a', 'an', 'nd', 'd_', '_t', 'th', 'he', 'e_', '_f', 'fu', 'ut', 'tu', 'ur', 're', 'e_', '_w', 'wa', 'al', 'lk', 'ke', 'ed', 'd_', '_i', 'in', 'nt', 'to', 'o_', '_a', 'a_', '_b', 'ba', 'ar', 'r_', '_i', 'it', 't_', '_w', 'wa', 'as', 's_', '_t', 'te', 'en', 'ns', 'se']

>>> knock = profiel('knock.txt14', 3)
>>> len(knock)
27
>>> knock['the']
1
>>> knock['_wh']
3
>>> knock['o_t']
2
>>> aantal_ngrammen(knock)
42

>>> bixby = profiel('bixby.txt15', n=3)
>>> len(bixby)
456
>>> bixby['the']
17
>>> bixby['in_']
3
>>> bixby['f_t']
4
>>> aantal_ngrammen(bixby)
743

>>> lincoln = profiel('lincoln.txt16', n=3)
>>> attributie(bixby, lincoln)
5209.447183892647

>>> hay = profiel('hay.txt17', n=3)
>>> attributie(bixby, hay)
5216.17091674669

>>> obama = profiel('obama.txt18', n=3)
>>> attributie(bixby, obama)
5079.372864440405

Epiloog

In 2013 werkten twee journalisten van The Sunday Times19 samen met professor Patrick Juola20 van de universiteit van Duquesne (VSA) om J.K. Rowling21 te ontmaskeren als de ware auteur van Koekoeksjong22, het boek dat ze in 2013 onder het pseudoniem Robert Galbraith publiceerde. Ook daarvoor gebruikten ze een variant van de n-gram tracing techniek.

koekoeksjong
Coverillustratie van de roman Koekoeksjong die JK Rowling schreef onder het pseudoniem Robert Galbraith, en die door critici de hemel werd in geprezen.

Het verhaal werd breed uitgesmeerd in de pers, met onder andere een uitgebreid artikel in de New York Times23. In het tijdschrift Time24 wordt uitgelegd hoe deze ontdekking tot stand kwam:

As one part of his work, Juola uses a program to pull out the hundred most frequent words across an author's vocabulary. This step eliminates rare words, character names and plot points, leaving him with words like of and but, ranked by usage. Those words might seem inconsequential, but they leave an authorial fingerprint on any work. "Propositions and articles and similar little function words are actually very individual," Juola says. "It's actually very, very hard to change them because they're so subconscious."

Bronnen