Seite 1 von 2

Bigramme

Verfasst: Dienstag 26. August 2014, 12:14
von desperation63
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

Re: Bigramme

Verfasst: Dienstag 26. August 2014, 12:39
von BlackJack
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()

Re: Bigramme

Verfasst: Dienstag 26. August 2014, 12:52
von desperation63
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.

Re: Bigramme

Verfasst: Dienstag 26. August 2014, 13:06
von BlackJack
@desperation63: Naja, denn Text halt auf Worte aufteilen und für jedes Wort dann die Funktion aufrufen.

Re: Bigramme

Verfasst: Dienstag 26. August 2014, 13:11
von desperation63
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.

Re: Bigramme

Verfasst: Dienstag 26. August 2014, 13:15
von BlackJack
@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()

Re: Bigramme

Verfasst: Dienstag 26. August 2014, 14:09
von nezzcarth
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))
Eine Zwischenfrage:
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.)

Re: Bigramme

Verfasst: Dienstag 26. August 2014, 15:27
von BlackJack
@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)

Re: Bigramme

Verfasst: Dienstag 26. August 2014, 15:43
von nezzcarth
@BlackJack:
Danke sehr, die Lösung find' ich gut :) Ich hatte mit deinem Ansatz von oben ein wenig rumgespielt:

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)]
Aber ich denke, das ist nicht sonderlich hübsch.

Re: Bigramme

Verfasst: Mittwoch 27. August 2014, 04:25
von desperation63
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.

Re: Bigramme

Verfasst: Mittwoch 27. August 2014, 09:50
von desperation63
Hat jemand eine Idee, wie ich die Bigramme durchzählen könnte und dann die Bigramme 2er verschiedener Texte vergleichen kann anhand ihrer Vorkommnisse?

Re: Bigramme

Verfasst: Mittwoch 27. August 2014, 10:45
von BlackJack
@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()

Re: Bigramme

Verfasst: Mittwoch 27. August 2014, 10:59
von cofi
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).

Re: Bigramme

Verfasst: Donnerstag 28. August 2014, 20:49
von desperation63
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.

Re: Bigramme

Verfasst: Freitag 29. August 2014, 17:55
von desperation63
Hat keiner ne Idee? Ich komm grad leider nicht weiter.

Re: Bigramme

Verfasst: Sonntag 31. August 2014, 22:53
von desperation63
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?

Re: Bigramme

Verfasst: Sonntag 31. August 2014, 23:07
von BlackJack
@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.

Re: Bigramme

Verfasst: Montag 1. September 2014, 16:46
von nezzcarth
@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.

Re: Bigramme

Verfasst: Montag 1. September 2014, 23:21
von desperation63
@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?

Re: Bigramme

Verfasst: Montag 1. September 2014, 23:41
von EyDu
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.