Example #1
0
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 = ["''", '``', '--']
Example #3
0
    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 = ["''", '``', '--']
Example #4
0
    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
Example #6
0
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()
Example #7
0
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
Example #8
0
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')
Example #9
0
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
Example #10
0
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)
Example #11
0
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)
Example #13
0
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')
Example #14
0
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')
Example #15
0
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)
Example #16
0
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))