def fit(self): # initializing the classifier self.__classifier = KNNClassifier(self.__nn, self.__metric) # relative bow-matrices by category (weighted) rel_category_bow_dict = { cat: self.__wght(self.category_bow_dict[cat]) for cat in self.category_bow_dict } # initializing the cross-validator (5 folds as in main) n_folds = 4 self.__cross_validator = CrossValidation( category_bow_dict=rel_category_bow_dict, n_folds=n_folds)
def test_cross_validation(self): cfg = Config() axi = xapian.Database(cfg.axi) packages = ["gimp","aaphoto","eog","emacs","dia","ferret", "festival","file","inkscape","xpdf"] path = "test_data/.sample_axi" sample_axi = SampleAptXapianIndex(packages,axi,path) rec = Recommender(cfg) rec.items_repository = sample_axi user = User({"gimp":1,"aaphoto":1,"eog":1,"emacs":1}) metrics = [] metrics.append(Precision()) metrics.append(Recall()) metrics.append(F1()) validation = CrossValidation(0.3,5,rec,metrics,0.5) validation.run(user) print validation
def aufgabe2(): # Laden des Brown Corpus CorpusLoader.load() brown = CorpusLoader.brown_corpus() brown_categories = brown.categories() # In dieser Aufgabe sollen unbekannte Dokumente zu bekannten Kategorien # automatisch zugeordnet werden. # # Die dabei erforderlichen numerischen Berechnungen lassen sich im Vergleich # zu einer direkten Implementierung in Python erheblich einfacher mit # NumPy / SciPy durchfuehren. Die folgende Aufgabe soll Ihnen die Unterschiede # anhand eines kleinen Beispiels verdeutlichen. # # Geben Sie fuer jede Katgorie des Brown Corpus die durchschnittliche Anzahl # von Woertern pro Dokument aus. Bestimmen Sie auch die Standardabweichung. # Stellen Sie diese Statistik mit einem bar plot dar. Verwenden Sie dabei # auch Fehlerbalken (siehe visualization.hbar_plot) # # Berechnen Sie Mittelwert und Standardabweichung jeweils: # # - nur mit Python Funktion # hilfreiche Funktionen: sum, float, math.sqrt, math.pow # # - mit NumPy # hilfreiche Funktionen: np.array, np.mean, np.std # # http://docs.python.org/2/library/math.html # http://wiki.scipy.org/Tentative_NumPy_Tutorial # http://docs.scipy.org/doc/numpy/reference/generated/numpy.mean.html # http://docs.scipy.org/doc/numpy/reference/generated/numpy.std.html ####### +++++ Python Implementierung ++++ print 'Python Implementierung' liste = [] for i in brown_categories: a = len(brown.words(categories=i))/len(brown.fileids(categories=i)) print i print a liste.append(a) mittelwert = sum(liste)/len(brown_categories) print 'Mittelwert:' + str(mittelwert) summe = 0 for i in liste: summe +=math.pow(i-mittelwert,2) standard = math.sqrt(summe/len(brown_categories)) #standard = math.sqrt(sum(list)/len(brown_categories)) print 'Standardabweichung:'+str(standard) ####### +++++ Numpy Implementierung ++++ print 'NumPy Implementierung' liste2 = np.array(liste) mittelwert2 = np.mean(liste2, axis=0) print 'Mittelwert:' + str(mittelwert2) standard2 = np.std(liste2, axis=0) print 'Standardabweichung:'+ str(standard2) hbar_plot(liste2, brown_categories, x_err=standard2, title="Words per document") # ********************************** ACHTUNG ************************************** # Die nun zu implementierenden Funktionen spielen eine zentrale Rolle im weiteren # Verlauf des Fachprojekts. Achten Sie auf eine effiziente und 'saubere' Umsetzung. # Verwenden Sie geeignete Datenstrukturen und passende Python Funktionen. # Wenn Ihnen Ihr Ansatz sehr aufwaendig vorkommt, haben Sie vermutlich nicht die # passenden Datenstrukturen / Algorithmen / (highlevel) Python / NumPy Funktionen # verwendet. Fragen Sie in diesem Fall! # # Schauen Sie sich jetzt schon gruendlich die Klassen und deren Interfaces in den # mitgelieferten Modulen an. Wenn Sie Ihre Datenstrukturen von Anfang an dazu # passend waehlen, erleichtert dies deren spaetere Benutzung. Zusaetzlich bieten # diese Klassen bereits etwas Inspiration fuer Python-typisches Design, wie zum # Beispiel Duck-Typing. # # Zu einigen der vorgebenen Intefaces finden Sie Unit Tests in dem Paket 'test'. # Diese sind sehr hilfreich um zu ueberpruefen, ob ihre Implementierung zusammen # mit anderen mitgelieferten Implementierungen / Interfaces funktionieren wird. # Stellen Sie immer sicher, dass die Unit tests fuer die von Ihnen verwendeten # Funktionen erfolgreich sind. # Hinweis: Im Verlauf des Fachprojekts werden die Unit Tests nach und nach erfolg- # reich sein. Falls es sie zu Beginn stoert, wenn einzelne Unit Tests fehlschlagen # koennen Sie diese durch einen 'decorator' vor der Methodendefinition voruebergehend # abschalten: @unittest.skip('') # https://docs.python.org/2/library/unittest.html#skipping-tests-and-expected-failures # Denken Sie aber daran sie spaeter wieder zu aktivieren. # # Wenn etwas unklar ist, fragen Sie! # ********************************************************************************* # # Klassifikation von Dokumenten # # Nachdem Sie sich nun mit der Struktur und den Eigenschaften des Brown # Corpus vertraut gemacht haben, soll er die Datengrundlage fuer die # Evaluierung von Algorithmen zur automatischen Klassifikation von # Dokumenten bilden. # In der Regel bestehen diese Algorithmen aus drei Schritten: # - Vorverarbeitung # - Merkmalsberechnung # - Klassifikation # # Bei der Anwendung auf Dokumente (Texte) werden diese Schritte wie folgt # umgesetzt: # - Vorverarbeitung: Filterung von stopwords und Abbildung von Woertern auf # Wortstaemme. # - Merkmalsberechnung: Jedes Dokument wird numerisch durch einen Vektor # repraesentiert (--> NumPy), der moeglichst die # bzgl. der Klassifikation bedeutungsunterscheidenden # Informationen enthaehlt. # - Klassifikation: Jedem Merkmalsvektor (Dokument) wird ein Klassenindex # (Kategorie) zugeordnet. # # Details finden Sie zum Beispiel in: # http://www5.informatik.uni-erlangen.de/fileadmin/Persons/NiemannHeinrich/klassifikation-von-mustern/m00-www.pdf (section 1.3) # # Eine sehr verbreitete Merkmalsrepraesentation fuer (textuelle) Dokumente sind # sogenannte Bag-of-Words. # Dabei wird jedes Dokument durch ein Histogram (Verteilung) ueber Wortfrequenzen # repraesentiert. Man betrachtet dazu das Vorkommen von 'typischen' Woertern, die # durch ein Vokabular gegeben sind. # # Bestimmen Sie ein Vokabular, also die typischen Woerter, fuer den Brown Corpus. # Berechnen Sie dazu die 500 haeufigsten Woerter (nach stemming und Filterung von # stopwords und Satzzeichen) normalized_words = WordListNormalizer().normalize_words(brown.words())[1] vocab = BagOfWords.most_freq_words(normalized_words, 500) # Berechnen Sie Bag-of-Words Repraesentationen fuer jedes Dokument des Brown Corpus. # Verwenden Sie absolute Frequenzen. # Speichern Sie die Bag-of-Word Repraesentationen fuer jede Kategorie in einem # 2-D NumPy Array. Speichern Sie den Bag-of-Words Vektor fuer jedes Dokument in # einer Zeile, so dass das Array (ndarray) folgende Dimension hat: # |Dokument_kat| X |Vokabular| # # |Dokument_kat| entspricht der Anzahl Dokumente einer Kategorie. # |Vokabular| entspricht der Anzahl Woerter im Vokabular (hier 500). # # Eine einfache Zuordnung von Kategorie und Bag-of-Words Matrix ist durch ein # Dictionary moeglich. # # Implementieren Sie die Funktion BagOfWords.category_bow_dict im Modul features. bow_list = {} for cat in brown_categories: bow_list[cat] = [WordListNormalizer().normalize_words(brown.words(fileids=doc))[1] for doc in brown.fileids(categories=cat)] a = BagOfWords(vocab) print "Merkmalsvektoren erstellt" # Um einen Klassifikator statistisch zu evaluieren, benoetigt man eine Trainingsstichprobe # und eine Teststichprobe der Daten die klassifiziert werden sollen. # Die Trainingsstichprobe benoetigt man zum Erstellen oder Trainieren des Klassifikators. # Dabei werden in der Regel die Modellparameter des Klassifikators statistisch aus den # Daten der Traingingsstichprobe geschaetzt. Die Klassenzugehoerigkeiten sind fuer die # Beispiele aus der Trainingsstichprobe durch so genannte Klassenlabels gegeben. # # Nachdem man den Klassifikator trainiert hat, interessiert man sich normalerweise dafuer # wie gut er sich unter realen Bedingung verhaelt. Das heisst, dass der Klassifikator bei # der Klassifikation zuvor unbekannter Daten moeglichst wenige Fehler machen soll. # Dies simuliert man mit der Teststichprobe. Da auch fuer jedes Beispiel aus der Teststichprobe # die Klassenzugehoerigkeit bekannt ist, kann man am Ende die Klassifikationsergebnisse mit # den wahren Klassenlabels (aus der Teststichprobe) vergleichen und eine Fehlerrate angeben. # In dem gegebenen Brown Corpus ist keine Aufteilung in Trainings und Testdaten vorgegeben. # # Waehlen Sie daher die ersten 80% der Dokumente UEBER ALLE KATEGORIEN als Trainingstichprobe # und die letzten 20% der Dokumente UEBER ALLE KATEGORIEN als Teststichprobe. # # Erklaeren Sie, warum Sie die Stichproben ueber alle Kategorien zusammenstellen MUESSEN. # # Bitte beachten Sie, dass wir im Rahmen des Fachprojekts keinen Test auf unbekannten Testdaten # simulieren. Wir haben ja bereits fuer die Erstellung der Vokabulars (haeufigste Woerter, # siehe oben) den kompletten Datensatz verwendet. # Stattdessen betrachten wir hier ein so genanntes Validierungsszenario, in dem wir die # Klassifikationsleistung auf dem Brown Corpus optimieren. Die Ergebnisse lassen sich somit # nur sehr bedingt auf unbekannte Daten uebertragen. # # Erstellen Sie nun die NumPy Arrays train_samples, train_labels, test_samples und test_labels, # so dass diese mit den estimate und classify Methoden der Klassen im classificaton Modul # verwendet werden koennen. Teilen Sie die Daten wie oben angegeben zu 80% in # Trainingsdaten und 20% in Testdaten auf. # # Hinweis: Vollziehen Sie nach, wie die Klasse CrossValidation im evaluation Modul # funktioniert. Wenn Sie moechten, koennen die Klasse zur Aufteilung der Daten # verwenden. print "Arrays sind generiert" train_labels = np.array(brown_categories).reshape(len(brown_categories), 1) test_labels =np.array(brown_categories).reshape(len(brown_categories), 1) print "Reshaped" cv = CrossValidation(a.category_bow_dict(bow_list), 5) cv2 = cv.corpus_fold(1) train_samples = cv2[0] test_samples = cv2[2] train_labels = cv2[1] test_labels = cv2[3] # Klassifizieren Sie nun alle Dokumente der Teststichprobe nach dem Prinzip des k-naechste- # Nachbarn Klassifikators. Dabei wird die Distanz zwischen dem Merkmalsvektors eines # Testbeispiels und allen Merkmalsvektoren aus der Trainingstichprobe berechnet. Das # Klassenlabel des Testbeispiels wird dann ueber einen Mehrheitsentscheid der Klassenlabels # der k aehnlichsten Merkmalsvektoren aus der Trainingsstichprobe bestimmt. # http://www5.informatik.uni-erlangen.de/fileadmin/Persons/NiemannHeinrich/klassifikation-von-mustern/m00-www.pdf (Abschnitt 4.2.7) # # Verwenden Sie die Euklidische Distanz und betrachten Sie nur den naechsten Nachbarn (k=1). # http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html # # Implementieren Sie die Funktionen estimate und classify in der Klasse KNNClassifier # im Modul classification. classification = KNNClassifier(1, 'euclidean') classification.estimate(train_samples, train_labels) result_knnk = classification.classify(test_samples) # Nachdem Sie mit dem KNNClassifier fuer jedes Testbeispiel ein Klassenlabel geschaetzt haben, # koennen Sie dieses mit dem tatsaechlichen Klassenlabel vergleichen. Dieses koennen Sie wie # bei den Traingingsdaten dem Corpus entnehmen. # # Ermitteln Sie eine Gesamtfehlerrate und je eine Fehlerrate pro Kategorie. # Implementieren Sie dazu die Klasse ClassificationEvaluator im evaluation Modul. # # Warum ist diese Aufteilung der Daten in Training und Test problematisch? Was sagen die Ergebnisse aus? eval = ClassificationEvaluator(result_knnk, test_labels) error_overall = eval.error_rate()[0] error_cat_list = eval.category_error_rates() print "Error Overall" print error_overall print "Error Catlist" print error_cat_list
def aufgabe2(): # Laden des Brown Corpus CorpusLoader.load() brown = CorpusLoader.brown_corpus() brown_categories = brown.categories() # In dieser Aufgabe sollen unbekannte Dokumente zu bekannten Kategorien # automatisch zugeordnet werden. # # Die dabei erforderlichen numerischen Berechnungen lassen sich im Vergleich # zu einer direkten Implementierung in Python erheblich einfacher mit # NumPy / SciPy durchfuehren. Die folgende Aufgabe soll Ihnen die Unterschiede # anhand eines kleinen Beispiels verdeutlichen. # # Geben Sie fuer jede Katgorie des Brown Corpus die durchschnittliche Anzahl # von Woertern pro Dokument aus. Bestimmen Sie auch die Standardabweichung. # Stellen Sie diese Statistik mit einem bar plot dar. Verwenden Sie dabei # auch Fehlerbalken (siehe visualization.hbar_plot) # # Berechnen Sie Mittelwert und Standardabweichung jeweils: # # - nur mit Python Funktion # hilfreiche Funktionen: sum, float, math.sqrt, math.pow # # - mit NumPy # hilfreiche Funktionen: np.array, np.mean, np.std # # http://docs.python.org/2/library/math.html # http://wiki.scipy.org/Tentative_NumPy_Tutorial # http://docs.scipy.org/doc/numpy/reference/generated/numpy.mean.html # http://docs.scipy.org/doc/numpy/reference/generated/numpy.std.html for cat in brown_categories: # python standard libs only # calculating the mean doc_words = 0 docs = brown.fileids(categories=cat) n = float(len(docs)) for doc in docs: doc_words += len(brown.words(doc)) mean = float(doc_words) / n # claculating the std std = 0. for doc in docs: std += math.pow(float(len(brown.words(doc))) - mean, 2) std = math.sqrt(std / n) # using numpy arr_doc_words = np.array([ len(brown.words(doc)) for doc in brown.fileids(categories=cat) ]).astype(float) np_std = np.std(arr_doc_words) # printing the std for each category print("{}\npython: {}, mean={}\nnp:{}, mean={}".format( cat, std, mean, np_std, np.mean(arr_doc_words))) # ********************************** ACHTUNG ************************************** # Die nun zu implementierenden Funktionen spielen eine zentrale Rolle im weiteren # Verlauf des Fachprojekts. Achten Sie auf eine effiziente und 'saubere' Umsetzung. # Verwenden Sie geeignete Datenstrukturen und passende Python Funktionen. # Wenn Ihnen Ihr Ansatz sehr aufwaendig vorkommt, haben Sie vermutlich nicht die # passenden Datenstrukturen / Algorithmen / (highlevel) Python / NumPy Funktionen # verwendet. Fragen Sie in diesem Fall! # # Schauen Sie sich jetzt schon gruendlich die Klassen und deren Interfaces in den # mitgelieferten Modulen an. Wenn Sie Ihre Datenstrukturen von Anfang an dazu # passend waehlen, erleichtert dies deren spaetere Benutzung. Zusaetzlich bieten # diese Klassen bereits etwas Inspiration fuer Python-typisches Design, wie zum # Beispiel Duck-Typing. # # Zu einigen der vorgebenen Intefaces finden Sie Unit Tests in dem Paket 'test'. # Diese sind sehr hilfreich um zu ueberpruefen, ob ihre Implementierung zusammen # mit anderen mitgelieferten Implementierungen / Interfaces funktionieren wird. # Stellen Sie immer sicher, dass die Unit tests fuer die von Ihnen verwendeten # Funktionen erfolgreich sind. # Hinweis: Im Verlauf des Fachprojekts werden die Unit Tests nach und nach erfolg- # reich sein. Falls es sie zu Beginn stoert, wenn einzelne Unit Tests fehlschlagen # koennen Sie diese durch einen 'decorator' vor der Methodendefinition voruebergehend # abschalten: @unittest.skip('') # https://docs.python.org/2/library/unittest.html#skipping-tests-and-expected-failures # Denken Sie aber daran sie spaeter wieder zu aktivieren. # # Wenn etwas unklar ist, fragen Sie! # ********************************************************************************* # # Klassifikation von Dokumenten # # Nachdem Sie sich nun mit der Struktur und den Eigenschaften des Brown # Corpus vertraut gemacht haben, soll er die Datengrundlage fuer die # Evaluierung von Algorithmen zur automatischen Klassifikation von # Dokumenten bilden. # In der Regel bestehen diese Algorithmen aus drei Schritten: # - Vorverarbeitung # - Merkmalsberechnung # - Klassifikation # # Bei der Anwendung auf Dokumente (Texte) werden diese Schritte wie folgt # umgesetzt: # - Vorverarbeitung: Filterung von stopwords und Abbildung von Woertern auf # Wortstaemme. # - Merkmalsberechnung: Jedes Dokument wird numerisch durch einen Vektor # repraesentiert (--> NumPy), der moeglichst die # bzgl. der Klassifikation bedeutungsunterscheidenden # Informationen enthaehlt. # - Klassifikation: Jedem Merkmalsvektor (Dokument) wird ein Klassenindex # (Kategorie) zugeordnet. # # Details finden Sie zum Beispiel in: # http://www5.informatik.uni-erlangen.de/fileadmin/Persons/NiemannHeinrich/klassifikation-von-mustern/m00-www.pdf (section 1.3) # # Eine sehr verbreitete Merkmalsrepraesentation fuer (textuelle) Dokumente sind # sogenannte Bag-of-Words. # Dabei wird jedes Dokument durch ein Histogram (Verteilung) ueber Wortfrequenzen # repraesentiert. Man betrachtet dazu das Vorkommen von 'typischen' Woertern, die # durch ein Vokabular gegeben sind. # # Bestimmen Sie ein Vokabular, also die typischen Woerter, fuer den Brown Corpus. # Berechnen Sie dazu die 500 haeufigsten Woerter (nach stemming und Filterung von # stopwords und Satzzeichen) normalizer = WordListNormalizer() normalized_words = normalizer.normalize_words(brown.words()) vocabulary = BagOfWords.most_freq_words(normalized_words[1], 500) print(vocabulary) print('finished vocab') # Berechnen Sie Bag-of-Words Repraesentationen fuer jedes Dokument des Brown Corpus. # Verwenden Sie absolute Frequenzen. # Speichern Sie die Bag-of-Word Repraesentationen fuer jede Kategorie in einem # 2-D NumPy Array. Speichern Sie den Bag-of-Words Vektor fuer jedes Dokument in # einer Zeile, so dass das Array (ndarray) folgende Dimension hat: # |Dokument_kat| X |Vokabular| # # |Dokument_kat| entspricht der Anzahl Dokumente einer Kategorie. # |Vokabular| entspricht der Anzahl Woerter im Vokabular (hier 500). # # Eine einfache Zuordnung von Kategorie und Bag-of-Words Matrix ist durch ein # Dictionary moeglich. # # Implementieren Sie die Funktion BagOfWords.category_bow_dict im Modul features. bow = BagOfWords(vocabulary) cat_word_dict = { cat: [brown.words(doc) for doc in brown.fileids(categories=cat)] for cat in brown_categories } print('calculating cat_to_bow') cat_to_bow = bow.category_bow_dict(cat_word_dict) print(cat_to_bow) # Um einen Klassifikator statistisch zu evaluieren, benoetigt man eine Trainingsstichprobe # und eine Teststichprobe der Daten die klassifiziert werden sollen. # Die Trainingsstichprobe benoetigt man zum Erstellen oder Trainieren des Klassifikators. # Dabei werden in der Regel die Modellparameter des Klassifikators statistisch aus den # Daten der Traingingsstichprobe geschaetzt. Die Klassenzugehoerigkeiten sind fuer die # Beispiele aus der Trainingsstichprobe durch so genannte Klassenlabels gegeben. # # Nachdem man den Klassifikator trainiert hat, interessiert man sich normalerweise dafuer # wie gut er sich unter realen Bedingung verhaelt. Das heisst, dass der Klassifikator bei # der Klassifikation zuvor unbekannter Daten moeglichst wenige Fehler machen soll. # Dies simuliert man mit der Teststichprobe. Da auch fuer jedes Beispiel aus der Teststichprobe # die Klassenzugehoerigkeit bekannt ist, kann man am Ende die Klassifikationsergebnisse mit # den wahren Klassenlabels (aus der Teststichprobe) vergleichen und eine Fehlerrate angeben. # In dem gegebenen Brown Corpus ist keine Aufteilung in Trainings und Testdaten vorgegeben. # # Waehlen Sie daher die ersten 80% der Dokumente UEBER ALLE KATEGORIEN als Trainingstichprobe # und die letzten 20% der Dokumente UEBER ALLE KATEGORIEN als Teststichprobe. # # Erklaeren Sie, warum Sie die Stichproben ueber alle Kategorien zusammenstellen MUESSEN. # # Bitte beachten Sie, dass wir im Rahmen des Fachprojekts keinen Test auf unbekannten Testdaten # simulieren. Wir haben ja bereits fuer die Erstellung der Vokabulars (haeufigste Woerter, # siehe oben) den kompletten Datensatz verwendet. # Stattdessen betrachten wir hier ein so genanntes Validierungsszenario, in dem wir die # Klassifikationsleistung auf dem Brown Corpus optimieren. Die Ergebnisse lassen sich somit # nur sehr bedingt auf unbekannte Daten uebertragen. # # Erstellen Sie nun die NumPy Arrays train_samples, train_labels, test_samples und test_labels, # so dass diese mit den estimate und classify Methoden der Klassen im classificaton Modul # verwendet werden koennen. Teilen Sie die Daten wie oben angegeben zu 80% in # Trainingsdaten und 20% in Testdaten auf. # # Hinweis: Vollziehen Sie nach, wie die Klasse CrossValidation im evaluation Modul # funktioniert. Wenn Sie moechten, koennen die Klasse zur Aufteilung der Daten # verwenden. cross_validator = CrossValidation(cat_to_bow, 5) train_samples, train_labels, test_samples, test_labels = cross_validator.corpus_fold( 0) print('finished cross validation') # Klassifizieren Sie nun alle Dokumente der Teststichprobe nach dem Prinzip des k-naechste- # Nachbarn Klassifikators. Dabei wird die Distanz zwischen dem Merkmalsvektors eines # Testbeispiels und allen Merkmalsvektoren aus der Trainingstichprobe berechnet. Das # Klassenlabel des Testbeispiels wird dann ueber einen Mehrheitsentscheid der Klassenlabels # der k aehnlichsten Merkmalsvektoren aus der Trainingsstichprobe bestimmt. # http://www5.informatik.uni-erlangen.de/fileadmin/Persons/NiemannHeinrich/klassifikation-von-mustern/m00-www.pdf (Abschnitt 4.2.7) # # Bestimmen Sie die Distanzen von Testdaten zu Trainingsdaten mit cdist: # http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html # Bestimmen Sie die k-naechsten Nachbarn auf Grundlage der zuvor berechneten # Distanzen mit argsort: # http://docs.scipy.org/doc/numpy/reference/generated/numpy.argsort.html # Ueberlegen Sie, welche zuvor von Ihnen implementierte Funktion Sie wiederverwenden # koennen, um den Mehrheitsentscheid umzusetzen. # # Implementieren Sie die Funktionen estimate und classify in der Klasse KNNClassifier # im Modul classification. # # Verwenden Sie die Euklidische Distanz und betrachten Sie zunaechst nur # den naechsten Nachbarn (k=1). # # HINWEIS: Hier ist zunaechst nur die Implementierung eines naechster Nachbar # Klassifikators erforderlich. Diese soll aber in der naechsten Aufgabe zu einer # Implementierung eines k-naechste Nachbarn Klassifikators erweitert werden. # Beruechsichtigen Sie das in ihrer Implementierung. Um die beiden Varianten # zu testen, finden Sie zwei Unit-Test Methoden test_nn und test_knn in dem Modul # test.classification_test # knn_1 = KNNClassifier(1, 'euclidean') knn_1.estimate(train_samples, train_labels) nearest_1 = knn_1.classify(test_samples) print(nearest_1) print('finished classification') # Nachdem Sie mit dem KNNClassifier fuer jedes Testbeispiel ein Klassenlabel geschaetzt haben, # koennen Sie dieses mit dem tatsaechlichen Klassenlabel vergleichen. Dieses koennen Sie wie # bei den Traingingsdaten dem Corpus entnehmen. # # Ermitteln Sie eine Gesamtfehlerrate und je eine Fehlerrate pro Kategorie. # Implementieren Sie dazu die Klasse ClassificationEvaluator im evaluation Modul. # # Warum ist diese Aufteilung der Daten in Training und Test problematisch? Was sagen die Ergebnisse aus? evaluator = ClassificationEvaluator(nearest_1, test_labels) cat_err_rates = evaluator.category_error_rates() print(evaluator.error_rate(None)) print(cat_err_rates) print('done')
class Configuration(object): ''' ''' def __init__(self, b_corpus, cat_word_dict, vocab, voc_size, dist_metric, n_neighbours, weighting='abs'): ''' ''' self.b_corpus = b_corpus self.__vocab = vocab[:voc_size] self.__metric = dist_metric self.__nn = n_neighbours self.__classifier = None self.__cross_validator = None # bow-matrices by category bow = BagOfWords(self.__vocab) self.category_bow_dict = bow.category_bow_dict(cat_word_dict) if weighting == 'abs': self.__wght = lambda x: x elif weighting == 'rel': self.__wght = RelativeTermFrequencies.weighting elif weighting == 'tfidf': tfidf = RelativeInverseDocumentWordFrequecies( self.__vocab, cat_word_dict) self.__wght = tfidf.weighting def fit(self): # initializing the classifier self.__classifier = KNNClassifier(self.__nn, self.__metric) # relative bow-matrices by category (weighted) rel_category_bow_dict = { cat: self.__wght(self.category_bow_dict[cat]) for cat in self.category_bow_dict } # initializing the cross-validator (5 folds as in main) n_folds = 4 self.__cross_validator = CrossValidation( category_bow_dict=rel_category_bow_dict, n_folds=n_folds) def eval(self, feature_trans=None): if feature_trans is None: feature_trans = IdentityFeatureTransform() return self.__cross_validator.validate(self.__classifier, feature_transform=feature_trans) # # class ExpConfigurations: # # def __init__(self, vocabulary, cat_wordlist_dict, voc_sizes=[], weightings=[], metrices=[], neighbours=[], ): # self.__voc_szs = voc_sizes # self.__wghts = weightings # self.__mtrcs = metrices # self.__nghbrs = neighbours # # self.__log = ["size", "weighting", "metric", "n_neighbours", "error"] # self.__classifier = None # self.__bow = None # # self.__vocab = vocabulary # self.cat_wordlist_dict = cat_wordlist_dict # # # def run(self): # # all possible configurations # for vs in self.__voc_szs: # for wght in self.__wghts: # for metric in self.__mtrcs: # for nn in self.__nghbrs: # # adding to the log # self.__classifier = KNNClassifier(nn, metric) # self.__log.append([vs, wght, metric, nn, # self.eval(vs, wght)]) # # best result # return self.best() # # # def eval(self, vocab_size, weighting): # # bow # self.__bow = BagOfWords(self.__vocab[:vocab_size]) # category_bow_dict = self.__bow.category_bow_dict(self.cat_wordlist_dict) # # # weighting function # if weighting == 'abs': # wght = lambda x : x # elif weighting == 'rel': # wght = RelativeTermFrequencies.weighting # elif weighting == 'tfidf': # tfidf = RelativeInverseDocumentWordFrequecies(self.__vocab, self.cat_wordlist_dict) # wght = tfidf.weighting # # # wght_category_bow_dict = {cat : wght(category_bow_dict[cat]) # for cat in category_bow_dict} # n_folds = 5 # # c_val = CrossValidation(category_bow_dict=wght_category_bow_dict, n_folds=n_folds) # return c_val.validate(self.__classifier) # # # def best(self): # res = self.__log[1:] # if res: # best = deepcopy(res[0]) # for r in res[1:]: # if best[4][0] > r[4][0]: # best = deepcopy(r) # return best # return None
def aufgabe3(): # ********************************** ACHTUNG ************************************** # Die nun zu implementierenden Funktionen spielen eine zentrale Rolle im weiteren # Verlauf des Fachprojekts. Achten Sie auf eine effiziente und 'saubere' Umsetzung. # Verwenden Sie geeignete Datenstrukturen und passende Python Funktionen. # Wenn Ihnen Ihr Ansatz sehr aufwaendig vorkommt, haben Sie vermutlich nicht die # passenden Datenstrukturen / Algorithmen / (highlevel) Python / NumPy Funktionen # verwendet. Fragen Sie in diesem Fall! # # Schauen Sie sich jetzt schon gruendlich die Klassen und deren Interfaces in den # mitgelieferten Modulen an. Wenn Sie Ihre Datenstrukturen von Anfang an dazu # passend waehlen, erleichtert dies deren spaetere Benutzung. Zusaetzlich bieten # diese Klassen bereits etwas Inspiration fuer Python-typisches Design, wie zum # Beispiel Duck-Typing. # # Zu einigen der vorgebenen Intefaces finden Sie Unit Tests in dem Paket 'test'. # Diese sind sehr hilfreich um zu ueberpruefen, ob ihre Implementierung zusammen # mit anderen mitgelieferten Implementierungen / Interfaces funktionieren wird. # Stellen Sie immer sicher, dass die Unit tests fuer die von Ihnen verwendeten # Funktionen erfolgreich sind. # Hinweis: Im Verlauf des Fachprojekts werden die Unit Tests nach und nach erfolg- # reich sein. Falls es sie zu Beginn stoert, wenn einzelne Unit Tests fehlschlagen # koennen Sie diese durch einen 'decorator' vor der Methodendefinition voruebergehend # abschalten: @unittest.skip('') # https://docs.python.org/2/library/unittest.html#skipping-tests-and-expected-failures # Denken Sie aber daran sie spaeter wieder zu aktivieren. # # Wenn etwas unklar ist, fragen Sie! # ********************************************************************************* print('loading brown') CorpusLoader.load() brown = CorpusLoader.brown_corpus() # Um eine willkuerliche Aufteilung der Daten in Training und Test zu vermeiden, # (machen Sie sich bewusst warum das problematisch ist) # verwendet man zur Evaluierung von Klassifikatoren eine Kreuzvalidierung. # Dabei wird der gesamte Datensatz in k disjunkte Ausschnitte (Folds) aufgeteilt. # Jeder dieser Ausschnitte wird einmal als Test Datensatz verwendet, waehrend alle # anderen k-1 Ausschnitte als Trainings Datensatz verwendet werden. Man erhaehlt also # k Gesamtfehlerraten und k klassenspezifische Fehlerraten ide man jeweils zu einer # gemeinsamen Fehlerrate fuer die gesamte Kreuzvalidierung mittelt. Beachten Sie, # dass dabei ein gewichtetes Mittel gebildet werden muss, da die einzelnen Test Folds # nicht unbedingt gleich gross sein muessen. # Fuehren Sie aufbauend auf den Ergebnissen aus aufgabe2 eine 5-Fold Kreuzvalidierung # fuer den k-Naechste-Nachbarn Klassifikator auf dem Brown Corpus durch. Dazu koennen # Sie die Klasse CrossValidation im evaluation Modul verwenden. # # Vollziehen Sie dazu nach wie die Klasse die Daten in Trainging und Test Folds aufteilt. # Fertigen Sie zu dem Schema eine Skizze an. Diskutieren Sie Vorteile und Nachteile. # Schauen Sie sich an, wie die eigentliche Kreuzvalidierung funktioniert. Erklaeren Sie # wie das Prinzip des Duck-Typing hier angewendet wird. # # Hinweise: # # Die Klasse CrossValidator verwendet die Klasse ClassificationEvaluator, die Sie schon # fuer aufgabe2 implementieren sollten. Kontrollieren Sie Ihre Umsetzung im Sinne der # Verwendung im CrossValidator. # # Fuer das Verstaendnis der Implementierung der Klasse CrossValidator ist der Eclipse- # Debugger sehr hilfreich. brown_categories = brown.categories() n_neighbours = 1 metric = 'euclidean' classifier = KNNClassifier(n_neighbours, metric) normalizer = WordListNormalizer() normalized_words = normalizer.normalize_words(brown.words()) vocabulary = BagOfWords.most_freq_words(normalized_words[1], 500) bow = BagOfWords(vocabulary) cat_word_dict = { cat: [brown.words(doc) for doc in brown.fileids(categories=cat)] for cat in brown_categories } n_folds = 5 category_bow_dict = bow.category_bow_dict(cat_word_dict) cross_validator = CrossValidation(category_bow_dict=category_bow_dict, n_folds=n_folds) crossval_overall_result, crossval_class_results = cross_validator.validate( classifier) print("ran cross validation for {}-nearest neighbour".format(n_neighbours)) print(crossval_overall_result) print(crossval_class_results) # Bag-of-Words Weighting # # Bisher enthalten die Bag-of-Words Histogramme absolute Frequenzen. # Dadurch sind die Repraesentationen abhaengig von der absoluten Anzahl # von Woertern in den Dokumenten. # Dies kann vermieden werden, in dem man die Bag-of-Words Histogramme mit # einem Normalisierungsfaktor gewichtet. # # Normalisieren Sie die Bag-of-Words Histogramme so, dass relative Frequenzen # verwendet werden. Implementieren und verwenden Sie die Klasse RelativeTermFrequencies # im features Modul. # # Wie erklaeren Sie das Ergebnis? Schauen Sie sich dazu noch einmal die # mittelere Anzahl von Woertern pro Dokument an (aufgabe2). # # Wie in der Literatur ueblich, verwenden wir den # Begriff des "Term". Ein Term bezeichnet ein Wort aus dem Vokabular ueber # dem die Bag-of-Words Histogramme gebildet werden. Ein Bag-of-Words Histogramm # wird daher auch als Term-Vektor bezeichnet. rel_category_bow_dict = { cat: RelativeTermFrequencies.weighting(category_bow_dict[cat]) for cat in category_bow_dict } cross_validator = CrossValidation(category_bow_dict=rel_category_bow_dict, n_folds=n_folds) crossval_overall_result, crossval_class_results = cross_validator.validate( classifier) print("ran cross validation for {}-nearest neighbour (relative)".format( n_neighbours)) print(crossval_overall_result) print(crossval_class_results) # Zusaetzlich kann man noch die inverse Frequenz von Dokumenten beruecksichtigen # in denen ein bestimmter Term vorkommt. Diese Normalisierung wird als # inverse document frequency bezeichnet. Die Idee dahinter ist Woerter die in # vielen Dokumenten vorkommen weniger stark im Bag-of-Words Histogramm zu gewichten. # Die zugrundeliegende Annahme ist aehnlich wie bei den stopwords (aufgabe1), dass # Woerter, die in vielen Dokumenten vorkommen, weniger Bedeutung fuer die # Unterscheidung von Dokumenten in verschiedene Klassen / Kategorien haben als # Woerter, die nur in wenigen Dokumenten vorkommen. # Diese Gewichtung laesst sich statistisch aus den Beispieldaten ermitteln. # # Zusammen mit der relativen Term Gewichtung ergibt sich die so genannte # "term frequency inverse document frequency" # # Anzahl von term in document Anzahl Dokumente # tfidf( term, document ) = ---------------------------- x log ( ---------------------------------- ) # Anzahl Woerter in document Anzahl Dokumente die term enthalten # # http://www.tfidf.com # # Eklaeren Sie die Formel. Plotten Sie die inverse document frequency fuer jeden # Term ueber dem Brown Corpus. # # Implementieren und verwenden Sie die Klasse RelativeInverseDocumentWordFrequecies # im features Modul, in der Sie ein tfidf Gewichtungsschema umsetzen. # Ermitteln Sie die Gesamt- und klassenspezifischen Fehlerraten mit der Kreuzvalidierung. # Vergleichen Sie das Ergebnis mit der absolten und relativen Gewichtung. # Erklaeren Sie die Unterschiede in den klassenspezifischen Fehlerraten. Schauen Sie # sich dazu die Verteilungen der Anzahl Woerter und Dokumente je Kategorie aus aufgabe1 # an. In wie weit ist eine Interpretation moeglich? tfidf = RelativeInverseDocumentWordFrequecies(vocabulary, cat_word_dict) rel_category_bow_dict = { cat: tfidf.weighting(category_bow_dict[cat]) for cat in category_bow_dict } cross_validator = CrossValidation(category_bow_dict=rel_category_bow_dict, n_folds=n_folds) crossval_overall_result, crossval_class_results = cross_validator.validate( classifier) print("ran cross validation for {}-nearest neighbour (relative-inverse)". format(n_neighbours)) print(crossval_overall_result) print(crossval_class_results) # Evaluieren Sie die beste Klassifikationsleistung # # Ermitteln Sie nun die Parameter fuer die beste Klassifikationsleistung des # k-naechste-Nachbarn Klassifikators auf dem Brown Corpus mit der Kreuzvalidierung. # Dabei wird gleichzeitig immer nur ein Parameter veraendert. Man hat eine lokal # optimale Parameterkonfiguration gefunden, wenn jede Aenderung eines Parameters # zu einer Verschlechterung der Fehlerrate fuehrt. # # Erlaeutern Sie warum eine solche Parameterkonfiguration lokal optimal ist. # # Testen Sie mindestens die angegebenen Werte fuer die folgenden Parameter: # 1. Groesse des Vokabulars typischer Woerter (100, 500, 1000, 2000) # 2. Gewichtung der Bag-of-Words Histogramme (absolute, relative, relative with inverse document frequency) # 3. Distanzfunktion fuer die Bestimmung der naechsten Nachbarn (Cityblock, Euclidean, Cosine) # 4. Anzahl der betrachteten naechsten Nachbarn (1, 2, 3, 4, 5, 6) # # Erklaeren Sie den Effekt aller Parameter. # # Erklaeren Sie den Effekt zwischen Gewichtungsschema und Distanzfunktion. # vocabulary sizes as specified voc_sizes = (100, 500, 1000, 2000) # weightings as specified weightings = ('abs', 'rel', 'tfidf') # metrices as specified dists = ("cityblock", "euclidean", "cosine") # numbers of neighbours as specified neighbours = (1, 2, 3, 4, 5, 6) # indices of best options, to keep track idx_vs = 0 idx_wghts = 0 idx_dsts = 0 idx_nn = 0 normalizer = WordListNormalizer() cat_word_dict = normalizer.category_wordlists_dict(corpus=brown) # Flatten the category word lists for computing overall word frequencies # The * operator expands the list/iterator to function arguments # itertools.chain concatenates all its parameters to a single list print 'Building Bag-of-Words vocabulary...' wordlists = itertools.chain(*(cat_word_dict.itervalues())) normalized_words = itertools.chain(*wordlists) vocabulary = BagOfWords.most_freq_words(normalized_words) # print("normalizing") # # normalizing # normalizer = WordListNormalizer() # # normalized words # normalized_words = normalizer.normalize_words(brown.words())[1] # print("normalized words") # # normalized wordlists # cat_word_dict = normalizer.category_wordlists_dict(brown) # print("normalized wordlists") # # # initializing the vocabulary at maximum size and then taking slices # vocabulary = BagOfWords.most_freq_words(normalized_words, 2000) # print('initializing configuration') # # exp_config = ExpConfigurations(vocabulary ,cat_word_dict, # voc_sizes, weightings, dists, neighbours) # print(exp_config.run()) # for row in exp_config.__log: # print(row) config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx_nn], weightings[idx_wghts]) config.fit() err_overall = config.eval()[0] # list of configuration results config_table = [['voc_sizes', 'metric', 'neighbours', 'weightings', 'err'], [ voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx_nn], weightings[idx_wghts], err_overall ]] print('calculating size') # local optimum for vocabulary size for idx, _ in enumerate(voc_sizes[1:]): tmp_config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx + 1], dists[idx_dsts], neighbours[idx_nn], weightings[idx_wghts]) tmp_config.fit() tmp_err = tmp_config.eval()[0] if err_overall > tmp_err: err_overall = deepcopy(tmp_err) idx_vs = deepcopy(idx + 1) config_table.append([ voc_sizes[idx + 1], dists[idx_dsts], neighbours[idx_nn], weightings[idx_wghts], tmp_err ]) print(voc_sizes[idx_vs]) print('calculating weights') # local optimum for weighting for idx, _ in enumerate(weightings[1:]): tmp_config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx_nn], weightings[idx + 1]) tmp_config.fit() tmp_err = tmp_config.eval()[0] if err_overall > tmp_err: err_overall = deepcopy(tmp_err) idx_wghts = deepcopy(idx + 1) config_table.append([ voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx_nn], weightings[idx + 1], tmp_err ]) print(weightings[idx_wghts]) print('calculating metric') # local optimum for metric for idx, _ in enumerate(dists[1:]): tmp_config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx_vs], dists[idx + 1], neighbours[idx_nn], weightings[idx_wghts]) tmp_config.fit() tmp_err = tmp_config.eval()[0] if err_overall > tmp_err: err_overall = deepcopy(tmp_err) idx_dsts = deepcopy(idx + 1) config_table.append([ voc_sizes[idx_vs], dists[idx + 1], neighbours[idx_nn], weightings[idx_wghts], tmp_err ]) print(dists[idx_dsts]) print('calculating neighbours') # local optimum for neighbours for idx, _ in enumerate(neighbours[1:]): tmp_config = Configuration(brown, cat_word_dict, vocabulary, voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx + 1], weightings[idx_wghts]) tmp_config.fit() tmp_err = tmp_config.eval()[0] if err_overall > tmp_err: err_overall = deepcopy(tmp_err) idx_nn = deepcopy(idx + 1) config_table.append([ voc_sizes[idx_vs], dists[idx_dsts], neighbours[idx + 1], weightings[idx_wghts], tmp_err ]) print(neighbours[idx_nn]) # ideal should be 2000, relative, cityblock, 4 print('local optimum at\nsize: {}\nweight: {}\nmetric: {}\nneighbours: {}'. format(voc_sizes[idx_vs], weightings[idx_wghts], dists[idx_dsts], neighbours[idx_nn])) for row in config_table: print(row)
def aufgabe4(): # # Mit dem Naechster Nachbar Klassifikator wurde ein Dokumente zu einer Klassen zugeordnet, # indem zunaechst aehnliche Dokumente aus einer Trainingsdatenbank ermittelt wurden. # Ueber die Klassenzugehoerigkeit dieser aehnlichen Dokumente aus dem Training # wurde dann das unbekannte Dokument einer Klasse zugeordnet. # Dabei wurden aber noch keine Zusammenhaenge zwischen einzelnen Woertern analysiert # und beruecksichtigt. Daher geht es nun um Topic Modelle. Topic Modelle beschreiben # diese Zusammenhaenge durch einen mathematischen Unterraum. Die Vektoren, die # diesen Unterraum aufspannen, sind die Topics, die jeweils fuer typische Wort- # konfigurationen stehen. Dokumente werden nun nicht mehr durch Frequenzen von # Woertern repraesentiert, sondern als Linearkombination von Topics im Topic # Vektorraum. Es ist zu beachten, dass fuer die Topic-Modellierung keine Informationen # ueber die Dokumentenkategorien benoetigt wird. # # Um ein besseres Verstaendnis fuer diese mathematischen Unterraeume zu entwickeln, # schauen wir uns zunaechst die Hauptkomponentenanalyse an. # # Ein 3D Beispieldatensatz wird aus einer Normalverteilung generiert. # Diese ist durch einen Mittelwert und eine Kovarianzmatrix definiert mean = np.array([10, 10, 10]) cov = np.array([[3, .2, .9], [.2, 5, .4], [.9, .4, 9]]) n_samples = 1000 limits_samples = ((0, 20), (0, 20), (0, 20)) samples = np.random.multivariate_normal(mean, cov, n_samples) # Plotten der Beispieldaten fig = plt.figure() ax = fig.add_subplot(111, projection='3d') PCAExample.plot_sample_data(samples, ax=ax) PCAExample.set_axis_limits(ax, limits=limits_samples) # In der Klasse PCAExample wird ein Unterraum mittels Hauptkomponentenanalyse # statistisch geschaetzt. Der Vektorraum wird beispielhaft visualisiert. pca_example = PCAExample(samples, target_dim=3) pca_example.plot_subspace(limits=limits_samples, color='r', linewidth=0.05, alpha=0.3) #plt.show() # Nun wird die Dimension des Unterraums reduziert. # Implementieren Sie die Reduktion im Konstruktor von PCAExample. Der neue # Vektorraum wird wieder visualisiert. pca_example_2d = PCAExample(samples, target_dim=2) pca_example_2d.plot_subspace(limits=limits_samples, color='b', linewidth=0.01, alpha=0.3) # Transformieren Sie nun die 3D Beispieldaten in den 2D Unterraum. # Implementieren Sie dazu die Methode transform_samples. Die Daten werden # dann in einem 2D Plot dargestellt. # # Optional: Verwenden Sie Unterraeume mit Dimensionen 3, 2 und 1. Transformieren # und plotten Sie die Daten. #pca_example_1d = PCAExample(samples, target_dim=1) #pca_example_1d.plot_subspace(limits=limits_samples, color='g', linewidth=0.01, alpha=0.3, ellipsoid=False) #samples_1d = pca_example_1d.transform_samples(samples) #fig = plt.figure() #ax = fig.add_subplot(111) #PCAExample.plot_sample_data(samples_1d, ax=ax) #PCAExample.set_axis_limits(ax, limits=((-10, 10), (-10, 10))) # Optional: Generieren und transformieren Sie weitere 3D Beispieldaten. Benutzen Sie # dabei auch andere Parameter fuer die Normalverteilung. # # Optional: Visualisieren Sie die transformierten 2D Daten auch in dem vorherigen # 3D Plot. samples_2d = pca_example_2d.transform_samples(samples) fig = plt.figure() ax = fig.add_subplot(111) PCAExample.plot_sample_data(samples_2d, ax=ax) PCAExample.set_axis_limits(ax, limits=((-10, 10), (-10, 10))) #plt.show() # Berechnen Sie nun die Kovarianzmatrix der transformierten Daten. # Welche Eigenschaften hat diese Matrix? (Dimension, etc.) # In welcher Groessenordnung liegen die einzelnen Eintraege? Erklaeren Sie das # anhand des vorherigen 2D Plots. # Vergleichen Sie das Ergebnis mit der Kovarianzmatrix, die oben zur Generierung # der Daten verwendet wurde. # Was erwarten Sie fuer den Mittelwert der transformierten Daten (noetig fuer # die Berechnung der Kovarianzmatrix) ? # # Verwenden Sie bei der Berechnung nicht die eingebaute numpy.cov Funktion # (hoechstens zur Kontrolle, achten Sie dabei auf den "bias" Parameter) # Verwenden Sie bei der Berechnung keine Schleifen, sondern nur Matrixoperationen. # Erklaeren Sie die Vorgehensweise. samples_mean = np.sum(samples_2d, axis=0) / n_samples X = samples_2d - samples_mean samples_2d_cov = np.dot(X.T, X) / n_samples print(samples_2d_cov) # # Latent Semantic Indexing # # Im folgenden soll ein Topic-Raum mittels Latent Semantic Indexing verwendet # werden. Das Prinzip geht unmittelbar auf die Hauptkomponentenanalyse zurueck. # Siehe: http://lsa.colorado.edu/papers/JASIS.lsi.90.pdf (Seite 12) # Grundsaetzlicher Unterschied ist, dass der Unterraum nicht durch eine Eigenewert- # analyse der Kovarianzmatrix bestimmt wird. Stattdessen ergibt sich der Unterraum # aus einer Zerlegung der Term-Dokument (!) Matrix mit einer Singulaerwertzerlegung. # Man kann zeigen, dass diese Singulaerwertzerlegung implizit einer Eigenwert- # analyse einer Termkorrelationsmatrix entspricht. Deren Berechnung unterscheidet # sich von der Berechnung der Kovarianzmatrix insbesondere darin, dass die Daten # nicht vom Mittelwert befreit werden. # Sei t die Anzahl der Terms (Groesse des Vokabulars), d die Anzahl der Dokumente, # m der Rang von X (Maximale Anzahl von Topics, die sich aus X bestimmen lassen). # D' ist die Transponierte von D. # # X = T * S * D' # t x d t x m m x m m x d # # In Analogie zur Hauptkomponentenanalyse findet man nun die Vektoren, die # den Unterraum aufspannen, in den Spalten von T. Die Matrix S hat nur Eintraege # auf der Diagonalen und enthaelt die Singulaerwerte zu den Spaltenvektoren in # T. (T und D enthalten die linken respektive rechten Singulaervektoren.) # Die Singulaerwerte entsprechen den Eigenwerten in der Hauptkomponentenanalyse. # Sie sind ein Mass fuer die Variabilitaet in den einzelnen Topics. Bei D handelt # es sich um die Koeffizienten der d Dokumente im Topic Raum (Ergebnis der # Transformation von den Bag-of-Words Repraesentationen aus X in den Topic Raum.) # # # Aus der Singulaerwertzerlegung (Formel oben) ergibt sich, wie man einen Topic- # Raum statistisch aus Beispieldaten schaetzt. Um den Topic-Raum aber mit unbekannten Daten # zu verwenden, muessen diese in den Topic-Raum transformiert werden. # Stellen Sie dazu die obige Formel nach D um. # # D = X' * T * S^-1 # d x m d x t t x m m x m # # Die zu transformierenden Bag-of-Words # Repaesentationen koennen dann fuer X eingesetzt werden. Dabei ist wichtig zu # beachten: # Die Spaltenvektoren in T sind orthonormal (zueinander) T' * T = I # Die Spaltenvektoren in D sind orthonormal (zueinander) D' * D = I # Dabei ist I die Einheitsmatrix, T' und D' sind die Transponierten in T und D. # Fuer Matrizen A und B gilt: (A * B)' = B' * A' # # Ueberlegen Sie wie die Transponierte einer Matrix gebildet wird und was das # fuer eine Matrix bedeutet, deren Eintraege nur auf der Hauptdiagonalen von # # Antwort: Die Matrix wird an der Hauptdiagonalen gespiegelt, bzw. die Zeilen und Spalten werden # vertauscht. Das bedeutet für die Hauptdiagonale, dass sie bei jeder Transponierung gleich bleibt # # Erlaeutern Sie die Funktion der einzelnen Matrizen in der sich ergebenden # Transformationsvorschrift. # # Das Schaetzen eines Topic-Raums soll an folgendem einfachen Beispiel veranschaulicht # werden. Sei dazu bow_train eine Dokument-Term Matrix mit 9 Dokumenten und 3 Terms. # Welcher Zusammenhang zwischen den Terms faellt Ihnen auf? # # Antwort: Der zweite Term scheint nicht besonders topic bezogen und kommt in jedem Dokument mind. 1 mal vor # die anderen beiden Terms sind dagegen eher topic bezogen, vor allem das dritte bow_train = np.array([[2, 5, 0], [4, 1, 0], [3, 3, 1], [9, 8, 2], [1, 5, 3], [0, 7, 9], [2, 9, 6], [0, 2, 3], [5, 3, 3]]) # Zerlegung der Dokument-Term Matrix mit der Singulaerwertzerlegung T, S_arr, D_ = np.linalg.svd(bow_train.T, full_matrices=False) S = np.diag(S_arr) print('Matrix T, Spaltenvektoren definieren Topic Raum') print(T) print('Matrix S, Singulaerwerte zu den Vektoren des Topic Raums') print(S) print('Matrix D, Koeffizienten der Termvektoren in bof Topic Raum') print(D_.T) # Transformieren Sie nun die folgenden Termvektoren in den Topic Raum # Was erwarten Sie fuer die Topic Zugehoerigkeiten? bow_test = np.array([[5, 0, 0], [0, 5, 0], [0, 0, 5], [5, 5, 0], [0, 5, 5]]) coefficients = np.dot(np.dot(bow_test, T), np.linalg.inv(S)) print(coefficients) # # Warum lassen sich die Koeffizienten der Termvektoren so schwer interpretieren? # Antwort: extrem kleine Werte -> besser: visualisieren # # Um eine bessere Vorstellung von der Bedeutung der einzelnen Topics zu bekommen, # plotten Sie die Bag-of-Words Repraesentationen sowie die Topic-Koeffizienten der # Trainingsdaten (bow_train) und der Testdaten (bow_test) in verschiedenen Farben. # Erstellen Sie dazu jeweils einen Plot fuer Bag-of-Words Repraesentationen und einen # Plot fuer Topic-Koeffizienten. Achten Sie auf eine geeignete Skalierung der Axen. # Um die Datenpunkte in den beiden Plots besser einander zuordnen zu koennen, plotten # Sie zusaetzlich die Termfrequenzen neben jeden Datenpunkt (als Annotation). # Mehrere Daten (Trainings-, Testdaten, Annotationen) lassen sich in einem gemeinsamen # Plot darzustellen indem sie nacheinander zu dem gleichen Axis Objekt hinzugefuegt # werden. Zum Erstellen der Plots orientieren Sie sich an den entsprechenden # Funktionen aus dem Beispiel zur Hauptkomponentenanalyse (oben). Schauen Sie sich # auch deren weitere Parameter (und zusaetzlich vorhandene Hilfsfunktionen) an. fig = plt.figure() ax = fig.add_subplot(111, projection='3d') annotations_D_test = PCAExample.samples_coordinate_annotations(bow_test) annotations_D_train = PCAExample.samples_coordinate_annotations(bow_train) PCAExample.plot_sample_data(D_.T, ax=ax, annotations=annotations_D_train, color='r') PCAExample.plot_sample_data(coefficients, ax=ax, annotations=annotations_D_test, color='b') PCAExample.set_axis_limits(ax, limits=((-1, 1), (-1, 1), (-1, 1))) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') PCAExample.plot_sample_data(bow_train, ax=ax, color='b', annotations=annotations_D_train) PCAExample.plot_sample_data(bow_test, ax=ax, color='r', annotations=annotations_D_test) PCAExample.set_axis_limits(ax, limits=((0, 10), (0, 10), (0, 10))) # # Fuehren Sie nun eine Dimensionsreduktion der Trainings und Testdaten auf zwei # Dimensionen durch und plotten Sie die Topic-Koeffizienten (inkl. Bag-of-Words # Annotationen). Vergleichen Sie alle drei Plots miteinander. Welchen Effekt hat # die Topic Modellierung im Bezug auf typische Termkonfigurationen? # # Optional: Transformieren Sie die Daten in einen Topic-Raum mit Dimension Eins # und plotten Sie die Koeffizienten inkl. deren Bag-of-Words Annotationen. # T_2d = T[:, :2] S_2d = S[:2, :2] D_2d_test = np.dot(np.dot(bow_test, T_2d), np.linalg.inv(S_2d)) D_2d_train = np.dot(np.dot(bow_train, T_2d), np.linalg.inv(S_2d)) ax = fig.add_subplot(111) annotations_D_test = PCAExample.samples_coordinate_annotations(bow_test) annotations_D_train = PCAExample.samples_coordinate_annotations(bow_train) PCAExample.plot_sample_data(D_2d_train, ax=ax, annotations=annotations_D_train, color='r') PCAExample.plot_sample_data(D_2d_test, ax=ax, annotations=annotations_D_test, color='b') PCAExample.set_axis_limits(ax, limits=((-0.75, 0.75), (-0.75, 0.75))) plt.show() # # Integrieren Sie nun die Topic-Raum Modellierung mittels Singulaerwertzerlegung # in die Kreuzvalidierung auf dem Brown Corpus. Berechnen Sie dabei fuer # jede Aufteilung von Training und Test einen neuen Topic-Raum. Transformieren # Sie die Bag-of-Words Repraesentationen und fuehren Sie die Klassifikation # wie zuvor mit dem Naechster-Nachbar-Klassifikator durch. Verwenden Sie dabei # verschiedene Distanzmasse und evaluieren Sie die Klassifikationsfehlerrate # fuer verschiedene Dimensionalitaeten des Topic-Raums. Die anderen Parameter # waehlen Sie gemaess der besten bisherigen Ergebnisse. # # Implementieren Sie die Klasse TopicFeatureTransform im features Modul # und verwenden Sie sie mit der CrossValidation Klasse (evaluation Modul). # # Optional: Fuehren Sie eine automatische Gridsuche ueber den kompletten Paramterraum # durch. Legen Sie sinnvolle Wertebereiche und Schrittweiten fuer die einzelnen # Parameter fest. Wie lassen sich diese bestimmen? # # Optional: Passen Sie das Suchgrid dynamisch gemaess der Ergebnisse in den einzelnen # Wertebereichen an. CorpusLoader.load() brown = CorpusLoader.brown_corpus() brown_categories = brown.categories() brown_words = brown.words() words_normalizer = WordListNormalizer() filtered_list, stemmed_list = words_normalizer.normalize_words(brown_words) vocabulary = BagOfWords.most_freq_words(stemmed_list, 500) cat_word_dict = {} for category in brown_categories: words_of_all_documents = [] for document in brown.fileids(category): filtered_list, stemmed_list = words_normalizer.normalize_words( brown.words(fileids=document)) words_of_all_documents.append(stemmed_list) cat_word_dict[category] = words_of_all_documents bag_of_words = BagOfWords(vocabulary) category_bow_dict = bag_of_words.category_bow_dict(cat_word_dict) cross_validation = CrossValidation(category_bow_dict, 5) knn_classifier = KNNClassifier(k_neighbors=4, metric='cosine') topic_feature_transform = TopicFeatureTransform(topic_dim=25) overall_result, class_result = cross_validation.validate( knn_classifier, feature_transform=topic_feature_transform) print(overall_result) print(class_result)
from user import RandomPopcon,LocalSystem,PopconSystem if __name__ == '__main__': cfg = Config() rec = Recommender(cfg) #user = LocalSystem() #user = RandomPopcon(cfg.popcon_dir) #user = RandomPopcon(cfg.popcon_dir,os.path.join(cfg.filters_dir,"desktopapps")) user = PopconSystem(os.path.expanduser("~/.app-recommender/popcon-entries/00/0001166d0737c6dffb083071e5ee69f5")) user.filter_pkg_profile(os.path.join(cfg.filters_dir,"desktopapps")) user.maximal_pkg_profile() begin_time = datetime.datetime.now() metrics = [] metrics.append(Precision()) metrics.append(Recall()) metrics.append(F_score(0.5)) metrics.append(Accuracy()) metrics.append(FPR()) validation = CrossValidation(0.9,20,rec,metrics,0.005) validation.run(user) print validation end_time = datetime.datetime.now() delta = end_time - begin_time logging.info("Cross-validation for user %s" % user.user_id) logging.info("Recommender strategy: %s" % rec.strategy.description) logging.debug("Cross-validation started at %s" % begin_time) logging.debug("Cross-validation completed at %s" % end_time) logging.info("Time elapsed: %d seconds." % delta.seconds)
def aufgabe3(): # ********************************** ACHTUNG ************************************** # Die nun zu implementierenden Funktionen spielen eine zentrale Rolle im weiteren # Verlauf des Fachprojekts. Achten Sie auf eine effiziente und 'saubere' Umsetzung. # Verwenden Sie geeignete Datenstrukturen und passende Python Funktionen. # Wenn Ihnen Ihr Ansatz sehr aufwaendig vorkommt, haben Sie vermutlich nicht die # passenden Datenstrukturen / Algorithmen / (highlevel) Python / NumPy Funktionen # verwendet. Fragen Sie in diesem Fall! # # Schauen Sie sich jetzt schon gruendlich die Klassen und deren Interfaces in den # mitgelieferten Modulen an. Wenn Sie Ihre Datenstrukturen von Anfang an dazu # passend waehlen, erleichtert dies deren spaetere Benutzung. Zusaetzlich bieten # diese Klassen bereits etwas Inspiration fuer Python-typisches Design, wie zum # Beispiel Duck-Typing. # # Zu einigen der vorgebenen Intefaces finden Sie Unit Tests in dem Paket 'test'. # Diese sind sehr hilfreich um zu ueberpruefen, ob ihre Implementierung zusammen # mit anderen mitgelieferten Implementierungen / Interfaces funktionieren wird. # Stellen Sie immer sicher, dass die Unit tests fuer die von Ihnen verwendeten # Funktionen erfolgreich sind. # Hinweis: Im Verlauf des Fachprojekts werden die Unit Tests nach und nach erfolg- # reich sein. Falls es sie zu Beginn stoert, wenn einzelne Unit Tests fehlschlagen # koennen Sie diese durch einen 'decorator' vor der Methodendefinition voruebergehend # abschalten: @unittest.skip('') # https://docs.python.org/2/library/unittest.html#skipping-tests-and-expected-failures # Denken Sie aber daran sie spaeter wieder zu aktivieren. # # Wenn etwas unklar ist, fragen Sie! # ********************************************************************************* CorpusLoader.load() brown = CorpusLoader.brown_corpus() # Um eine willkuerliche Aufteilung der Daten in Training und Test zu vermeiden, # (machen Sie sich bewusst warum das problematisch ist) # verwendet man zur Evaluierung von Klassifikatoren eine Kreuzvalidierung. # Dabei wird der gesamte Datensatz in k disjunkte Ausschnitte (Folds) aufgeteilt. # Jeder dieser Ausschnitte wird einmal als Test Datensatz verwendet, waehrend alle # anderen k-1 Ausschnitte als Trainings Datensatz verwendet werden. Man erhaehlt also # k Gesamtfehlerraten und k klassenspezifische Fehlerraten ide man jeweils zu einer # gemeinsamen Fehlerrate fuer die gesamte Kreuzvalidierung mittelt. Beachten Sie, # dass dabei ein gewichtetes Mittel gebildet werden muss, da die einzelnen Test Folds # nicht unbedingt gleich gross sein muessen. # Fuehren Sie aufbauend auf den Ergebnissen aus aufgabe2 eine 5-Fold Kreuzvalidierung # fuer den k-Naechste-Nachbarn Klassifikator auf dem Brown Corpus durch. Dazu koennen # Sie die Klasse CrossValidation im evaluation Modul verwenden. # # Vollziehen Sie dazu nach wie die Klasse die Daten in Trainging und Test Folds aufteilt. # Fertigen Sie zu dem Schema eine Skizze an. Diskutieren Sie Vorteile und Nachteile. # Schauen Sie sich an, wie die eigentliche Kreuzvalidierung funktioniert. Erklaeren Sie # wie das Prinzip des Duck-Typing hier angewendet wird. # # Hinweise: # # Die Klasse CrossValidator verwendet die Klasse , die Sie schon # fuer aufgabe2 implementieren sollten. Kontrollieren Sie Ihre Umsetzung im Sinne der # Verwendung im CrossValidator. # # Fuer das Verstaendnis der Implementierung der Klasse CrossValidator ist der Eclipse- # Debugger sehr hilfreich. normalized_words = WordListNormalizer().normalize_words(brown.words())[1] # vocabulary = BagOfWords.most_freq_words(normalized_words, 500) # word_bag = BagOfWords(vocabulary) # # bow_mat = {} # for cat in brown.categories(): # bow_mat[cat] = [WordListNormalizer().normalize_words(brown.words(fileids=doc))[1] for doc in brown.fileids(categories=cat)] # category_dic = word_bag.category_bow_dict(bow_mat) # # cross_validator = CrossValidation(category_dic, 5) # # first_fold = cross_validator.corpus_fold(0) # second_fold = cross_validator.corpus_fold(1) # third_fold = cross_validator.corpus_fold(2) # fourth_fold = cross_validator.corpus_fold(3) # fifth_fold = cross_validator.corpus_fold(4) # # classificator = KNNClassifier(1, 'euclidean') # # classificator.estimate(first_fold[0], first_fold[1]) # result_first_fold = classificator.classify(first_fold[2]) # # classificator.estimate(second_fold[0], second_fold[1]) # result_second_fold = classificator.classify(second_fold[2]) # # classificator.estimate(third_fold[0], third_fold[1]) # result_third_fold = classificator.classify(third_fold[2]) # # classificator.estimate(fourth_fold[0], fourth_fold[1]) # result_fourth_fold = classificator.classify(fourth_fold[2]) # # classificator.estimate(fifth_fold[0], fifth_fold[1]) # result_fifth_fold = classificator.classify(fifth_fold[2]) # # eval_first_fold = ClassificationEvaluator(result_first_fold, first_fold[3]) # eval_second_fold = ClassificationEvaluator(result_second_fold, second_fold[3]) # eval_third_fold = ClassificationEvaluator(result_third_fold, third_fold[3]) # eval_fourth_fold = ClassificationEvaluator(result_fourth_fold, fourth_fold[3]) # eval_fifth_fold = ClassificationEvaluator(result_fifth_fold, fifth_fold[3]) # # list_eval_folds =[] # list_eval_folds.append(eval_first_fold.error_rate()[0]) # list_eval_folds.append(eval_second_fold.error_rate()[0]) # list_eval_folds.append(eval_third_fold.error_rate()[0]) # list_eval_folds.append(eval_fourth_fold.error_rate()[0]) # list_eval_folds.append(eval_fifth_fold.error_rate()[0]) # np_array_eval_folds = np.array(list_eval_folds) # print np_array_eval_folds # mittelwert = np.mean(np_array_eval_folds) # print "Mittelwert" # print mittelwert # print "++++++++++++" # print "Minimum" # print np.min(np_array_eval_folds, axis=0) # Bag-of-Words Weighting # # Bisher enthalten die Bag-of-Words Histogramme absolute Frequenzen. # Dadurch sind die Repraesentationen abhaengig von der absoluten Anzahl # von Woertern in den Dokumenten. # Dies kann vermieden werden, in dem man die Bag-of-Words Histogramme mit # einem Normalisierungsfaktor gewichtet. # # Normalisieren Sie die Bag-of-Words Histogramme so, dass relative Frequenzen # verwendet werden. Implementieren und verwenden Sie die Klasse RelativeTermFrequencies # im features Modul. # # Wie erklaeren Sie das Ergebnis? Schauen Sie sich dazu noch einmal die # mittelere Anzahl von Woertern pro Dokument an (aufgabe2). # # Wie in der Literatur ueblich, verwenden wir den # Begriff des "Term". Ein Term bezeichnet ein Wort aus dem Vokabular ueber # dem die Bag-of-Words Histogramme gebildet werden. Ein Bag-of-Words Histogramm # wird daher auch als Term-Vektor bezeichnet. #normalized_words = WordListNormalizer().normalize_words(brown.words())[1] #vocab = BagOfWords.most_freq_words(normalized_words, 20) #word_bag = BagOfWords(vocab) # word_dic_category = {} # for cat in brown.categories(): # word_dic_category[cat] = [WordListNormalizer().normalize_words(brown.words(fileids = doc))[1] for doc in brown.fileids(categories=cat)] # category_word_dic = word_bag.category_bow_dict(word_dic_category) # # category_weighted = {} # for key in category_word_dic: # category_weighted[key] = RelativeTermFrequencies.weighting(category_word_dic[key]) # Zusaetzlich kann man noch die inverse Frequenz von Dokumenten beruecksichtigen # in denen ein bestimmter Term vorkommt. Diese Normalisierung wird als # inverse document frequency bezeichnet. Die Idee dahinter ist Woerter die in # vielen Dokumenten vorkommen weniger stark im Bag-of-Words Histogramm zu gewichten. # Die zugrundeliegende Annahme ist aehnlich wie bei den stopwords (aufgabe1), dass # Woerter, die in vielen Dokumenten vorkommen, weniger Bedeutung fuer die # Unterscheidung von Dokumenten in verschiedene Klassen / Kategorien haben als # Woerter, die nur in wenigen Dokumenten vorkommen. # Diese Gewichtung laesst sich statistisch aus den Beispieldaten ermitteln. # # Zusammen mit der relativen Term Gewichtung ergibt sich die so genannte # "term frequency inverse document frequency" # # Anzahl von term in document Anzahl Dokumente # tfidf( term, document ) = ---------------------------- x log ( ---------------------------------- ) # Anzahl Woerter in document Anzahl Dokumente die term enthalten # # http://www.tfidf.com # # Eklaeren Sie die Formel. Plotten Sie die inverse document frequency fuer jeden # Term ueber dem Brown Corpus. # # Implementieren und verwenden Sie die Klasse RelativeInverseDocumentWordFrequecies # im features Modul, in der Sie ein tfidf Gewichtungsschema umsetzen. # Ermitteln Sie die Gesamt- und klassenspezifischen Fehlerraten mit der Kreuzvalidierung. # Vergleichen Sie das Ergebnis mit der absolten und relativen Gewichtung. # Erklaeren Sie die Unterschiede in den klassenspezifischen Fehlerraten. Schauen Sie # sich dazu die Verteilungen der Anzahl Woerter und Dokumente je Kategorie aus aufgabe1 # an. In wie weit ist eine Interpretation moeglich? # raise NotImplementedError('Implement me') # Evaluieren Sie die beste Klassifikationsleistung # # Ermitteln Sie nun die Parameter fuer die bester Klassifikationsleistung des # k-naechste-Nachbarn Klassifikators auf dem Brown Corpus mit der Kreuzvalidierung. # Dabei wird gleichzeitig immer nur ein Parameter veraendert. Man hat eine lokal # optimale Parameterkonfiguration gefunden, wenn jede Aenderung eines Parameters # zu einer Verschlechterung der Fehlerrate fuehrt. # # Erlaeutern Sie warum eine solche Parameterkonfiguration lokal optimal ist. # # Testen Sie mindestens die angegebenen Werte fuer die folgenden Parameter: # 1. Groesse des Vokabulars typischer Woerter (100, 500, 1000, 2000!) # 2. Gewichtung der Bag-of-Words Histogramme (absolute, relative!, relative with inverse document frequency) # 3. Distanzfunktion fuer die Bestimmung der naechsten Nachbarn (Cityblock!, Euclidean, Cosine) # 4. Anzahl der betrachteten naechsten Nachbarn (1, 2, 3, 4, 5, 6!) # # Erklaeren Sie den Effekt aller Parameter. # # Erklaeren Sie den Effekt zwischen Gewichtungsschema und Distanzfunktion. print "+++++++++++++++++++++++++++++++++++++++++++++++" print "Testfunktion" vocab_size = 2000 distance_function="cityblock" knn=6 #print "vocabsize:" + vocab_size +"; distance" + distance_function +"; knn" + knn vocabulary = BagOfWords.most_freq_words(normalized_words, vocab_size) word_bag = BagOfWords(vocabulary) bow_mat = {} for cat in brown.categories(): bow_mat[cat] = [WordListNormalizer().normalize_words(brown.words(fileids=doc))[1] for doc in brown.fileids(categories=cat)] category_dic = word_bag.category_bow_dict(bow_mat) relative_category_dict = {} for key in category_dic: relative_category_dict[key] = RelativeTermFrequencies.weighting(category_dic[key]) cross_validator = CrossValidation(relative_category_dict, 5) classificator = KNNClassifier(knn, distance_function) print cross_validator.validate(classificator)
def aufgabe4(): # # Mit dem Naechster Nachbar Klassifikator wurde ein Dokumente zu einer Klassen zugeordnet, # indem zunaechst aehnliche Dokumente aus einer Trainingsdatenbank ermittelt wurden. # Ueber die Klassenzugehoerigkeit dieser aehnlichen Dokumente aus dem Training # wurde dann das unbekannte Dokument einer Klasse zugeordnet. # Dabei wurden aber noch keine Zusammenhaenge zwischen einzelnen Woertern analysiert # und beruecksichtigt. Daher geht es nun um Topic Modelle. Topic Modelle beschreiben # diese Zusammenhaenge durch einen mathematischen Unterraum. Die Vektoren, die # diesen Unterraum aufspannen, sind die Topics, die jeweils fuer typische Wort- # konfigurationen stehen. Dokumente werden nun nicht mehr durch Frequenzen von # Woertern repraesentiert, sondern als Linearkombination von Topics im Topic # Vektorraum. Es ist zu beachten, dass fuer die Topic-Modellierung keine Informationen # ueber die Dokumentenkategorien benoetigt wird. # # Um ein besseres Verstaendnis fuer diese mathematischen Unterraeume zu entwickeln, # schauen wir uns zunaechst die Hauptkomponentenanalyse an. # # Ein 3D Beispieldatensatz wird aus einer Normalverteilung generiert. # Diese ist durch einen Mittelwert und eine Kovarianzmatrix definiert mean = np.array([10, 10, 10]) cov = np.array([[3, .2, .9], [.2, 5, .4], [.9, .4, 9]]) n_samples = 1000 limits_samples = ((0, 20), (0, 20), (0, 20)) samples = np.random.multivariate_normal(mean, cov, n_samples) # Plotten der Beispieldaten fig = plt.figure() ax = fig.add_subplot(111, projection='3d') PCAExample.plot_sample_data(samples, ax=ax) PCAExample.set_axis_limits(ax, limits=limits_samples) # In der Klasse PCAExample wird ein Unterraum mittels Hauptkomponentenanalyse # statistisch geschaetzt. Der Vektorraum wird beispielhaft visualisiert. pca_example = PCAExample(samples, target_dim=3) pca_example.plot_subspace(limits=limits_samples, color='r', linewidth=0.05, alpha=0.3) plt.show() # Nun wird die Dimension des Unterraums reduziert. # Implementieren Sie die Reduktion im Konstruktor von PCAExample. Der neue # Vektorraum wird wieder visualisiert. pca_example_2d = PCAExample(samples, target_dim=2) pca_example_2d.plot_subspace(limits=limits_samples, color='b', linewidth=0.01, alpha=0.3) # Transformieren Sie nun die 3D Beispieldaten in den 2D Unterraum. # Implementieren Sie dazu die Methode transform_samples. Die Daten werden # dann in einem 2D Plot dargestellt. # # Optional: Verwenden Sie Unterraeume mit Dimensionen 3, 2 und 1. Transformieren # und plotten Sie die Daten. # # Optional: Generieren und transformieren Sie weitere 3D Beispieldaten. Benutzen Sie # dabei auch andere Parameter fuer die Normalverteilung. # # Optional: Visualisieren Sie die transformierten 2D Daten auch in dem vorherigen # 3D Plot. samples_2d = pca_example_2d.transform_samples(samples) fig = plt.figure() ax = fig.add_subplot(111) PCAExample.plot_sample_data(samples_2d, ax=ax) PCAExample.set_axis_limits(ax, limits=((-10, 10), (-10, 10))) plt.show() # Berechnen Sie nun die Kovarianzmatrix der transformierten Daten. # Welche Eigenschaften hat diese Matrix? (Dimension, etc.) # In welcher Groessenordnung liegen die einzelnen Eintraege? Erklaeren Sie das # anhand des vorherigen 2D Plots. # Vergleichen Sie das Ergebnis mit der Kovarianzmatrix, die oben zur Generierung # der Daten verwendet wurde. # Was erwarten Sie fuer den Mittelwert der transformierten Daten (noetig fuer # die Berechnung der Kovarianzmatrix) ? # # Verwenden Sie bei der Berechnung nicht die eingebaute numpy.cov Funktion # (hoechstens zur Kontrolle, achten Sie dabei auf den "bias" Parameter) # Verwenden Sie bei der Berechnung keine Schleifen, sondern nur Matrixoperationen. # Erklaeren Sie die Vorgehensweise. zeilen, spalten = samples_2d.shape print zeilen, spalten mean_xy = np.mean(samples_2d, axis=0) samples_2d_mf = samples_2d - mean_xy kovarianz_mat = np.dot(samples_2d_mf.T, samples_2d_mf)/(zeilen-1) print "kovarianz ausgerechnet" print kovarianz_mat kovarianz_referenz = np.cov(samples_2d, rowvar=0) print "kovarianz referenz" print kovarianz_referenz # # Latent Semantic Indexing # # Im folgenden soll ein Topic-Raum mittels Latent Semantic Indexing verwendet # werden. Das Prinzip geht unmittelbar auf die Hauptkomponentenanalyse zurueck. # Siehe: http://lsa.colorado.edu/papers/JASIS.lsi.90.pdf (Seite 12) # Grundsaetzlicher Unterschied ist, dass der Unterraum nicht durch eine Eigenewert- # analyse der Kovarianzmatrix bestimmt wird. Stattdessen ergibt sich der Unterraum # aus einer Zerlegung der Term-Dokument (!) Matrix mit einer Singulaerwertzerlegung. # Man kann zeigen, dass diese Singulaerwertzerlegung implizit einer Eigenwert- # analyse einer Termkorrelationsmatrix entspricht. Deren Berechnung unterscheidet # sich von der Berechnung der Kovarianzmatrix insbesondere darin, dass die Daten # nicht vom Mittelwert befreit werden. # Sei t die Anzahl der Terms (Groesse des Vokabulars), d die Anzahl der Dokumente, # m der Rang von X (Maximale Anzahl von Topics, die sich aus X bestimmen lassen). # D' ist die Transponierte von D. # # X = T * S * D' # t x d t x m m x m m x d # # In Analogie zur Hauptkomponentenanalyse findet man nun die Vektoren, die # den Unterraum aufspannen, in den Spalten von T. Die Matrix S hat nur Eintraege # auf der Diagonalen und enthaelt die Singulaerwerte zu den Spaltenvektoren in # T. (T und D enthalten die linken respektive rechten Singulaervektoren.) # Die Singulaerwerte entsprechen den Eigenwerten in der Hauptkomponentenanalyse. # Sie sind ein Mass fuer die Variabilitaet in den einzelnen Topics. Bei D handelt # es sich um die Koeffizienten der d Dokumente im Topic Raum (Ergebnis der # Transformation von den Bag-of-Words Repraesentationen aus X in den Topic Raum.) # # # Aus der Singulaerwertzerlegung (Formel oben) ergibt sich, wie man einen Topic- # Raum statistisch aus Beispieldaten schaetzt. Um den Topic-Raum aber mit unbekannten Daten # zu verwenden, muessen diese in den Topic-Raum transformiert werden. # Stellen Sie dazu die obige Formel nach D um. Die zu transformierenden Bag-of-Words # Repaesentationen koennen dann fuer X eingesetzt werden. Dabei ist wichtig zu # beachten: # Die Spaltenvektoren in T sind orthonormal (zueinander) T' * T = I # Die Spaltenvektoren in D sind orthonormal (zueinander) D' * D = I # Dabei ist I die Einheitsmatrix, T' und D' sind die Transponierten in T und D. # Fuer Matrizen A und B gilt: (A * B)' = B' * A' # # Ueberlegen Sie wie die Transponierte einer Matrix gebildet wird und was das # fuer eine Matrix bedeutet, deren Eintraege nur auf der Hauptdiagonalen von # 0 verschieden sind. # # Erlaeutern Sie die Funktion der einzelnen Matrizen in der sich ergebenden # Transformationsvorschrift. # # Das Schaetzen eines Topic-Raums soll an folgendem einfachen Beispiel veranschaulicht # werden. Sei dazu bow_train eine Dokument-Term Matrix mit 9 Dokumenten und 3 Terms. # Welcher Zusammenhang zwischen den Terms faellt Ihnen auf? bow_train = np.array([[2, 5, 0], [4, 1, 0], [3, 3, 1], [9, 8, 2], [1, 5, 3], [0, 7, 9], [2, 9, 6], [0, 2, 3], [5, 3, 3]]) # Zerlegung der Dokument-Term Matrix mit der Singulaerwertzerlegung T, S_arr, D_ = np.linalg.svd(bow_train.T, full_matrices=False) S = np.diag(S_arr) print 'Matrix T, Spaltenvektoren definieren Topic Raum' print T print 'Matrix S, Singulaerwerte zu den Vektoren des Topic Raums' print S print 'Matrix D, Koeffizienten der Termvektoren in bof im Topic Raum' print D_.T # Transformieren Sie nun die folgenden Termvektoren in den Topic Raum # Was erwarten Sie fuer die Topic Zugehoerigkeiten? bow_test = np.array([[5, 0, 0], [0, 5, 0], [0, 0, 5], [5, 5, 0], [0, 5, 5]]) n_topics = 3 top_feature_trans = TopicFeatureTransform(n_topics) top_feature_trans.estimate(bow_train, bow_train) bow_transformed = top_feature_trans.transform(bow_test) bow_train_transformed = top_feature_trans.transform(bow_train) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') PCAExample.plot_sample_data(bow_train_transformed, annotations=bow_train, ax=ax) PCAExample.set_axis_limits(ax, limits=((-1, 1), (-1, 1), (-1, 1))) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') PCAExample.plot_sample_data(bow_transformed, annotations=bow_test, ax=ax) PCAExample.set_axis_limits(ax, limits=((-1, 1), (-1, 1), (-1, 1))) plt.show() # # Warum lassen sich die Koeffizienten der Termvektoren so schwer interpretieren? # # Um eine bessere Vorstellung von der Bedeutung der einzelnen Topics zu bekommen, # plotten Sie die Bag-of-Words Repraesentationen sowie die Topic-Koeffizienten der # Trainingsdaten (bow_train) und der Testdaten (bow_test) in verschiedenen Farben. # Erstellen Sie dazu jeweils einen Plot fuer Bag-of-Words Repraesentationen und einen # Plot fuer Topic-Koeffizienten. Achten Sie auf eine geeignete Skalierung der Axen. # Um die Datenpunkte in den beiden Plots besser einander zuordnen zu koennen, plotten # Sie zusaetzlich die Termfrequenzen neben jeden Datenpunkt (als Annotation). # Mehrere Daten (Trainings-, Testdaten, Annotationen) lassen sich in einem gemeinsamen # Plot darzustellen indem Sie die Funktion 'hold' des Axes Objekts mit dem Parameter # 'True' aufrufen. Zum Erstellen der Plots orientieren Sie sich an den entsprechenden # Funktionen aus dem Beispiel zur Hauptkomponentenanalyse (oben). Schauen Sie sich # auch deren weitere Parameter (und zusaetzlich vorhandene Hilfsfunktionen) an. # #Bag of words plots # fig = plt.figure() # ax = fig.add_subplot(111, projection='3d') # PCAExample.plot_sample_data(bow_train, color='r', annotations=bow_train, ax=ax) # fig.hold(True) # PCAExample.plot_sample_data(bow_test, color='g', annotations=bow_test, ax=ax) # PCAExample.set_axis_limits(ax, limits=((0, 10), (0, 10), (0,10))) # fig.hold() # # # #koeffizienten plot # # T_test, S_arr_test, D_test_ = np.linalg.svd(bow_test.T, full_matrices=False) # # S_test = np.diag(S_arr_test) # # n_topics = 3 # top_feature_trans = TopicFeatureTransform(n_topics) # top_feature_trans.estimate(bow_train, None) # test_daten = top_feature_trans.transform(bow_test) # train_daten = top_feature_trans.transform(bow_train) # fig = plt.figure() # ax = fig.add_subplot(111, projection='3d') # PCAExample.plot_sample_data(D_.T, color='r', annotations=bow_train, ax=ax) # fig.hold(True) # PCAExample.plot_sample_data(D_test_.T, color='g', annotations=bow_test, ax=ax) # PCAExample.set_axis_limits(ax, limits=((-1, 1), (-1, 1), (-1,1))) # fig.hold() # # Fuehren Sie nun eine Dimensionsreduktion der Trainings und Testdaten auf zwei # Dimensionen durch und plotten Sie die Topic-Koeffizienten (inkl. Bag-of-Words # Annotationen). Vergleichen Sie alle drei Plots miteinander. Welchen Effekt hat # die Topic Modellierung im Bezug auf typische Termkonfigurationen? # # Optional: Transformieren Sie die Daten in einen Topic-Raum mit Dimension Eins # und plotten Sie die Koeffizienten inkl. deren Bag-of-Words Annotationen. # n_topics = 2 top_feature_trans = TopicFeatureTransform(n_topics) top_feature_trans.estimate(bow_train, bow_train) bow_transformed = top_feature_trans.transform(bow_test) bow_train_transformed = top_feature_trans.transform(bow_train) fig = plt.figure() ax = fig.add_subplot(111) PCAExample.plot_sample_data(bow_train_transformed, annotations=bow_train, ax=ax) PCAExample.set_axis_limits(ax, limits=((-1, 1), (-1, 1))) fig = plt.figure() ax = fig.add_subplot(111) PCAExample.plot_sample_data(bow_transformed, annotations=bow_test, ax=ax) PCAExample.set_axis_limits(ax, limits=((-1, 1), (-1, 1))) plt.show() # S_inv = np.linalg.inv(S) # S_inv_test = np.linalg.inv(S_test) # # T = T[:n_topics] # S_inv = S_inv[:n_topics,:n_topics] # T_test = T_test[:n_topics] # S_inv_test = S_inv_test[:n_topics,:n_topics] # # data_trans = np.dot(np.dot(bow_train, T.T), S_inv) # data_trans_test = np.dot(np.dot(bow_test, T_test.T), S_inv_test) # # fig = plt.figure() # ax = fig.add_subplot(111) # PCAExample.plot_sample_data(data_trans, color='r', annotations=bow_train, ax=ax) # fig.hold(True) # PCAExample.plot_sample_data(data_trans_test, color='g', annotations=bow_test, ax=ax) # PCAExample.set_axis_limits(ax, limits=((-1, 1), (-1, 1))) # fig.hold() # plt.show() # # # Integrieren Sie nun die Topic-Raum Modellierung mittels Singulaerwertzerlegung # in die Kreuzvalidierung auf dem Brown Corpus. Berechnen Sie dabei fuer # jede Aufteilung von Training und Test einen neuen Topic-Raum. Transformieren # Sie die Bag-of-Words Repraesentationen und fuehren Sie die Klassifikation # wie zuvor mit dem Naechster-Nachbar-Klassifikator durch. Verwenden Sie dabei # verschiedene Distanzmasse und evaluieren Sie die Klassifikationsfehlerrate # fuer verschiedene Dimensionalitaeten des Topic-Raums. Die anderen Parameter # waehlen Sie gemaess der besten bisherigen Ergebnisse. # # Implementieren Sie die Klasse TopicFeatureTransform im features Modul # und verwenden Sie sie mit der CrossValidation Klasse (evaluation Modul). # # Optional: Fuehren Sie eine automatische Gridsuche ueber den kompletten Paramterraum # durch. Legen Sie sinnvolle Wertebereiche und Schrittweiten fuer die einzelnen # Parameter fest. Wie lassen sich diese bestimmen? # # Optional: Passen Sie das Suchgrid dynamisch gemaess der Ergebnisse in den einzelnen # Wertebereichen an. CorpusLoader.load() brown = CorpusLoader.brown_corpus() normalized_words = WordListNormalizer().normalize_words(brown.words())[1] vocab_size = 2000 distance_function="cosine" knn=6 vocabulary = BagOfWords.most_freq_words(normalized_words, vocab_size) word_bag = BagOfWords(vocabulary) bow_mat = {} for cat in brown.categories(): bow_mat[cat] = [WordListNormalizer().normalize_words(brown.words(fileids=doc))[1] for doc in brown.fileids(categories=cat)] category_dic = word_bag.category_bow_dict(bow_mat) cross_validator = CrossValidation(category_dic, 5) classificator = KNNClassifier(knn, distance_function) print cross_validator.validate(classificator, TopicFeatureTransform(20))