Hallo liebe Leute,
ich habe letztens einen Text über Text-Kategorisierung gelesen und habe überlegt das Ganze in Python 3.4 umzusetzen. Dabei wird ein Text in Bigramme aufgeteilt bzw. jedes einzelne Wort des Textes. Die einzelnen Bigramme sollen wie folgt aus sehen. Bei dem Wort "TEXT" sollen folgende Bigramme erscheinen: _T, TE, EX, XT, T_
Das soll dann mit allen Worten des Textes gemacht werden und das Vorkommen der einzelnen Bigramme soll gezählt werden.
Es soll also immer ein Bigramm mehr erstellt werden als das Wort Buchstaben besitzt. Leider fehlt mir der Ansatz wie ich diese Bigramme erstellen kann. Könnte mir da jemand helfen?
Vielen Danke im Voraus.
Viele Grüße,
desperation63
Bigramme
Da würden sich die `itertools` anbieten:
Code: Alles auswählen
from itertools import chain, tee
def iter_bigrams(word):
it_a, it_b = tee(chain('_', word, '_'))
next(it_b)
return (a + b for a, b in zip(it_a, it_b))
def main():
print(list(iter_bigrams('TEXT'))) # -> ['_T', 'TE', 'EX', 'XT', 'T_']
if __name__ == '__main__':
main()
Das sieht schonmal sehr gut aus, danke. Aber wie kann ich das Prinzip jetzt auf einen ganzen Text anwenden? Wenn ich deinen Code jetzt so übernehme, wie er ist und versuche das ganze statt mit einem Wort mit einem ganzen Text zu machen, dann klappt das leider nicht mehr so gut. Wäre super wenn du mir da noch helfen könntest.
@desperation63: Naja, denn Text halt auf Worte aufteilen und für jedes Wort dann die Funktion aufrufen.
Sprich den Text mit der split()-Funktion bearbeiten das habe ich gemacht, aber wie rufe ich die FUnktion für jedes Wort auf? Das will grad nicht funktionieren.
@desperation63: Schon mal was von Schleifen gehört?
Oder mit der `map()`-Funktion.

Code: Alles auswählen
import re
from itertools import chain, tee
WORD_RE = re.compile(r'\w+')
def iter_words(text):
return (m.group(0) for m in WORD_RE.finditer(text))
def iter_bigrams(word):
it_a, it_b = tee(chain('_', word.upper(), '_'))
next(it_b)
return (a + b for a, b in zip(it_a, it_b))
def iter_bigrams_from_text(text):
return chain.from_iterable(map(iter_bigrams, iter_words(text)))
def main():
print(list(iter_bigrams_from_text('Dies ist ein Text-Text.')))
if __name__ == '__main__':
main()
Eine Zwischenfrage:BlackJack hat geschrieben:Da würden sich die `itertools` anbieten:Code: Alles auswählen
from itertools import chain, tee def iter_bigrams(word): it_a, it_b = tee(chain('_', word, '_')) next(it_b) return (a + b for a, b in zip(it_a, it_b))
Das ließe sich aber nicht so gut auf N-Gramme generalisieren, oder? Für die im Ausgangspost erwähnte Textklassifizierung wäre das allerdings ggf. praktisch (bei dem mir bekannten "klassischen" Ansatz, werden z.B. N-Gramm mit n=1..5 verwendet.)
@nezzcarth: Stimmt das lässt sich nicht so leicht generalisieren. Dafür könnte man dann zum Beispiel eine `collections.deque` mit einer maximalen Länge verwenden (ungetestet):
Code: Alles auswählen
def iter_ngrams(n, word):
ngram = deque('_' * n, n)
for character in chain(word.upper(), '_' * (n - 1)):
ngram.append(character)
yield ''.join(ngram)
@BlackJack:
Danke sehr, die Lösung find' ich gut
Ich hatte mit deinem Ansatz von oben ein wenig rumgespielt:
Aber ich denke, das ist nicht sonderlich hübsch.
Danke sehr, die Lösung find' ich gut

Code: Alles auswählen
def ngrams2(word, n=2, fill='_'):
iterators = tee(chain(fill*n, word, fill*(n-1)), n)
for i in range(len(iterators)):
for iterator in iterators[i:]:
next(iterator)
return [''.join(i) for i in zip(*iterators)]
Das sieht super aus danke. Gibt es auch eine Möglichkeit, dass ich beispielsweise den Bigramme von zwei Texte dann miteinander vergleiche, um eine Differenz zwischen den Texten zu ermitteln, so funktioniert das nämlich bei dieser Text-Kategorisierung.
Hat jemand eine Idee, wie ich die Bigramme durchzählen könnte und dann die Bigramme 2er verschiedener Texte vergleichen kann anhand ihrer Vorkommnisse?
@desperation63: Zählen könnte man mit `collections.Counter` machen:
Code: Alles auswählen
import re
from collections import Counter
from itertools import chain, tee
WORD_RE = re.compile(r'\w+')
def iter_words(text):
return (m.group(0) for m in WORD_RE.finditer(text))
def iter_bigrams(word):
it_a, it_b = tee(chain('_', word.upper(), '_'))
next(it_b)
return (a + b for a, b in zip(it_a, it_b))
def iter_bigrams_from_text(text):
return chain.from_iterable(map(iter_bigrams, iter_words(text)))
def main():
text_a = 'Dies ist ein Test-Text.'
text_b = 'Dies ist ein anderer Test-Text.'
histogram_a = Counter(iter_bigrams_from_text(text_a))
histogram_b = Counter(iter_bigrams_from_text(text_b))
print(histogram_a)
print(histogram_b)
print()
histogram_a.subtract(histogram_b)
print(histogram_a)
if __name__ == '__main__':
main()
- cofi
- Python-Forum Veteran
- Beiträge: 4432
- Registriert: Sonntag 30. März 2008, 04:16
- Wohnort: RGFybXN0YWR0
Je nach Wortmodell sind beispielsweise Set-Operationen hilfreich bei Uebereinstimmung/Differenz.
Und fuer NLP sollte auch nltk nicht unerwaehnt bleiben (die haben z.B. auch Implementierungen fuer n-Gramme und Wortverteilungen).
Und fuer NLP sollte auch nltk nicht unerwaehnt bleiben (die haben z.B. auch Implementierungen fuer n-Gramme und Wortverteilungen).
Michael Markert ❖ PEP 8 Übersetzung ❖ Tutorial Übersetzung (3.x) ⇒ Online-Version (Python 3.3) ❖ Deutscher Python-Insider ❖ Projekte
Danke für die Hilfestellungen jedoch stehe ich vor einem neuen Problem.
Ich habe nur 10 vordefinierte Kategorien und will eine neue Textdatei zu einer Kategorie machen und diese eine Kategorie dann mit den anderen 10 vergleichen. Dabei soll herausgefunden werden welche der 10 Kategorien die geringsten Abweichungen mit der einen neuen Kategorie hat(sprich welche Kategorie hat die meisten gemeinsamen Bigramme mit der neuen Kategorie).
Edit: Die Kategorien sind jeweils als Dictionaries vorhanden.
Hat jemand eine Idee wie ich das umsetzen kann?
Danke im Voraus und danke für die bisherige Hilfe. Ihr seid super
PS: @cofi. nltk möchte ich nicht verwenden, trotzdem danke für den hinweis.
Ich habe nur 10 vordefinierte Kategorien und will eine neue Textdatei zu einer Kategorie machen und diese eine Kategorie dann mit den anderen 10 vergleichen. Dabei soll herausgefunden werden welche der 10 Kategorien die geringsten Abweichungen mit der einen neuen Kategorie hat(sprich welche Kategorie hat die meisten gemeinsamen Bigramme mit der neuen Kategorie).
Edit: Die Kategorien sind jeweils als Dictionaries vorhanden.
Hat jemand eine Idee wie ich das umsetzen kann?
Danke im Voraus und danke für die bisherige Hilfe. Ihr seid super
PS: @cofi. nltk möchte ich nicht verwenden, trotzdem danke für den hinweis.
Hat wirklich niemand eine Idee, wie ich das eine Dictionary mit den anderen 10 abgleichen kann und dann ausgeben kann, mit welchem Dictionary das eine die meisten Übereinstimmungen hat?
@desperation63: Du musst Dir halt eine Methode ausdenken/auswählen die auf dieses Problem bezogen am besten den ”Abstand” zwischen zwei Dictionaries auf eine Zahl abbilden kann. Man könnte die beiden Dictionaries zum Beispiel ”voneinander abziehen”, die Werte als Vektor auffassen, und die Länge beziehungsweise den Betrag davon berechnen.
@desparation63: Vielleicht wäre es einfacher, wenn du verraten könntest, um welchen Text, den du im Eingagspost erwähntest, es sich handelt. Willst du tatsächlich nur das Dictionary mit der größten Schnittmenge? Weshalb berechnest du dann Häufigkeiten?
Ein anderes Verfahren ist basiert bespielsweise darauf, dass man die N-Gramm-Häufigkeiten für jede Kategorie berechnet und in eine Rangfolge bringt. Vergleiche funktionieren dann darüber, dass man die Rangfolgenunterschiede aufsummiert und diejenige Kategorie mit der geringsten Abweichung wählt.
Ein anderes Verfahren ist basiert bespielsweise darauf, dass man die N-Gramm-Häufigkeiten für jede Kategorie berechnet und in eine Rangfolge bringt. Vergleiche funktionieren dann darüber, dass man die Rangfolgenunterschiede aufsummiert und diejenige Kategorie mit der geringsten Abweichung wählt.
@nezzcarth
Das mit den Häufigkeiten hab ich wieder rausgenommen. Der Text an sich ist eig erstmal egal. Ich hab da einfach einen kurzen Beispieltext genommen den ich hier rumfliegen hatte.
Ich habe jetzt erstmal die Schnittmengen von allen Profilen mit dem einen Vergleichsprofil gebildet. Wie gebe ich nun am besten das mit der größten Schnittmenge aus?
Dein Vorschlag hört sich interessant aber sehr kompliziert an. Wie könnte man sowas denn realisieren?
Das mit den Häufigkeiten hab ich wieder rausgenommen. Der Text an sich ist eig erstmal egal. Ich hab da einfach einen kurzen Beispieltext genommen den ich hier rumfliegen hatte.
Ich habe jetzt erstmal die Schnittmengen von allen Profilen mit dem einen Vergleichsprofil gebildet. Wie gebe ich nun am besten das mit der größten Schnittmenge aus?
Dein Vorschlag hört sich interessant aber sehr kompliziert an. Wie könnte man sowas denn realisieren?
Das Stichwort lautet Information Retrieval, in deinem Fall würde sich zunächst mal das Vector Space Model anbieten. Das lässt sich leicht und schnell implementieren. Gehe einfach mal die Wikipedia-Seite zu IR durch und arbeite dich ein wenig ein.
Das Leben ist wie ein Tennisball.