From 89ea2a863dbe03f7f66fe197e6888216c90c6f92 Mon Sep 17 00:00:00 2001 From: "jannis.grundmann" Date: Wed, 20 Sep 2017 15:22:13 +0200 Subject: [PATCH] lemmatizer gebaut --- lemmatization-de.txt | 1 + stopwords-de.txt | 622 +++++++++++++++++++++++++++++++++++++++++++ testo.py | 154 +++++++++-- testra.py | 76 +++--- 4 files changed, 798 insertions(+), 55 deletions(-) create mode 100644 stopwords-de.txt diff --git a/lemmatization-de.txt b/lemmatization-de.txt index 184eda3..2bb0958 100644 --- a/lemmatization-de.txt +++ b/lemmatization-de.txt @@ -165813,6 +165813,7 @@ Gruselnde Gruselnden Gruselndere Gruselnderen Gruselndste Gruselndsten Gruß Gruße +Gruß Grüße Gruß Grüße Gruß Grüßen Gruß Grußes diff --git a/stopwords-de.txt b/stopwords-de.txt new file mode 100644 index 0000000..1a66fd3 --- /dev/null +++ b/stopwords-de.txt @@ -0,0 +1,622 @@ +a +ab +aber +ach +acht +achte +trotz +achten +achter +achtes +ag +alle +allein +allem +allen +aller +allerdings +alles +allgemeinen +als +also +am +an +ander +andere +anderem +anderen +anderer +anderes +anderm +andern +anderr +anders +au +auch +auf +aus +ausser +ausserdem +außer +außerdem +b +bald +bei +beide +beiden +beim +beispiel +bekannt +bereits +besonders +besser +besten +bin +bis +bisher +bist +c +d +d.h +da +dabei +dadurch +dafür +dagegen +daher +dahin +dahinter +damals +damit +danach +daneben +dank +dann +daran +darauf +daraus +darf +darfst +darin +darum +darunter +darüber +das +dasein +daselbst +dass +dasselbe +davon +davor +dazu +dazwischen +daß +dein +deine +deinem +deinen +deiner +deines +dem +dementsprechend +demgegenüber +demgemäss +demgemäß +demselben +demzufolge +den +denen +denn +denselben +der +deren +derer +derjenige +derjenigen +dermassen +dermaßen +derselbe +derselben +des +deshalb +desselben +dessen +deswegen +dich +die +diejenige +diejenigen +dies +diese +dieselbe +dieselben +diesem +diesen +dieser +dieses +dir +doch +dort +drei +drin +dritte +dritten +dritter +drittes +du +durch +durchaus +durfte +durften +dürfen +dürft +e +eben +ebenso +ehrlich +ei +ei, +eigen +eigene +eigenen +eigener +eigenes +ein +einander +eine +einem +einen +einer +eines +einig +einige +einigem +einigen +einiger +einiges +einmal +eins +elf +en +ende +endlich +entweder +er +ernst +erst +erste +ersten +erster +erstes +es +etwa +etwas +euch +euer +eure +eurem +euren +eurer +eures +f +folgende +früher +fünf +fünfte +fünften +fünfter +fünftes +für +g +gab +ganz +ganze +ganzen +ganzer +ganzes +gar +gedurft +gegen +gegenüber +gehabt +gehen +geht +gekannt +gekonnt +gemacht +gemocht +gemusst +genug +gerade +gern +gesagt +geschweige +gewesen +gewollt +geworden +gibt +ging +gleich +gott +gross +grosse +grossen +grosser +grosses +groß +große +großen +großer +großes +gut +gute +guter +gutes +h +hab +habe +haben +habt +hast +hat +hatte +hatten +hattest +hattet +heisst +her +heute +hier +hin +hinter +hoch +hätte +hätten +i +ich +ihm +ihn +ihnen +ihr +ihre +ihrem +ihren +ihrer +ihres +im +immer +in +indem +infolgedessen +ins +irgend +ist +j +ja +jahr +jahre +jahren +je +jede +jedem +jeden +jeder +jedermann +jedermanns +jedes +jedoch +jemand +jemandem +jemanden +jene +jenem +jenen +jener +jenes +jetzt +k +kam +kann +kannst +kaum +kein +keine +keinem +keinen +keiner +keines +kleine +kleinen +kleiner +kleines +kommen +kommt +konnte +konnten +kurz +können +könnt +könnte +l +lang +lange +leicht +leide +lieber +los +m +machen +macht +machte +mag +magst +mahn +mal +man +manche +manchem +manchen +mancher +manches +mann +mehr +mein +meine +meinem +meinen +meiner +meines +mensch +menschen +mich +mir +mit +mittel +mochte +mochten +morgen +muss +musst +musste +mussten +muß +mußt +möchte +mögen +möglich +mögt +müssen +müsst +müßt +n +na +nach +nachdem +nahm +natürlich +neben +nein +neue +neuen +neun +neunte +neunten +neunter +neuntes +nicht +nichts +nie +niemand +niemandem +niemanden +noch +nun +nur +o +ob +oben +oder +offen +oft +ohne +ordnung +p +q +r +recht +rechte +rechten +rechter +rechtes +richtig +rund +s +sa +sache +sagt +sagte +sah +satt +schlecht +schluss +schon +sechs +sechste +sechsten +sechster +sechstes +sehr +sei +seid +seien +sein +seine +seinem +seinen +seiner +seines +seit +seitdem +selbst +sich +sie +sieben +siebente +siebenten +siebenter +siebentes +sind +so +solang +solche +solchem +solchen +solcher +solches +soll +sollen +sollst +sollt +sollte +sollten +sondern +sonst +soweit +sowie +später +startseite +statt +steht +suche +t +tag +tage +tagen +tat +teil +tel +tritt +trotzdem +tun +u +uhr +um +und +und? +uns +unse +unsem +unsen +unser +unsere +unserer +unses +unter +v +vergangenen +viel +viele +vielem +vielen +vielleicht +vier +vierte +vierten +vierter +viertes +vom +von +vor +w +wahr? +wann +war +waren +warst +wart +warum +was +weg +wegen +weil +weit +weiter +weitere +weiteren +weiteres +welche +welchem +welchen +welcher +welches +wem +wen +wenig +wenige +weniger +weniges +wenigstens +wenn +wer +werde +werden +werdet +weshalb +wessen +wie +wieder +wieso +will +willst +wir +wird +wirklich +wirst +wissen +wo +woher +wohin +wohl +wollen +wollt +wollte +wollten +worden +wurde +wurden +während +währenddem +währenddessen +wäre +würde +würden +x +y +z +z.b +zehn +zehnte +zehnten +zehnter +zehntes +zeit +zu +zuerst +zugleich +zum +zunächst +zur +zurück +zusammen +zwanzig +zwar +zwei +zweite +zweiten +zweiter +zweites +zwischen +zwölf +über +überhaupt +übrigens \ No newline at end of file diff --git a/testo.py b/testo.py index a88bb85..24b7daa 100644 --- a/testo.py +++ b/testo.py @@ -21,6 +21,9 @@ from textacy import Vectorizer import warnings import configparser as ConfigParser import sys +import hunspell +from postal.parser import parse_address + csv.field_size_limit(sys.maxsize) @@ -48,13 +51,33 @@ THESAURUS = list(textacy.fileio.read_csv(thesauruspath, delimiter=";")) DE_PARSER = spacy.load("de") #todo spacherkennung idee: verschiedene Corpi für verschiedene Sprachen -de_stop_words=list(__import__("spacy." + DE_PARSER.lang, globals(), locals(), ['object']).STOP_WORDS) + +SPELLCHECKER = hunspell.HunSpell('/usr/share/hunspell/de_DE.dic', + '/usr/share/hunspell/de_DE.aff') -LEMMAS=config.get("filepath","lemmas") +def replaceRockDots(): + return lambda string: re.sub(r'[ß]', "ss", (re.sub(r'[ö]', "oe", (re.sub(r'[ü]', "ue", (re.sub(r'[ä]', "ae", string.lower()))))))) + +""" +de_stop_words= set( + list(__import__("spacy." + DE_PARSER.lang, globals(), locals(), ['object']).STOP_WORDS) + + list(textacy.fileio.read_file_lines("stopwords-de.txt")) +) + + +LEMMAS = list(textacy.fileio.read_file_lines(filepath="lemmatization-de.txt")) VORNAMEN = list(textacy.fileio.read_file_lines("vornamen.txt")) +""" +de_stop_words = list(map(textacy.preprocess.normalize_whitespace,textacy.fileio.read_file_lines("de_stop_words.txt"))) +LEMMAS = list(textacy.fileio.read_file_lines("lemmas.txt")) +VORNAMEN = list(map(textacy.preprocess.normalize_whitespace,textacy.fileio.read_file_lines("firstnames.txt"))) + +print(de_stop_words[10:30]) +print(LEMMAS[10:30]) +print(VORNAMEN[10:30]) regex_specialChars = r'[`\-=~!#@,.$%^&*()_+\[\]{};\'\\:"|?]' regex_topLvl = r'\.[a-z]{2,3}(\.[a-z]{2,3})?' @@ -172,8 +195,10 @@ def removeENT(ent_list): def remove_words_containing_Numbers(): return lambda tok: not bool(re.search('\d', tok.lower_)) - - +""" +def remove_words_containing_topLVL(): + return lambda tok: not bool(re.search(regex_topLvl, tok.lower_)) +""" def remove_words_containing_specialCharacters(): return lambda tok: not bool(re.search(regex_specialChars, tok.lower_)) @@ -196,17 +221,23 @@ def remove_first_names(): ############# strings +def remove_addresses(string): + pass #todo + def stringcleaning(stringstream, funclist): for string in stringstream: for f in funclist: string = f(string) yield string +def cut_after(word="gruss"): + return lambda string: string.rpartition(word)[0] if word in string else string def seperate_words_on_regex(regex=regex_specialChars): return lambda string: " ".join(re.compile(regex).split(string)) + def remove_words_containing_topLVL(): return lambda string: " ".join([w.lower() for w in string.split() if not re.search(regex_topLvl, w) ]) @@ -227,47 +258,107 @@ def replaceSharpS(replace_with="ss"): return lambda string: re.sub(r'[ß]',replace_with,string.lower()) -def replaceRockDots(): - return lambda string: re.sub(r'[ß]', "ss", (re.sub(r'[ö]', "oe", (re.sub(r'[ü]', "ue", (re.sub(r'[ä]', "ae", string.lower()))))))) - def fixUnicode(): return lambda string: textacy.preprocess.fix_bad_unicode(string.lower(), normalization=u'NFC') - +""" def lemmatizeWord(word,filepath=LEMMAS): - """http://www.lexiconista.com/datasets/lemmatization/""" for line in list(textacy.fileio.read_file_lines(filepath=filepath)): if word.lower() == line.split()[1].strip().lower(): return line.split()[0].strip().lower() return word.lower() # falls nix gefunden wurde +""" + +def create_lemma_dicts(lemmalist=LEMMAS): + w_dict = {} + lem_dict = {} + + for i, line in enumerate(lemmalist): + try: + lem_word_pair = line.split() + + if len(lem_word_pair) != 2: + print(line) + + lemma = lem_word_pair[0].strip().lower() + + word = lem_word_pair[1].strip().lower() + except: + print(line) + + if lemma not in lem_dict: + lem_dict[lemma] = i + + if word not in w_dict: + w_dict[word] = lem_dict[lemma] + + l_dict = {v: k for k, v in lem_dict.items()} # switch key/values + + return l_dict,w_dict + +lemma_dict,word_dict = create_lemma_dicts() + +def lemmatizeWord(word,l_dict=lemma_dict,w_dict=word_dict): + #mehrmals machen + for i in range(3): + try: + word = l_dict[w_dict[word.lower()]] if word.lower() in w_dict else word.lower() + except: + print(word) + return word + +def autocorrectWord(word,spellchecker=SPELLCHECKER): + try: + return spellchecker.suggest(word)[0] + except: + return word + + +""" def lemmatize(): - #todo https://alpha.spacy.io/docs/usage/adding-languages#lemmatizer return lambda doc: " ".join([lemmatizeWord(tok.lower_) for tok in doc]) +""" +def lemmatize(): + return lambda string: " ".join([lemmatizeWord(s.lower()) for s in string.split()]) +def autocorrect(): + return lambda string: " ".join([autocorrectWord(s.lower()) for s in string.split()]) -def processTextstream(textstream, string_funclist, tok_funclist, parser=DE_PARSER, single_doc_func=None): +def processTextstream(textstream, pre_parse=None, in_parse=None, post_parse=None, parser=DE_PARSER): """ :param textstream: string-gen :param funclist: [func] :param parser: spacy-parser :return: string-gen """ - #zuerst die string-methoden - pipe = parser.pipe(stringcleaning(textstream,string_funclist)) + #pre_parse + if pre_parse is not None: + textstream = stringcleaning(textstream, pre_parse) + + + pipe = parser.pipe(textstream) + tokens=[] for doc in pipe: tokens = [tok for tok in doc] - #dann die auf tokens - tokens = processTokens(tokens,tok_funclist) + # in_parse + if in_parse is not None: + tokens = processTokens(tokens, in_parse) + + + # post_parse + if post_parse is not None: + + #todo vllt doch lieber eine große funktion basteln, dieses zusammenfrickeln nervt + yield post_parse(parser(" ".join([tok.lower_ for tok in tokens]))) + - if single_doc_func is not None: - yield single_doc_func(parser(" ".join([tok.lower_ for tok in tokens]))) else: yield " ".join([tok.lower_ for tok in tokens]) @@ -286,30 +377,43 @@ def processTokens(tokens, funclist): - -string_comp=[ +pre_parse=[ fixUnicode(), replaceRockDots(), remove_words_containing_topLVL(), - seperate_words_on_regex() + seperate_words_on_regex(), + lemmatize(), + cut_after(), + autocorrect() + ] -tok_comp=[ +custom_words=["geehrt","dame","herr","hilfe","problem","lauten","bedanken","voraus","hallo","gerne","freundlich","fragen","fehler","bitten","ehre" + ] + + +in_parse=[ #removeENT(["PERSON"]), + #todo addressen enfernen + #idee rechtschreibkorrektur + #idee thesaurus + remove_words_containing_Numbers(), + removePOS(["PUNCT","SPACE","NUM"]), - removeWords(de_stop_words), + + removeWords(de_stop_words+custom_words), remove_long_words(), remove_short_words(), - remove_first_names(), #keepPOS(["NOUN"]), ] -single_doc_func = lemmatize() +post_parse=None + @@ -364,7 +468,7 @@ ticketcorpus = textacy.Corpus(DE_PARSER) ## add files to textacy-corpus, printlog("add texts to textacy-corpus") ticketcorpus.add_texts( - processTextstream(csv_to_contentStream(path2csv,"Description"), string_funclist=string_comp, tok_funclist=tok_comp, single_doc_func=single_doc_func) + processTextstream(csv_to_contentStream(path2csv,"Description"), pre_parse=pre_parse, in_parse=in_parse, post_parse=post_parse) ) for i in range(10): diff --git a/testra.py b/testra.py index 2850c1f..c0752d5 100644 --- a/testra.py +++ b/testra.py @@ -1,43 +1,22 @@ # -*- coding: utf-8 -*- +import time +start = time.time() import corenlp as corenlp import os import re + +import spacy import textacy import nltk from textblob_de import TextBlobDE from textblob_de import PatternParser - -filepath = "lemmatization-de.txt" +#from polyglot.text import Text +import hunspell +from postal.parser import parse_address - -blob = TextBlobDE(str(textacy.fileio.read_file("teststring.txt")),parser=PatternParser(pprint=True, lemmata=True)) - -print(blob.parse()) - - - - - -#erste spalte zu {lemma : id} . zweite spalte zu {word : id} - - - -"""http://www.lexiconista.com/datasets/lemmatization/""" - -lemma2id = {} -word2id = {} - -for id,line in enumerate(list(textacy.fileio.read_file_lines(filepath=filepath))): - - lemma = line.split()[0].strip().lower() - if lemma not in lemma2id: - lemma2id[lemma] = id - - word = line.split()[1].strip().lower() - - word2id[word] = lemma2id[word] +print(parse_address(str(textacy.fileio.read_file("teststring.txt")))) @@ -90,4 +69,41 @@ for s in stringcleaning((w for w in words),[seperate_words_on_regex()]): #print(re.sub(r'[`\-=~!@#$%^&*()_+\[\]{};\'\\:"|<,./>?]'," ",w)) #print(re.sub(r'\.[a-z]{2,3}(\.[a-z]{2,3})?', " ", w)) -""" \ No newline at end of file +""" + + +""" +de_stop_words= set( + list(__import__("spacy." + DE_PARSER.lang, globals(), locals(), ['object']).STOP_WORDS) + + list(textacy.fileio.read_file_lines("stopwords-de.txt")) +) + + +LEMMAS = list(textacy.fileio.read_file_lines(filepath="lemmatization-de.txt")) + +VORNAMEN = list(textacy.fileio.read_file_lines("vornamen.txt")) + + +#blob = Text(str(textacy.fileio.read_file("teststring.txt")))#,parser=PatternParser(pprint=True, lemmata=True)) + +#print(blob.entities) + +de_stop_words = list(map(replaceRockDots(),de_stop_words)) +LEMMAS = list(map(replaceRockDots(),LEMMAS)) +VORNAMEN = list(map(replaceRockDots(),VORNAMEN)) + +de_stop_words = list(map(textacy.preprocess.normalize_whitespace,de_stop_words)) +LEMMAS = list(map(textacy.preprocess.normalize_whitespace,LEMMAS)) +VORNAMEN = list(map(textacy.preprocess.normalize_whitespace,VORNAMEN)) + + + + +textacy.fileio.write_file_lines(LEMMAS,"lemmas.txt") +textacy.fileio.write_file_lines(VORNAMEN,"firstnames.txt") +textacy.fileio.write_file_lines(de_stop_words,"de_stop_words.txt") +""" + +end = time.time() +print("\n\n\nTime Elapsed Topic:{0}\n\n".format(end - start)) +