def main(): parser = argparse.ArgumentParser('LM main') parser.add_argument('--corpus', type=str, default='tiny_corpus.txt', help='corpus to train') parser.add_argument('--batch_size', type=int, default=128) parser.add_argument('--emb_dim', type=int, default=128) parser.add_argument('--num_layers', type=int, default=1) parser.add_argument('--drop', type=float, default=0.1) parser.add_argument('--num_workers', type=int, default=4) parser.add_argument('--lr', type=float, default=0.1) parser.add_argument('--momentum', type=float, default=.99) parser.add_argument('--clip_norm', type=float, default=5) parser.add_argument('--epochs', type=int, default=100) parser.add_argument('--device', type=str, default='cpu') parser.add_argument('--save', type=str, default='model.pt') parser.add_argument('--load', type=str, default=None) parser.add_argument('--arpa', type=str, default='tiny_corpus.arpa') args = parser.parse_args() corpus = Corpus(args.corpus) loader = CorpusLoader(corpus, args.batch_size, True, args.num_workers) if args.load is None: extractor = EmbeddingExtractor(corpus.vocab, args.emb_dim, args.device) network = Network(extractor, args.num_layers, drop=args.drop).to(args.device) else: network = torch.load(args.load, map_location=args.device) network.extractor.device = args.device network.rnn.flatten_parameters() ken_lm = kenlm.LanguageModel(args.arpa) optimizer = torch.optim.SGD(network.parameters(), args.lr, args.momentum) loss_fn = torch.nn.CrossEntropyLoss(reduction='none') scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=10, verbose=True, factor=.5) min_loss = float('inf') for epoch in range(args.epochs): pred = generate(network, device=args.device) gen_sentence = ' '.join(pred) ppl = ken_lm.perplexity(gen_sentence) print('%s\nPPL:\t%f' % (gen_sentence, ppl)) loss = single_epoch(network, loader, optimizer, loss_fn, args.clip_norm) print('epochs %d \t loss %.3f' % (epoch, loss)) scheduler.step(loss) if min_loss > loss: min_loss = loss print('saving to %s' % args.save) torch.save(network, args.save) print()
def __init__(self, stoplist=None, stemmer=None): """Initialisiert die Filter Params: stoplist: Python Liste von Woertern, die entfernt werden sollen (stopwords). Optional, verwendet NLTK stopwords falls None stemmer: Objekt, das die stem(word) Funktion implementiert. Optional, verwendet den Porter Stemmer falls None. """ if stoplist is None: stoplist = CorpusLoader.stopwords_corpus() self.__stoplist = stoplist if stemmer is None: stemmer = PorterStemmer() self.__stemmer = stemmer self.__punctuation = string.punctuation self.__delimiters = ["''", '``', '--']
def normalize_words(self, word_list): """Normalisiert die gegebenen Woerter nach in der Methode angwendeten Filter-Regeln (Gross-/Kleinschreibung, stopwords, Satzzeichen, Bindestriche und Anfuehrungszeichen, Stemming) Params: word_list: Python Liste von Worten. Returns: word_list_filtered, word_list_stemmed: Tuple von Listen Bei der ersten Liste wurden alle Filterregeln, bis auch stemming angewandt. Bei der zweiten Liste wurde zusaetzlich auch stemming angewandt. """ stopwords = CorpusLoader.stopwords_corpus() punctation = string.punctuation filteredUpper = [w.lower() for w in word_list] filteredStopwords = [w for w in filteredUpper if w not in stopwords] word_list_filtered = [w for w in filteredStopwords if w not in punctation and w not in self.__delimiters] word_list_stemmed = [PorterStemmer().stem(w) for w in word_list_filtered] return word_list_filtered, word_list_stemmed
def aufgabe1(): # # In der ersten Aufgabe sollen Sie sich mit dem Brown Corpus # vertraut machen. # - Laden Sie den Corpus und schauen Sie sich dessen Aufbau an. # - Analysieren Sie den Corpus in dem Sie Wortstatistiken bestimmen. # - Verbessern Sie die Aussagekraft der Statistiken. # Laden des Corpus # Fuer das Fachprojekt benoetigen Sie die NLTK (http://www.nltk.org/) # Datensaetze "brown" und "stopwords". Falls diese noch nicht lokal # auf Ihrem Rechner verfuegbar sein sollten, koennen Sie sie ueber # den "NLTK Downloader" herunterladen. Ein entsprechender Dialog # oeffnet sich in diesem Fall automatisch. CorpusLoader.load() # # Im Folgenden werden einige grundlegende Statistiken des Brown Corpus # ausgegeben, die vor allem etwas ueber dessen Struktur / Aufbau # aussagen. # Siehe auch: http://en.wikipedia.org/wiki/Brown_Corpus # # Der Corpus enthaelt verschiedene Kategorien, in die Dokumente # einsortiert sind. Ein Dokument besteht aus Woertern. # Als naechstes sehen Sie, wie Sie auf Kategorien, Dokumente und # Woerter zugreifen koennen. brown = CorpusLoader.brown_corpus() brown_categories = brown.categories() brown_documents = brown.fileids() brown_words = brown.words() # Geben Sie nun die Gesamtanzahl von Kategorien, Dokumenten und Woertern # mit print auf der Konsole aus. print('Anzahl Kategorien: ' + str(len(brown_categories))) print('Anzahl Dokumente: ' + str(len(brown_documents))) print('Anzahl Wörter: ' + str(len(brown_words))) # Geben Sie die Namen der einzelnen Kategorien aus. print('Die Namen der Kategorien:') for val in brown_categories: print(val) print('\n') # Bisher haben Sie noch keine Information ueber die Struktur des Brown # Corpus gewonnen, da sie jeweils die Gesamtzahl von Kategorien, Dokumenten # und Woertern ausgegeben haben. # # Geben Sie als naechstes die Anzahl von Dokumenten und Woertern je # Kategorie aus. # http://www.nltk.org/howto/corpus.html#categorized-corpora # Hilfreiche Funktionen: fileids, words for val in brown_categories: print(f'Category {val}: ') print('Number of documents per category: ' + str(len(brown.fileids(val)))) print('Number of words per category: ' + str(len(brown.words(categories=val)))) print('\n') # Visualisieren Sie die Verteilungen mit Hilfe von horizontalen bar plots. # http://matplotlib.org/examples/lines_bars_and_markers/barh_demo.html #Balkendiagramm (Y-Achse: Kategorien, X-Achse: Anzahl Dokumente) plt.barh(brown_categories, [len(brown.fileids(cat)) for cat in brown_categories]) plt.xlabel('Number of Documents') plt.ylabel('Categories') #Balkendiagramm(Y-Achse: Kategorien, X-Achse: Anzahl Wörter) plt.figure() plt.barh(brown_categories, [len(brown.words(categories=cat)) for cat in brown_categories]) plt.xlabel('Number of Words') plt.ylabel('Categories') print('Fenster müssen geschlossen werden, damit weiter kompiliert wird') print('\n') plt.show() # Optional: Plotten Sie die Verteilungen mit vertikalen bar plots. # Vermeiden Sie, dass sich die an der x-Achse aufgetragenen labels ueberlappen # http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.set_xticklabels # Stellen Sie nun die Verteilungen ueber Dokumente und Woerter in einem # gemeinsamen Plot dar. Verwenden Sie unterschiedliche Farben. # http://matplotlib.org/examples/api/barchart_demo.html #plt.bar(len(brown_categories), [len(brown.fileids(cat)) for cat in brown_categories], width=0.3, color='green') #plt.bar(len(brown_categories)+0.3, [len(brown.words(categories=cat)) for cat in brown_categories], width=0.3, color='blue') #plt.show() # ********************************** 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/3/library/unittest.html#skipping-tests-and-expected-failures # Denken Sie aber daran sie spaeter wieder zu aktivieren. # # Wenn etwas unklar ist, fragen Sie! # ********************************************************************************* # Um Texte / Dokumente semantisch zu analysieren, betrachtet man Verteilungen # ueber Wortvorkommen. Ziel dieser semantischen Analyse soll es letztlich sein # unbekannte Dokumente automatisch einer bekannten Kategorie / Klasse zuzuordnen. # # Bestimmen Sie die 20 haeufigsten Woerter des Brown Corpus (insgesamt), sowie # die 20 haeufigsten Woerter je Kategorie. # http://docs.python.org/3/library/collections.html#collections.defaultdict # http://docs.python.org/3/library/functions.html#sorted # Hinweis: Die Dokumentation zu defaultdict enthaelt ein sehr hilfreiches Beispiel. # # Implementieren Sie die (statische) Funktion BagOfWords.most_freq_words im Modul # features. print('Die 20 häufigsten Wörter insgesamt: ' + str(BagOfWords.most_freq_words(brown_words, 20))) print('Die 20 häufigsten Wörter pro Kategorie: ') for category in brown_categories: val = BagOfWords.most_freq_words(brown.words(categories=category), 20) print(f'Category {category}: {val}') print('\n') # # Diese Woerter sind nicht besonders charakteristisch fuer die Unterscheidung # verschiedener Kategorien. Daher entfernt man solche wenig aussagekraeftigen # Woerter vor einer semantischen Analyse. Man bezeichnet diese Woerter als # stopwords. # Eine Liste mit stopwords wird durch NLTK bereitgestellt (siehe oben sowie # im 'corpus' Modul). # Filtern Sie nun alle stopwords bevor Sie die 20 haeufigsten Woerter im Brown # Corpus (insgesamt und je Kategorie) erneut bestimmen. Achten Sie dabei auch # Gross- und Kleinschreibung und filtern Sie ach Satzzeichen (string.punctuation). # http://www.nltk.org/howto/corpus.html#word-lists-and-lexicons # http://docs.python.org/3/library/string.html # # Geben Sie zunaechst stopwords und Satzzeichen auf der Kommandozeile aus. stopwords = CorpusLoader.stopwords_corpus() list_punctuation = [a for a in string.punctuation] print('Ausgabe der Stopwords: ' + str(stopwords)) print('Ausgabe der Satzzeichen: ' + str(list_punctuation)) print('\n') # Mit der Liste von stopwords koennen Sie noch keine grammatikalischen Varianten # von Woertern erfassen, die ebenfalls nicht entscheidend fuer die semantische # Analyse von Texten sind (zum Beispiel: walking, walked). # # Verwenden Sie daher den PorterStemmer um Woerter auf ihre Wortstaemme abzubilden. # Geben Sie die 20 haeufigsten Woerter nach jedem Filter Schrift aus: # 1. stopwords und Satzzeichen # 2. Abbildung auf Wortstaemme (stemming) # Erlaeutern Sie Ihre Beobachtungen. # http://www.nltk.org/api/nltk.stem.html#module-nltk.stem.porter # # Implementieren Sie die Funktion WordListNormalizer.normalize_words im # features Modul. words_normalizer = WordListNormalizer() filtered_list, stemmed_list = words_normalizer.normalize_words(brown_words) print('Gesamtwörter gefiltert: ' + str(BagOfWords.most_freq_words(filtered_list, 20))) print('Gesamtwörter gestemmt: ' + str(BagOfWords.most_freq_words(stemmed_list, 20))) print('Wörter je Kategorie gefiltert und gestemmt:') for category in brown_categories: filtered_list, stemmed_list = words_normalizer.normalize_words( brown.words(categories=category)) filteredVal = BagOfWords.most_freq_words(filtered_list, 20) stemmedVal = BagOfWords.most_freq_words(stemmed_list, 20) print(f'Category {category}: {filteredVal}') print(f'Category {category}: {stemmedVal}') return
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) plt.show() # 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. # 1/N * Sum((x-u).T * x-u) cov = lambda x: np.dot((x - np.mean(x)).T, (x - np.mean(x))) / x.shape[0] cov2d = cov(samples_2d) print(cov2d) # # 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. # # X = T * S * D' # t x d t x m m x m m x d # # D' = X / (T*S) # 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], #v1 [4, 1, 0], #v2 [3, 3, 1], #v3 [9, 8, 2], #v4 [1, 5, 3], #v5 [0, 7, 9], #v6 [2, 9, 6], #v7 [0, 2, 3], #v8 [5, 3, 3] ]) #v9 # vielfache : v3, v4 | v6, v8 | v5, v7 # 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]]) # X = T * S * D' # t x d t x m m x m m x d # # D = X' * T * S^-1 # d x m d x t t x m m x m # bow_test bereits transponiert vorliegend D_bow_test = np.dot(np.dot(bow_test, T), np.linalg.inv(S)) print "in den topic-Raum transponiert" print D_bow_test # # 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 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. train_annotations = PCAExample.samples_coordinate_annotations(bow_train) test_annotations = PCAExample.samples_coordinate_annotations(bow_test) fig = plt.figure() ax = fig.add_subplot(111, projection='3d') print(bow_train) PCAExample.plot_sample_data(bow_train, color='b', annotations=train_annotations, ax=ax) PCAExample.plot_sample_data(bow_test, color='r', annotations=test_annotations, ax=ax) plt.show() fig = plt.figure() ax = fig.add_subplot(111, projection='3d') PCAExample.plot_sample_data(D_.T, color='b', annotations=train_annotations, ax=ax) PCAExample.plot_sample_data(D_bow_test, color='r', annotations=test_annotations, ax=ax) plt.show() # # 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. # train_D_2d = np.dot(np.dot(bow_train, T[:, :2]), np.linalg.inv(S[:2, :2])) print(train_D_2d.shape) test_D_2d = np.dot(np.dot(bow_test, T[:, :2]), np.linalg.inv(S[:2, :2])) print(test_D_2d.shape) plt.rcdefaults() fig, ax = plt.subplots() PCAExample.plot_sample_data(train_D_2d, color='b', annotations=train_annotations, ax=ax) PCAExample.plot_sample_data(test_D_2d, color='r', annotations=test_annotations, ax=ax) 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. #parameters n_neighbours = 4 metrices = ("cityblock", "euclidean", "cosine") voc_size = 2000 weighting = 'rel' CorpusLoader.load() brown = CorpusLoader.brown_corpus() # normalizing words normalizer = WordListNormalizer() cat_wordlist_dict = normalizer.category_wordlists_dict(corpus=brown) wordlists = itertools.chain(*(cat_wordlist_dict.itervalues())) normalized_words = itertools.chain(*wordlists) vocab = BagOfWords.most_freq_words(normalized_words) # evaluating results = [] mins = [] mins_mtc = [] n_cats = len(brown.categories()) print('evaluating for 1-{} dimensions'.format(n_cats + 1)) max_dim = 102 step = 10 for t_dim in range(1, max_dim, step): # initializing the transformation topic_trans = TopicFeatureTransform(t_dim) # with different metrices for metric in metrices: config = Configuration(brown, cat_wordlist_dict, vocab, voc_size, metric, n_neighbours, weighting) config.fit() results.append([metric, 'dim={}'.format(t_dim)] + list(config.eval(feature_trans=topic_trans))) # logging the best metric tmp_min_idx = len(results) - 3 for rel_idx, r in enumerate(results[-3:]): if results[tmp_min_idx][2] > r[2]: tmp_min_idx = len(results) - 3 + rel_idx mins.append(results[tmp_min_idx][2]) mins_mtc.append(results[tmp_min_idx][0]) # displaying the results for res in results: print('{},{}:\t{}'.format(res[0], res[1], res[2:])) plt.rcdefaults() fig, ax = plt.subplots() plt.plot(range(1, max_dim, step), mins) # annotating the best metric for i in range(len(mins_mtc)): ax.annotate(mins_mtc[i], xy=((i + 1) * step - 9, mins[i])) plt.show()
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')
def aufgabe1(): # # In der ersten Aufgabe sollen Sie sich mit dem Brown Corpus aaaaaa # vertraut machen. # - Laden Sie den Corpus und schauen Sie sich dessen Aufbau an. # - Analysieren Sie den Corpus in dem Sie Wortstatistiken bestimmen. # - Verbessern Sie die Aussagekraft der Statistiken. # Laden des Corpus # Fuer das Fachprojekt benoetigen Sie die NLTK (http://www.nltk.org/) # Datensaetze "brown" und "stopwords". Falls diese noch nicht lokal # auf Ihrem Rechner verfuegbar sein sollten, koennen Sie sie ueber # den "NLTK Downloader" herunterladen. Ein entsprechender Dialog # oeffnet sich in diesem Fall automatisch. CorpusLoader.load() # # Im Folgenden werden einige grundlegende Statistiken des Brown Corpus # ausgegeben, die vor allem etwas ueber dessen Struktur / Aufbau # aussagen. # Siehe auch: http://en.wikipedia.org/wiki/Brown_Corpus # # Der Corpus enthaelt verschiedene Kategorien, in die Dokumente # einsortiert sind. Ein Dokument besteht aus Woertern. # Als naechstes sehen Sie, wie Sie auf Kategorien, Dokumente und # Woerter zugreifen koennen. brown = CorpusLoader.brown_corpus() brown_categories = brown.categories() brown_documents = brown.fileids() brown_words = brown.words() # Geben Sie nun die Gesamtanzahl von Kategorien, Dokumenten und Woertern # mit print auf der Konsole aus. print len(brown_categories) print len(brown_documents) print len(brown_words) # Geben Sie die Namen der einzelnen Kategorien aus. print brown_categories # Bisher haben Sie noch keine Information ueber die Struktur des Brown # Corpus gewonnen, da sie jeweils die Gesamtzahl von Kategorien, Dokumenten # und Woertern ausgegeben haben. # # Geben Sie als naechstes die Anzahl von Dokumenten und Woertern je # Kategorie aus. # http://www.nltk.org/howto/corpus.html#categorized-corpora # Hilfreiche Funktionen: fileids, words # # Visualisieren Sie die Verteilungen mit Hilfe von horizontalen bar plots. # http://matplotlib.org/examples/lines_bars_and_markers/barh_demo.html # # Optional: Plotten Sie die Verteilungen mit vertikalen bar plots. # Vermeiden Sie, dass sich die an der x-Achse aufgetragenen labels ueberlappen # http://matplotlib.org/api/axes_api.html#matplotlib.axes.Axes.set_xticklabels # Stellen Sie nun die Verteilungen ueber Dokumente und Woerter in einem # gemeinsamen Plot dar. Verwenden Sie unterschiedliche Farben. # http://matplotlib.org/examples/api/barchart_demo.html listOfDocs = [] listOfWords = [] for i in brown_categories: docPerCategorie = len(brown.fileids(categories=i)) print docPerCategorie listOfDocs.append(docPerCategorie) wordsPerCategorie = len(brown.words(categories=i)) print wordsPerCategorie listOfWords.append(wordsPerCategorie) allDocs = np.array(listOfDocs) allWords = np.array(listOfWords) plt.barh(np.arange(len(brown_categories)), allDocs , xerr=0, align='center', alpha=0.4) plt.yticks(np.arange(len(brown_categories)), brown_categories) plt.xlabel("Amount of documents") plt.draw() plt.show() plt.barh(np.arange(len(brown_categories)), allWords , xerr=0, align='center', alpha=0.4) plt.yticks(np.arange(len(brown_categories)), brown_categories) plt.xlabel("Amount of words") plt.draw() plt.show() # Gemeinsamer Plot ind = np.arange(len(brown_categories)) width = 0.35 fig, ax = plt.subplots() rects1 = ax.bar(ind, allDocs, width, color='r', yerr=0) rects2 = ax.bar(ind + width, allWords, width, color='y', yerr=0) ax.set_ylabel('Amount') ax.set_title('Amount of documents and words by categories') ax.set_xticks(ind + width) ax.set_xticklabels(brown_categories, rotation='vertical') ax.legend((rects1[0], rects2[0]), ('Documents', 'Words')) # def autolabel(rects): # # attach some text labels # for rect in rects: # height = rect.get_height() # ax.text(rect.get_x() + rect.get_width()/2., 1.05*height, # '%d' % int(height), # ha='center', va='bottom') # autolabel(rects1) # autolabel(rects2) plt.show() # ********************************** 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! # ********************************************************************************* # Um Texte / Dokumente semantisch zu analysieren, betrachtet man Verteilungen # ueber Wortvorkommen. Ziel dieser semantischen Analyse soll es letztlich sein # unbekannte Dokumente automatisch einer bekannten Kategorie / Klasse zuzuordnen. # # Bestimmen Sie die 20 haeufigsten Woerter des Brown Corpus (insgesamt), sowie # die 20 haeufigsten Woerter je Kategorie. # http://docs.python.org/2/library/collections.html#collections.defaultdict # http://docs.python.org/2/library/functions.html#sorted # Hinweis: Die Dokumentation zu defaultdict enthaelt ein sehr hilfreiches Beispiel. # # Implementieren Sie die (statische) Funktion BagOfWords.most_freq_words im Modul # features. stopwords = CorpusLoader.stopwords_corpus() print stopwords punctation = string.punctuation print punctation for i in brown_categories: wordsPerCategorie = WordListNormalizer().normalize_words(brown.words(categories = i)) print BagOfWords.most_freq_words(wordsPerCategorie[0], 20) # # Diese Woerter sind nicht besonders charakteristisch fuer die Unterscheidung # verschiedener Kategorien. Daher entfernt man solche wenig aussagekraeftigen # Woerter vor einer semantischen Analyse. Man bezeichnet diese Woerter als # stopwords. # Eine Liste mit stopwords wird durch NLTK bereitgestellt (siehe oben sowie # im 'corpus' Modul). # Filtern Sie nun alle stopwords bevor Sie die 20 haeufigsten Woerter im Brown # Corpus (insgesamt und je Kategorie) erneut bestimmen. Achten Sie dabei auch # Gross- und Kleinschreibung und filtern Sie ach Satzzeichen (string.punctuation). # http://www.nltk.org/howto/corpus.html#word-lists-and-lexicons # http://docs.python.org/2/library/string.html # # Geben Sie zunaechst stopwords und Satzzeichen auf der Kommandozeile aus. # Mit der Liste von stopwords koennen Sie noch keine grammatikalischen Varianten # von Woertern erfassen, die ebenfalls nicht entscheidend fuer die semantische # Analyse von Texten sind (zum Beispiel: walking, walked). # # Verwenden Sie daher den PorterStemmer um Woerter auf ihre Wortstaemme abzubilden. # Geben Sie die 20 haeufigsten Woerter nach jedem Filter Schrift aus: # 1. stopwords und Satzzeichen # 2. Abbildung auf Wortstaemme (stemming) # Erlaeutern Sie Ihre Beobachtungen. # http://www.nltk.org/api/nltk.stem.html#module-nltk.stem.porter # # Implementieren Sie die Funktion WordListNormalizer.normalize_words im # features Modul. filteredTupel = WordListNormalizer().normalize_words(brown_words) print "Of ALL!!!!!" print BagOfWords.most_freq_words(filteredTupel[0], 20) return
class EmbeddingExtractor(Extractor): def __init__(self, vocab: list, emb_dim: int, device: str): super(EmbeddingExtractor, self).__init__(vocab, emb_dim, device) self.embedding = torch.nn.Embedding(len(vocab), emb_dim) def forward(self, sentences: list) -> PackedSequence: pack = self.get_packed_sequence(sentences) vectors = self.embedding(pack.data) return PackedSequence(vectors, pack.batch_sizes) def get_packed_sequence(self, sentences: list): seqs = [ torch.LongTensor([self.word2idx[word] for word in s]) for s in sentences ] return pack_sequence(seqs).to(self.device) if __name__ == '__main__': from corpus import Corpus, CorpusLoader corpus_file = 'tiny_corpus.txt' corpus = Corpus(corpus_file) loader = CorpusLoader(corpus, 100, False, 8) extractor = EmbeddingExtractor(corpus.vocab, 64, 'cpu') print(corpus.vocab) for x, y in loader: pack = extractor(x) print(len(x), pack.data.shape)
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)
def aufgabe5(): # # Naive Bayes Klassifikation # # Der Naive Bayes Klassifikator basiert auf dem Satz von Bayes fuer bedingte # Wahrscheinlichkeiten: # # P( K_i ) P( f | K_i ) # P( K_i | f ) = ----------------------- # P( f ) # # Man kann also gewissermassen eine bedingte Wahrscheinlichkeit umdrehen, # wenn man die Einzelwahrscheinlichkeiten kennt. # # Der Bayes Klassifikator ordnet nun einem Sample f eine Klasse K_i nach # maximaler a-posteriori Wahrscheinlichkeit zu. Der Index k, der dem Sample # zugeordneten Klasse bestimmt sich gemaess: # # k = argmax P( K_i | f ) # i # # Der Klassifikator ist damit durch die Verteilungen von P( K_i ) und P( f | K_i ) # definiert. # # FRAGEN: # Warum wird die Verteilung zu P( f ) nicht benoetigt? # # Wie laesst sich die Verteilung zu P( K_i ) interpretieren? # # Wie laesst sich die Verteilung P( f | K_i ) interpretieren? # # Welche Verteilungsmodelle nehmen wir hier fuer P( K_i ) und P(f | K_i ) an und # warum? In unserem Fall ist f eine Bag-of-Words Repraesentation eines Dokuments # und K_i eine Dokumentenkategorie. # # Bei der direkten Umsetzung kommt es zu numerischen Problemen durch # zu kleinen Zahlen. Wodurch werden diese Probleme verursacht? # Loesen lassen sie sich durch eine Betrachtung der logarithmischen a-posteriori # Wahrscheinlichkeit. # # Warum? Erklaeren Sie ausserdem warum sich das Ergebnis der Klassifikation # durch die logarithmische Betrachtung nicht aendert. # # Stellen Sie die entsprechende Formel unter Beruecksichtigung der Verteilungsmodelle um. # # Wie lassen sich die Verteilungen aus Beispieldaten statistisch schaetzen? # CorpusLoader.load() brown = CorpusLoader.brown_corpus() # # Implementieren Sie den Bayes Klassifikator und integrieren Sie ihn in die # Kreuzvalidierung zur Kategorisierung der Dokumente des Brown Corpus (classification Modul). # Fuehren Sie die Vorverarbeitung und Merkmalsberechnung wie bei dem K Naechste # Nachbarn Klassifikator durch. # Evaluieren Sie die Fehlerrate fuer verschiedene Groessen des Vokabulars (500, 1000, 1500). # Lassen sich die verschiedenen Term Gewichtungen sinnvoll einsetzen (absolut, relativ, idf)? # Fuehren Sie gegebenenfalls eine entsprechende Evaluierung durch. # # Vergleichen Sie die Fehlerraten mit denen des K Naechste Nachbarn Klassifikators. # raise NotImplementedError('Implement me')
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))