Pythonscript zur Textkorpusanalyse

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
PR1AN
User
Beiträge: 4
Registriert: Donnerstag 24. Februar 2011, 10:40

hallo allerseits!

jeden tag eine neue herausforderung... heut hab ich mir zur aufgabe gemacht einen großen textkorpus bestehend aus 400.000 zeilen mit einem regex-file zu durchforsten. hab mir diesbezüglich auch schon vieles überlegt und wie jeder gute koch hab ich mir auch schon was zurechtgelegt. ich bin linguist und programmiertechnisch relativ "beschränkt" (die wahrheit tut hier echt dem auge weh :) ). erfahrungen hab ich hauptsächlich in java, jedoch möchte ich, auf empfehlung von freunden hin, gerne python ausprobieren. mir wurde gesagt, dass python für meine zwecke besser geeignet ist.

nun zu meinem plan:
der textkorpus (kam durch grep zustande) = fileA
die regexdatei = fileRX

was ich nun machen möchte ist fileA mit fileRX durchforsten und sobald ein item gematched wird sollte diese zeile gelöscht werden. dies dient sozusagen um festzustellen wieviele zeilen ich nicht treffe und um zu vermeiden, dass manche zeilen mehrfach gematched werden.

leider kann ich mir nicht tagelang tutorials durchlesen um dieses problem zu lösen und wollte euch um gedankenanstöße bitten. ein hinweis zum richtigen ort wo ich zu diesem problem näheres nachlesen kann wäre auch schon spitze.

lg,
PR1AN am Poden
BlackJack

@PR1AN: Mindestens das Tutorial in der Python-Dokumentation sollte man einmal durchgearbeitet haben. Da bekommt man einen guten Überblick über die Sprache und die grundlegenden Datentypen. Unter anderem auch über Dateien und wie man die am einfachsten und sichersten zeilenweise einlesen kann. Stichworte Dateiobjekte sind "iterable" und die ``with``-Anweisung.

Dann wäre PEP 8 -- Style Guide for Python Code vielleicht eine nützliche Lektüre und Python Is Not Java um einigen schlechten Angewohnheiten von Java entgegen zu wirken. ;-)

Wenn Du mit regulären Ausdrücken arbeiten möchtest, dann gibt es dafür das `re`-Modul aus der Standardbibliothek.

Ansonsten ist mir die Problemstellung noch nicht so ganz klar. Was bedeutet es eine Datei mit einer Anderen zu durchsuchen? Ist in der 'fileRX' ein regulärer Ausdruck? Oder viele?

Zeilen aus Textdateien löschen geht im Grunde nicht. Du müsstest also eine neue Datei schreiben, mit allen Zeilen, die den Test "überlebt" haben.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

PR1AN hat geschrieben: nun zu meinem plan:
der textkorpus (kam durch grep zustande) = fileA
die regexdatei = fileRX

was ich nun machen möchte ist fileA mit fileRX durchforsten und sobald ein item gematched wird sollte diese zeile gelöscht werden. dies dient sozusagen um festzustellen wieviele zeilen ich nicht treffe und um zu vermeiden, dass manche zeilen mehrfach gematched werden.
Ich denke Du müsstest an dieser Stelle ein wenig ausführlicher beschreiben, was Du planst und was Du als Ergebnis wünscht. So etwas wie "löschen, um rauszufinden" klingt verdächtig nach Vorgehensweisen aus der Shell, wo man oftmals in seinen Mitteln beschränkt ist.

Ich kann mir unter Textkorpus auch wenig vorstellen.

Zeig Doch einfach mal einen kurzen Korpus, dazu einige RegExps und demonstriere "per Hand", was Du als Ergebnis haben willst. Also im Sinne von "ich habe diese Zeilen und werfe den regExp drauf. Nun will ich wissen, wie oft...?" oder "Als Ergebnis sollen dann diese Zeile übrig bleiben".
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
PR1AN
User
Beiträge: 4
Registriert: Donnerstag 24. Februar 2011, 10:40

hey danke für die schnelle antwort!

@BlackJack:
genau, fileRX ist eine textdatei welche eine unzahl von lexemen (wörter) enthaltet welche mit hilfe von regex modifiziert wurden (einfaches Bsp: Bücher --> B(ue|ü)cher). sobald einer dieser begriffe gematched wird, möchte ich die zeile in welcher er zutrifft aus der suche ausschließen, da sonst der nächste begriff wieder über die selbe zeile iteriert und diesen dann auch matchen könnte (sofern konkordanz gegeben ist). jede zeile in fileA steht für ein objekt (z.B.: buchtitel) und sollte max. 1mal erfasst werden.
ich hoffe das ist jetzt etwas besser beschrieben.

wenn ich jede trefferzeile in einer neuen datei ausgeben lasse, dann habe ich erst wieder mehrere gleiche zeilen und der hund jagt wieder seinen schwanz. im grunde sollte das resultat eine umkehr des suchergebnisses sein.

@hyperion:
deine vermutung ist nicht unberechtigt. ich habe tatsächlich das meiste in der shell durchgekaut, jedoch bin ich gerade wegen des lösch-problems an meine grenzen gestoßen.

ein beispiel:
die begriffe Pädagogik und sozial (würde so ca. aussehn: [Pp](ae|ä)dagog(ik|isch|e)|[Ss]ozial) aus der fileRX treffen nacheinander auf die zeile:
# pädagogische Sozialanthropologie
nun würde ich für diese zeile 2 treffer angezeigt bekommen. ich möchte aber dass die zeile nur einmal gematched wird.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Dann dreh doch die Reihenfolge um! Anstelle die Lexeme zu durchlaufen und gegen die Zeilen aus deiner Textdatei zu matchen, mach es einfach umgekehrt. Damit kannst Du nach dem ersten Treffer die weiteren Tests vorzeitig abbrechen.

Mal so im Pseudo-Code:

Code: Alles auswählen

for line in text:
    for lexem in lexeme:
        if test(lexem, line):
            # mache etwas mit dem Ergebnis
            break
Das kann man sicherlich noch schöner formulieren, etwa mit any() o.ä.

Bevor wir hier ins Detail gehen stellen sich mir noch zwei Fragen:

1.) Was willst Du denn als Ergebnis haben? Denn davon hängt ja einiges ab
2.) Gibt es denn eine Lib, die diese Lexeme in RegExps wandelt oder sonst wie gegen einen Text validiert?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@PR1AN: Der Ausdruck '[Pp](ae|ä)dagog(ik|isch|e)|[Ss]ozial' würde nur einmal matchen, oder meinst Du '[Pp](ae|ä)dagog(ik|isch|e)' und '[Ss]ozial' sind *zwei* Ausdrücke in verschiedenen Zeilen?

Ungetestet:

Code: Alles auswählen

import re
from itertools import ifilter


def main():
    with open('rx.txt') as lines:
        regexes = [re.compile(line.rstrip()) for line in lines]
    
    def predicate(line):
        return not any(r.match(line) for r in regexes)
    
    with open('in.txt') as lines:
        with open('out.txt') as out_file:
            out_file.writelines(ifilter(predicate, lines))


if __name__ == '__main__':
    main()
PR1AN
User
Beiträge: 4
Registriert: Donnerstag 24. Februar 2011, 10:40

@hyperion:
das mit dem umkehren ist ein guter punkt... würde wohl auch effizienter sein, da 40000 zeilen "besser" auf 6000 lexeme zu überprüfen sind als umgekehrt (rein rechentechnisch). ich werds mir mal genauer anschaun. bin außerdem durch BlackJacks hinweis gerade auf einen blöden fehler draufgekommen.

@BlackJack:
jetzt fällt mir gerade auf WARUM manche "zeilen" mehrmals gematched haben. da ich sie automatisiert erstellt habe, hab ichs nicht so genau durchgschaut und jetzt sehe ich, dass ich wohl einige die carriage returns nicht entfernt habe als ich sie in der shell weiterverarbeitet hab. somit dürfte tatsächlich nur ein lexem eine zeile matchen da alle meine regex durch pipes getrennt sind.

und danke für deine scriptidee! werds gerne heut abend austesten und berichte dann wie's gelaufen ist. jetzt ist leider grad nicht genug zeit dafür.


herzlichsten dank nochmal euch beiden. ich denke (um jbs-thema für pythonneulinge zu zitieren), ich kann die stützräder jetzt mal wieder runternehmen und versuchen selbst zu fahren. hoffe ich kann mich wieder melden falls ich auf maul gefallen bin :)
PR1AN
User
Beiträge: 4
Registriert: Donnerstag 24. Februar 2011, 10:40

und täglich grüßt die shell :)

hab jetzt das script soweit fertig und es läuft auch ganz hervorragend (danke nochmal BlackJack&hyperion für die hilfe). einziges problem das ich habe, ist die limitierung bei der gesamtsumme der regulären ausdrücke. meine regex-datei ist ~ 150kb groß und python beklagt sich jedes mal, dass nur max. 100 abfragegruppen aufgerufen werden können.
hab diesbezüglich schon etwas recherchiert und es wird öfters davon geredet ein dictionary anzulegen um dies zu umgehen... kann sich da jemand von euch was drunter vorstellen? hab echt keine ahnung wie das geht. :K
Hyperion hat geschrieben: 2.) Gibt es denn eine Lib, die diese Lexeme in RegExps wandelt oder sonst wie gegen einen Text validiert?
nein, leider hab ich sowas noch nicht gefunden, darum funzt auch die idee mit der umkehr bei der abfrage nicht. eine datei besteht aus regex und die andere aus plain-text (kann den plain-text wohl kaum über die regex-begriffe iterieren lassen, oder?)

EDIT:

erledigt. habs in JAVA geschrieben.
Antworten