Seite 1 von 1
n-Gramme
Verfasst: Montag 19. März 2012, 22:58
von MarcelF6
Guten Abend miteinander
Ich habe die folgende Funktion, welche alle n-Gramme (0<n<4) eines gegebenen Wortes ausgeben sollte:
Code: Alles auswählen
def trigrams(text):
unigrams, bigrams, trigrams = {}, {}, {}
for i, c in enumerate(text):
unigrams[c] = unigrams.get(c, 0) + 1
bigrams[text[i:i+2]] = unigrams.get(c, 0)
trigrams[text[i:i+3]] = unigrams.get(c, 0)
trigrams.update(bigrams)
trigrams.update(unigrams)
return trigrams
print trigrams('Kralle')
Wenn ich wie hier "Kralle" angebe, erwarte ich folgende Ausgabe:
{'a': 1, 'all': 1, 'le': 1, 'e': 1, 'ral': 1, 'al': 1, 'l': 2, 'Kr': 1, 'r': 1, 'ra': 1, 'K': 1, 'Kra': 1, 'll': 1, 'lle': 1}
ABER: Mit meiner Funktion erhalte ich momentan noch 2 bei 'le', obwohl 'le' nur einmal vorhanden ist.
Auch bei anderen Worten ist es immer dieses eine Bigramm, das falsch ist.
Wo steckt hier bloss der Fehler? :S
Re: n-Gramme
Verfasst: Montag 19. März 2012, 23:13
von EyDu
Ohne es mir jetzt im Detail angeschaut zu haben, aber lass dir mal in der Schleife ``c``, ``text[i:i+2]`` und ``text[i:i+3]`` ausgeben. Dann würde ich über deren Länge nachdenken und warum diese Teilweise falsch ist.
Re: n-Gramme
Verfasst: Montag 19. März 2012, 23:28
von MarcelF6
Danke für die schnelle Antwort. Fehler bereits korrigiert - habe +1 geschrieben statt die 1 in die Klammer

Danke für den Hinweis

Re: n-Gramme
Verfasst: Montag 19. März 2012, 23:32
von MarcelF6
Oh nein, das war doch nicht der Fehler.
Hatte das hier korrigiert:
Aber in der ursprünglichen Version war das korrekt.
Das Problem ist ja, dass wenn zwei gleiche Buchstaben auftauchen, dass dann das zweite eine Vorkommnis-Zahl 2 erhält etc.. Dieser Fehler wirkt sich dann natürlich aus...(hier: das "l").
Aber wie lässt sich das beheben?
Re: n-Gramme
Verfasst: Montag 19. März 2012, 23:40
von BlackJack
@MarcelF6: Lass mich mal raten: Du hast den Code für die Unigramme von irgendwo fertig her und jetzt die Aufgabe den um Bi- und Trigramme zu erweitern und versuchst jetzt durch wildes rumprobieren das Problem zu lösen…
Re: n-Gramme
Verfasst: Montag 19. März 2012, 23:40
von EyDu
Das Problem ist eigentlich, das du den völlig falschen Ansatzt wählst. Warum machst du nicht einfach drei Schleifen oder zwei in einander verschachtelte?
Re: n-Gramme
Verfasst: Dienstag 20. März 2012, 00:20
von MarcelF6
Ok, also mit den Schleifen sähe es so aus:
Code: Alles auswählen
def trigrams(text):
unigrams, bigrams, trigrams = {}, {}, {}
for i, c in enumerate(text):
unigrams[text[i:i+1]] = unigrams.get(c, 0) + 1
for i, c in enumerate(text):
bigrams[text[i:i+2]] = bigrams.get(c, 0) + 1
for i, c in enumerate(text):
trigrams[text[i:i+3]] = trigrams.get(c, 0) + 1
trigrams.update(bigrams)
trigrams.update(unigrams)
return trigrams
Den Fehler allerdings konnte ich immernoch nicht ausmerzen. Bei Bigrammen, die eigentlich mehrfach vorkommen, wird z.T. immernoch eine falsche Anzahl ausgegeben. Mit den Indizes stimmt es sicher...
PS: Nein, der Code (auch nicht Teile davon) stammt nicht von extern. Sonst würde er wahrscheinlich fehlerls funktionieren

Re: n-Gramme
Verfasst: Dienstag 20. März 2012, 02:29
von bords0
Re: n-Gramme
Verfasst: Dienstag 20. März 2012, 10:34
von MarcelF6
Das habe ich gar nicht bemerkt. Ja, nun ist klar, wo sich der Fehler befindet.
Für die Behebung habe ich nun einfach zusätzliche Abfragen eingefügt.Die Abfragen selbst stimmen so, also sie liefern immer den erwarteten Wert zurück. Was aber stimmt mit dem jeweiligen Inhalt nicht?
Wenn ich z.B. bei den Trigrammen nur noch zwei Buchstaben erwische, dann sollte die Anzahl unter Bigrammen um 1 erhöht werden (sofern dieselbe Folge dort nicht schon gezählt wurde).
So schauts momentan aus:
Code: Alles auswählen
def trigrams(text):
unigrams, bigrams, trigrams = {}, {}, {}
for i, c in enumerate(text):
unigrams[text[i:i+1]] = unigrams.get(c, 0) + 1
for i, c in enumerate(text):
if (len(text[i:i+2])) == 2:
bigrams[text[i:i+2]] = bigrams.get(c, 0) + 1
elif (len(text[i:i+2])) == 1:
bigrams[text[i:i+2]] = unigrams.get(c, 0) + 1
for i, c in enumerate(text):
if (len(text[i:i+3])) == 3:
trigrams[text[i:i+3]] = trigrams.get(c, 0) + 1
elif (len(text[i:i+3])) == 2:
trigrams[text[i:i+3]] = bigrams.get(c, 0) + 1
elif (len(text[i:i+3])) == 1:
trigrams[text[i:i+3]] = unigrams.get(c, 0) + 1
trigrams.update(bigrams)
trigrams.update(unigrams)
return trigrams
Danke vielmals für die Hinweise!
Re: n-Gramme
Verfasst: Dienstag 20. März 2012, 12:45
von EyDu
Hättets du meinen ersten Hinweis auch nur ausprobiert, dann hättest du den Fehler auch selber gefunden. Nun sollte dir auch klar sein, warum es falsch ist jedes Mal bis zur Länge des des Worts zu iterieren.
Code: Alles auswählen
>>> import collections
>>> def ngram(word, n):
... result = collections.defaultdict(int)
... length = len(word)
... for i in range(n):
... for j in range(length-i):
... c = word[j:j+i+1]
... result[c] += 1
... return result
Re: n-Gramme
Verfasst: Dienstag 20. März 2012, 14:44
von MarcelF6
Ah dein Code kann beliebige n-Gramme bearbeiten - Super!

Ich habe mich doch nochmal hingesetzt und den Code bearbeitet. Mittlerweilen funktioniert es genau so, wie es sollte

Jupii

..aber auch dein n-Gram-Code hab ich gleich getestet (und gespeichert

)
Re: n-Gramme
Verfasst: Dienstag 20. März 2012, 15:07
von pillmuncher
Oder so (ab Python 2.7):
Code: Alles auswählen
from collections import Counter
def ngrams(word, length):
k = len(word)
for i in xrange(1, length + 1):
for j in xrange(k - i + 1):
yield word[j:j + i]
print list(ngrams(word='Kralle', length=3))
print dict(Counter(ngrams(word='Kralle', length=3)))
Ergebnis:
Code: Alles auswählen
['K', 'r', 'a', 'l', 'l', 'e', 'Kr', 'ra', 'al', 'll', 'le', 'Kra', 'ral', 'all', 'lle']
{'a': 1, 'all': 1, 'le': 1, 'e': 1, 'll': 1, 'K': 1, 'l': 2, 'al': 1, 'Kr': 1, 'r': 1, 'ra': 1, 'Kra': 1, 'ral': 1, 'lle': 1}