Richtig zufrieden bin ich mit dem Porter-Stemmer-Algorithmus nicht. Er erkennt den gemeinsamen Wortstamm sehr gut, aber so habe ich es mir nicht vorgestellt. Er macht aus z.B. Töchterchen, Tochter, Töchter den Stamm tocht, und aus Brüder, Bruder, brüderlich, brüderlicherseits den Stamm brud, aber aus sehen macht er seh und aus sahen und sah wird sah. Ich wünsche mir aber Worte, die ich auch im Wörterbuch nachschlage und wenn ich nach sah oder sahen suche, schaue ich unter sehen. Oder wenn ich nach sprechen oder gesprochen oder sprach suche, schaue ich unter sprechen. Diese Grundformen nennt man aber Lemma und es existieren Programme, nämlich Lemmatisierer, um Wörter auf ihre Grundform, ihre Wörterbuchform, zurück zu führen. Außerdem will ich es jetzt wirklich wissen und mich interessieren auch die POS (Part of Speech)-Tags eines Satzes. Diese Tags sagen mir, ob ein Wort ein Nomen, ein Name oder eines von 10 Arten von Verben oder ein bestimmtes Adjektiv oder Adverb ist. Jetzt, wo ich schon am Thema NLP (Natural Language Processing) bin, kann ich mir das Gebiet ja auch zu Nutze machen. Als POS-Tagger, die für deutsche Sätze funktionieren habe ich nur den Stanford POS-Tagger und den IMS Tree Tagger gefunden. Nur der IMS Tree Tagger vermag es aber, mir auch das Lemma eines Wortes zu geben.
Im nachfolgenden Codebeispiel, zerlegt mir der Stanford POS-Tagger einen Satz in Tokens gibt dann für jedes Token dessen POS-Tag aus. Die Quellcodebeispiele sind alle in Java, welches die vorherrschende Sprache im NLP zu sein scheint. Es muss wohl doch keine so langsamen Sprache sein. Allerdings erledigen alle Programme, die ich gefunden habe, die Arbeit statisch. Sie sind nicht in andere Software eingebunden, sondern ein Text wird durch NLP-Software rechenintensiv verarbeitet und mit dem Ausgabetext kann man dann machen, was man will.
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import edu.stanford.nlp.ling.Sentence;
import edu.stanford.nlp.ling.TaggedWord;
import edu.stanford.nlp.ling.HasWord;
import edu.stanford.nlp.tagger.maxent.MaxentTagger;
class TaggerDemo {
public static void main(String[] args) throws Exception {
MaxentTagger tagger = new MaxentTagger("models/german-hgc.tagger");
String s = "Aber alle Griechen nahmen Sosthenes, den Synagogenvorsteher, mit sich und schlugen ihn vor dem Richterstuhl. Und Gallio kümmerte sich um keinen dieser (Vorgänge).";
InputStream is = new ByteArrayInputStream(s.getBytes());
BufferedReader br = new BufferedReader(new InputStreamReader(is));
List<List<HasWord>> sentences = tagger.tokenizeText(br);
for (List<HasWord> sentence : sentences) {
ArrayList<TaggedWord> tSentence = tagger.tagSentence(sentence);
System.out.println(Sentence.listToString(tSentence, false));
}
}
}
Die Ausgabe:
Aber/KON alle/PIDAT Griechen/NN nahmen/VVFIN Sosthenes/NE ,/$, den/ART Synagogenvorsteher/NN ,/$, mit/APPR sich/PRF und/KON schlugen/VVFIN ihn/PPER vor/APPR dem/ART Richterstuhl/NN ./$.
Und/KON Gallio/NE kümmerte/VVFIN sich/PRF um/APPR keinen/PIAT dieser/PDAT -LRB-/TRUNC Vorgänge/NN -RRB-/TRUNC ./$.
Schade, dass es für den Stanford POS Tagger keinen Lemmatisierer gibt. Den Tokenizer, welcher mir Sätze in Tokens zerlegt kann ich aber gebrauchen. So etwas muss ich ja nicht selbst programmieren. Im nachfolgenden Codeschnipsel tut der IMS Tree Tagger seinen Dienst und gibt sowohl Lemmas als auch POS-Tags aus.
import static java.util.Arrays.asList;
import org.annolab.tt4j.TokenHandler;
import org.annolab.tt4j.TreeTaggerWrapper;
public class tt4j {
public static void main(String[] args) throws Exception {
// Point TT4J to the TreeTagger installation directory. The executable is expected
// in the "bin" subdirectory - in this example at "/opt/treetagger/bin/tree-tagger"
System.setProperty("treetagger.home", "/home/bileser/Downloads/IMSTreeTagger/tree-tagger-linux-3.2");
TreeTaggerWrapper<String> tt = new TreeTaggerWrapper<String>();
try {
tt.setModel("/home/bileser/Downloads/IMSTreeTagger/tree-tagger-linux-3.2/german.par:iso8859-1");
tt.setHandler(new TokenHandler<String>() {
public void token(String token, String pos, String lemma) {
System.out.println(token + "\t" + pos + "\t" + lemma);
}
});
String[] list = new String[] {
"Und",
"Gott",
"sah",
",",
"dass",
"es",
"gut",
"war",
"."
};
tt.process(asList(list));
}
finally {
tt.destroy();
}
}
}
Die Ausgabe:
Und KON und
Gott NN Gott
sah VVFIN sehen
, $, ,
dass KOUS dass
es PPER es
gut ADJD gut
war VAFIN sein
. $. .
Durch POS-Tags und Lemmatisierung habe ich vor, Lückentexte zu generieren und rechnerisch die wichtigsten Sätze von Texten anhand der Häufigkeiten der Lemmas von Nomen, Verben und anderen Satzbestandteilen zu ermitteln. Zu den Themen automatische Generierung von Zusammenfassungen oder Fragen findet man im Netz allerhand Papers. So tief will ich denn in die Wissenschaft nicht eintauchen.
