Basis¶
Wat een tekst over zichzelf zegt¶
Een tekst is voor een computer eerst een lange rij tekens. Tel je die tekens op de goede manier, dan komt er iets uit dat je vooraf niet zag: hoe groot de woordenschat van de schrijver is, welk woord hij het vaakst gebruikt, hoeveel woorden hij maar één keer nodig had.
Daar hangt meer aan vast dan het lijkt. Leesbaarheidsscores werken zo, plagiaatdetectie werkt zo, en in 2013 werd op deze manier vastgesteld dat de onbekende debutant Robert Galbraith in werkelijkheid J.K. Rowling was: haar woordgebruik verried haar.
Je bouwt in deze opgave het gereedschap dat dat soort vragen beantwoordt.
De kern: een dictionary¶
Om te tellen hoe vaak elk woord voorkomt heb je iets nodig dat een woord aan een getal koppelt. Dat is precies wat een dictionary is.
Voor de woorden ["spam", "spam", "taart", "spam"]:
{"spam": 3, "taart": 1}
Je loopt de woorden één voor één langs. Ken je het woord nog niet, dan zet je het
erin met de waarde 1. Ken je het al, dan tel je er één bij op:
if word in counts:
counts[word] = counts[word] + 1
else:
counts[word] = 1
Dat is de hele truc. De rest van deze opgave is eromheen.
De teksten¶
In assets/teksten/ staan twee bestanden.
kort.txt is één zin, zodat je met de hand kunt narekenen of je functie klopt:
Ik wil taarten en 42 en spam. Ik krijg toch spam en taarten voor de vakantie? Ik wil 42 taarten!
vuurtoren.txt is een stuk van ruim tweehonderd woorden. Daar zie je pas iets
interessants.
Wat je gaat maken¶
Stap |
Functie |
Doet |
|---|---|---|
1 |
|
de tekst uit een bestand lezen |
2 |
|
de tekst opdelen in losse woorden |
3 |
|
tellen hoe vaak elk woord voorkomt |
4 |
|
het meest gebruikte woord vinden |
5 |
|
tellen hoeveel woorden maar één keer voorkomen |
6 |
|
alles samen afdrukken als verslag |
Stap 1: read_text(filename)¶
Leest het bestand met die naam en geeft de hele inhoud terug als één string.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Dit deed je in week 6 al. Anders dan toen lees je nu het hele bestand in één keer in plaats van regel voor regel, want voor tellen maakt het niet uit waar de regels ophouden.
Hint
Binnen het with-blok geeft file.read() je de hele inhoud als één string.
# jouw oplossing
assert len(read_text("assets/teksten/kort.txt")) == 97
assert read_text("assets/teksten/kort.txt")[0:6] == "Ik wil"
Stap 2: word_list(text)¶
Geeft een lijst van de woorden in de tekst, allemaal in kleine letters en zonder leestekens.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Twee dingen moeten weg, en allebei om dezelfde reden: anders telt hetzelfde woord dubbel.
Hoofdletters. "De" aan het begin van een zin en "de" in het midden zijn
hetzelfde woord.
Leestekens. Zonder ingrijpen levert "spam." een ander woord op dan
"spam".
Hint
text.lower() maakt van elke letter een kleine letter. Loop daarna de tekens
langs en vervang elk leesteken door een spatie voordat je split() gebruikt.
Neem als leestekens in elk geval .,!?;: mee.
# jouw oplossing
assert word_list("Ik wil taarten!") == ["ik", "wil", "taarten"]
assert word_list("Spam, spam.") == ["spam", "spam"]
assert len(word_list(read_text("assets/teksten/kort.txt"))) == 20
assert len(word_list(read_text("assets/teksten/vuurtoren.txt"))) == 227
Stap 3: count_words(words)¶
Geeft een dictionary die elk woord koppelt aan het aantal keren dat het voorkomt.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Dit is de kern van de opgave, en de code ervoor staat hierboven al.
# jouw oplossing
assert count_words(["spam", "spam", "taart"]) == {"spam": 2, "taart": 1}
assert count_words([]) == {}
assert count_words(word_list(read_text("assets/teksten/kort.txt")))["taarten"] == 3
Korter met .get()
Nu je .get() uit het college kent, mag count_words ook zo:
counts[word] = counts.get(word, 0) + 1
Dat is dezelfde functie, alleen zonder de if ... else: bestaat word nog
niet, dan geeft .get(word, 0) de standaardwaarde 0 terug, en tel je er
gewoon één bij op. Beide vormen zijn goed; kies wat voor jou het leesbaarst is.
Stap 4: most_frequent(counts)¶
Geeft het woord dat het vaakst voorkomt.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Hint
for word in counts: loopt de sleutels van een dictionary langs, en met
counts[word] heb je het bijbehorende aantal. Onthoud het beste woord tot nu toe
en het aantal dat erbij hoort, zoals je bij een hoogste getal ook zou doen.
Let op gelijkspel
In kort.txt komen meerdere woorden even vaak voor. Welk van die woorden je
functie teruggeeft hangt af van hoe je het gelijkspel afhandelt; de test
hieronder gebruikt daarom vuurtoren.txt, waar dat niet speelt.
# jouw oplossing
assert most_frequent({"spam": 2, "taart": 1}) == "spam"
assert most_frequent(count_words(word_list(read_text("assets/teksten/vuurtoren.txt")))) == "een"
Stap 5: words_used_once(counts)¶
Geeft het aantal woorden dat precies één keer voorkomt.
Aanroep |
Resultaat |
|---|---|
|
|
|
|
Dit getal zegt meer dan je zou denken. Een tekst waarin bijna elk woord één keer voorkomt is een tekst die zich niet herhaalt, en dat is een van de dingen waaraan je een schrijver herkent.
# jouw oplossing
assert words_used_once({"spam": 2, "taart": 1}) == 1
assert words_used_once({}) == 0
assert words_used_once(count_words(word_list(read_text("assets/teksten/vuurtoren.txt")))) == 94
Stap 6: report(filename)¶
Leest het bestand en drukt een verslag af. Geeft niets terug.
Voor assets/teksten/vuurtoren.txt:
Woorden: 227
Verschillende: 134
Meest gebruikt: een
Eenmalig gebruikt: 94
Alles wat je hiervoor hebt gemaakt komt hier samen. Deze functie rekent zelf niets uit; hij roept aan en drukt af.
Hint
Het aantal verschillende woorden hoeft geen eigen functie: len() op een
dictionary geeft het aantal sleutels.
# jouw oplossing
report("assets/teksten/vuurtoren.txt")
Uitproberen¶
Zet zelf een tekst in assets/teksten/ en haal hem door report. Een verhaal,
een verslag, een hoofdstuk uit een boek dat je leest.
Vergelijk daarna twee teksten van verschillende schrijvers. Zie je verschil in het aantal eenmalig gebruikte woorden?
Tot slot¶
Je hebt nu een dictionary die woorden aan aantallen koppelt. In het werkcollege maak je er een die woorden aan hun opvolgers koppelt, en daarmee kun je tekst laten schrijven die klinkt als de schrijver die je erin stopte.
Dezelfde structuur, een andere vraag.
En één ding om over na te denken. Dat woordgebruik een schrijver verraadt is handig bij het opsporen van plagiaat, en het is precies wat de auteur van een pseudoniem liever niet had gehad. Hetzelfde gereedschap, twee tegengestelde belangen.