[PYTHON] Definieren Sie Ihre eigene Distanzfunktion mit k-Mitteln des Scikit-Lernens

Was in diesem Artikel einzuführen

Apropos k-means-Methode: Wie Sie alle wissen, teilt diese die Daten.

Da es oft in Lehrbüchern zu sehen ist, werde ich detaillierte Erklärungen weglassen, aber was immer noch verwendet wird, ist (verbotene Angelegenheit), nicht wahr?

Übrigens diese Art von Video und diese Art von Tool ), Ich finde es schön, die bewegung von k-means gut zu verstehen.

In k-means ist also eine "Distanzfunktion" erforderlich, um den Abstand zwischen dem Schwerpunkt und den einzelnen Daten zu messen.

In Lehrbüchern wird oft "euklidische Distanz" gewählt, aber ist das wirklich richtig?

Dieses Papier, Anna Huang, "Ähnlichkeitsmaße für das Clustering von Textdokumenten", 2008

Wird eine solche Frage klar beantworten.

Werfen wir einen Blick auf Tabelle 4, die aus dem Papier entlehnt wurde. Da es sich um einen Entropieindex handelt, ist ein niedrigeres Clustering besser.

スクリーンショット 2015-11-04 20.24.24.png

Sie können sehen, dass die euklidische Distanz in der Textklassifizierungsaufgabe nicht gerecht wird.

Dann ist es die Menschheit, die Sie dazu bringt, andere Distanzfunktionen auszuprobieren.

Versuchen wir es mit Scikit-Learn

Zusammenfassend gibt es keine solche Option.

Mendokusei zu untersuchen. Es ist nicht wirklich.

Sie können das sehen, indem Sie sich den Scikit-Lerncode ansehen.

    closest_dist_sq = euclidean_distances(
        centers[0, np.newaxis], X, Y_norm_squared=x_squared_norms,
        squared=True)
    current_pot = closest_dist_sq.sum()

Dies ist k-means Code-Snippet, aber der euklidische Abstand ist fest codiert Sie können sehen, dass.

Mit anderen Worten, es gibt keinen Raum, um die Distanzfunktion als Option zu ändern.

Aber was ist es nicht? Bei Github-Problemen heißt es etwa "weil es schwierig ist, mit anderen Distanzfunktionen zu verallgemeinern". Es gibt.

Trotzdem möchte ich es zu einer versteckten Option machen ...

Wie benutzt man dann andere Distanzfunktionen? ??

Es scheint mehrere Möglichkeiten zu geben.

  1. Schreiben Sie k-means selbst. Es befindet sich auf der Stack-Overflow-Seite (http://stackoverflow.com/questions/5529625/is-it-possible-to-specify-your-own-distance-function-using-scikit-learn-k-means). Die Methode ist geschrieben
  2. Verwenden Sie die k-Schwerpunkt-Methode. Es scheint, dass es mit Scikit-Learn verwendet werden kann. Ich habe es nicht überprüft.
  3. Verwenden Sie Monkey-Patch. Diesmal werde ich das tun.

Was ist Affen-Patch? Mit anderen Worten: "Überschreiben Sie die Methode und machen Sie, was Sie wollen".

Dieses Mal überschreiben wir die euklidische Distanzfunktion in k-Mitteln. Diese Seite beschreibt, wie dies gemacht wird.

Lass es uns tatsächlich tun.

Die zu verwendenden Daten stammen von hier. Es sind keine Textdaten, aber es ist süß ...

Lassen Sie uns das Verhalten der euklidischen Distanz von scikit-learn sehen

Die euklidische Entfernung, die k-means anruft, ist this.

Das Verhalten kann grob unterteilt werden.

  1. Wenn Y Keine ist
  2. Wenn X ein Array aus einem Sample und Y ein Array aus mehreren Samples ist
  3. Wenn X ein Array von 2 Samples und Y ein Array von mehreren Samples ist

ist.

In beiden Fällen

array([
    [Abstand zwischen X und Y.]
])

Gibt ein Array des Formulars zurück.

Wenn Sie also eine neue Distanzfunktion definieren, folgen Sie diesem Format.

Implementieren Sie die Abstandsfunktion des Pearson-Korrelationskoeffizienten

Lassen Sie uns den in diesem Artikel vorgestellten Pearson-Korrelationskoeffizienten implementieren. In Python ist es Verfügbar in scipy.

Wie in der Veröffentlichung erwähnt, wird es jedoch nicht zu einer Distanzfunktion, wie es ist. Deshalb werde ich die Formel ein wenig ändern.

special_pearsonr(X, Y) = {
    1 - pearsonr(X, Y) if pearsonr(X, Y) > 0,
    |pearsonr(X, Y)| else
}

Die Formel wird transformiert.

Lassen Sie es uns nun unter Berücksichtigung der drei Fälle der euklidischen Distanz implementieren.

def special_pearsonr(X, Y):
    pearsonr_value = scipy.stats.pearsonr(X, Y)
    if pearsonr_value[0] < 0:
        return abs(pearsonr_value[0])
    else:
        return 1 - pearsonr_value[0]


def sub_pearsonr(X, row_index_1, row_index_2):
    pearsonr_distance = special_pearsonr(X[row_index_1], X[row_index_2])
    return (row_index_1, row_index_2, pearsonr_distance)


def pearsonr_distances(X, Y=None):
    if Y==None:
        #Es wird nur X eingegeben und X ist 2d-Für Array
        row_combinations = list(combinations(range(0, len(X)), 2))
        pearsonr_set = [sub_pearsonr(X, index_set_tuple[0], index_set_tuple[1]) for index_set_tuple in row_combinations]
        matrix_source_data = pearsonr_set + map(copy_inverse_index, pearsonr_set)

        row = [t[0] for t in matrix_source_data]
        col = [t[1] for t in matrix_source_data]
        data = [t[2] for t in matrix_source_data]

        pearsonr_matrix = special_pearsonr((data, (row, col)), (X.shape[0], X.shape[0]))
        return pearsonr_matrix.toarray()

    elif len(X.shape)==1 and len(Y.shape)==2:
        #Wenn X eine Probe ist und Y mehrere Proben ist
        #return ist ein Array von 1 Beispiel
        pearsonr_set = numpy.array([special_pearsonr(X, Y[y_sample_index]) for y_sample_index in range(0, Y.shape[0])])

        return pearsonr_set

    elif len(X.shape)==2 and len(Y.shape)==2:
        #X in einer Zeile[i]Andy[j] in n(Y)Notieren Sie die Entfernung und geben Sie sie zurück
        # X[i]Eine Funktion, die alle Abstände zwischen und Y berechnet
        pearsonr_x_and_all_y = lambda X, Y: numpy.array([special_pearsonr(X, Y[y_sample_index]) for y_sample_index in range(0, Y.shape[0])])
        pearsonr_divergence_set = numpy.array([pearsonr_x_and_all_y(X[x_i], Y) for x_i in range(0, X.shape[0])])
        return pearsonr_divergence_set
    else:
        raise Exception("Exception case caused")

Die Distanzfunktion, die pearsonr_distances mit k-means aufruft.

Lassen Sie uns nun die euklidische Distanzfunktion mit einem Affen-Patch versehen.

start = time.time()

#Um die Eingabe zu gewährleisten, bereiten Sie eine Funktion mit denselben Parametern wie die euklidische Distanzfunktion vor.
def new_euclidean_distances(X, Y=None, Y_norm_squared=None, squared=False):
    return pearsonr_distances(X, Y)

from sklearn.cluster import k_means_

#Hier überschreiben!
k_means_.euclidean_distances = new_euclidean_distances
kmeans_model = KMeans(n_clusters=3, random_state=10, init='random').fit(features)
print(kmeans_model.labels_)
elapsed_time = time.time() - start
print ("Pearsonr k-means:{0}".format(elapsed_time))

Ich wollte die Ausführungszeit sehen, also habe ich beschlossen, auch die Zeit zu messen.

Ich habe vergessen zu sagen, dass die Daten sind

features = numpy.array([
        [  80,  85, 100 ],
        [  96, 100, 100 ],
        [  54,  83,  98 ],
        [  80,  98,  98 ],
        [  90,  92,  91 ],
        [  84,  78,  82 ],
        [  79, 100,  96 ],
        [  88,  92,  92 ],
        [  98,  73,  72 ],
        [  75,  84,  85 ],
        [  92, 100,  96 ],
        [  96,  92,  90 ],
        [  99,  76,  91 ],
        [  75,  82,  88 ],
        [  90,  94,  94 ],
        [  54,  84,  87 ],
        [  92,  89,  62 ],
        [  88,  94,  97 ],
        [  42,  99,  80 ],
        [  70,  98,  70 ],
        [  94,  78,  83 ],
        [  52,  73,  87 ],
        [  94,  88,  72 ],
        [  70,  73,  80 ],
        [  95,  84,  90 ],
        [  95,  88,  84 ],
        [  75,  97,  89 ],
        [  49,  81,  86 ],
        [  83,  72,  80 ],
        [  75,  73,  88 ],
        [  79,  82,  76 ],
        [ 100,  77,  89 ],
        [  88,  63,  79 ],
        [ 100,  50,  86 ],
        [  55,  96,  84 ],
        [  92,  74,  77 ],
        [  97,  50,  73 ],
])

ist. Wenn ich es laufen lasse,

[0 0 0 1 1 2 1 0 2 1 0 2 2 0 0 1 1 0 1 0 2 0 2 0 2 2 1 1 2 1 1 2 2 2 1 2 2]
Pearsonr k-means:11.0138161182

Ich konnte bestätigen, dass es fest funktionierte! Yattane!

Die normale euklidische Distanzversion mit k-Mitteln ist übrigens

[1 1 0 1 1 2 1 1 2 1 1 1 2 1 1 0 2 1 0 0 2 0 2 0 1 1 1 0 2 2 2 2 2 2 0 2 2]
========================================
Normal k-means:0.016499042511

ist. Sie können sehen, ob es Daten mit unterschiedlichen Clustern von 0 und 1 gibt.

Die Ausführungszeit ist ... Leider gibt es einen Unterschied von fast 600 Mal ...

Da die Anzahl der aufzurufenden Funktionen zugenommen hat, kann nicht geholfen werden. Es besteht eine gute Chance, dass es etwas schneller geht, wenn die Implementierung entwickelt wird. (Erotische Leute, die beschleunigen werden. Rekrutierung)

Ich habe den Unterschied nicht gesehen, weil ich ihn nicht für die Klassifizierung von Dokumenten verwendet habe, aber da er in der Arbeit bewiesen wurde, wird der Pearson-Korrelationskoeffizient sicherlich gute Ergebnisse liefern (sollte sein ...)

Zusammenfassung


Apropos ...

Ich habe auch Calback Livener Distance implementiert. Leider hört es mit einem Fehler auf.

Bei der Messung des Abstands zwischen X und Y wird zwangsläufig ein negativer Faktor erzeugt, und der Abstand wird inf, sodass er überhaupt nicht initialisiert werden kann.

Ich frage mich, was ich mit den negativen Faktoren anfangen soll, aber was soll ich tun? Ich habe es in meiner Zeitung nicht erwähnt.

from sklearn.preprocessing import normalize
def averaged_kullback_leibler(X, Y):
    #norm_X = normalize(X=X, norm='l1')[0]
    #norm_Y = normalize(X=Y, norm='l1')[0]
    norm_X = X
    norm_Y = Y

    pie_1 = norm_X / (norm_X + norm_Y)
    pie_2 = norm_Y / (norm_X + norm_Y)
    M = (pie_1 * norm_X) + (pie_2 * norm_Y)

    KLD_averaged = (pie_1 * scipy.stats.entropy(pk=norm_X, qk=M)) + (pie_2 * scipy.stats.entropy(pk=norm_Y, qk=M))

    return KLD_averaged

def sub_KL_divergence(X, row_index_1, row_index_2):
    #kl_distance = scipy.stats.entropy(pk=X[row_index_1], qk=X[row_index_2])
    kl_distance = averaged_kullback_leibler(X[row_index_1], X[row_index_2])
    return (row_index_1, row_index_2, kl_distance)

def copy_inverse_index(row_col_data_tuple):
    return (row_col_data_tuple[1], row_col_data_tuple[0], row_col_data_tuple[2])

def KLD_distances(X, Y=None):
    if Y==None:
        #Es wird nur X eingegeben und X ist 2d-Für Array
        row_combinations = list(combinations(range(0, len(X)), 2))
        kl_divergence_set = [sub_KL_divergence(X, index_set_tuple[0], index_set_tuple[1]) for index_set_tuple in row_combinations]
        matrix_source_data = kl_divergence_set + map(copy_inverse_index, kl_divergence_set)

        row = [t[0] for t in matrix_source_data]
        col = [t[1] for t in matrix_source_data]
        data = [t[2] for t in matrix_source_data]

        kl_distance_matrix = scipy.sparse.csr_matrix((data, (row, col)), (X.shape[0], X.shape[0]))
        return kl_distance_matrix.toarray()
    elif len(X.shape)==1 and len(Y.shape)==2:
        #Wenn X eine Probe ist und Y mehrere Proben ist
        #return ist ein Array von 1 Beispiel
        kl_divergence_set = numpy.array([averaged_kullback_leibler(X, Y[y_sample_index]) for y_sample_index in range(0, Y.shape[0])])

        return kl_divergence_set
    elif len(X.shape)==2 and len(Y.shape)==2:
        #X in einer Zeile[i]Andy[j] in n(Y)Notieren Sie die Entfernung und geben Sie sie zurück
        # X[i]Eine Funktion, die alle Abstände zwischen und Y berechnet
        for x_i in range(0, X.shape[0]):
            xx = X[x_i]
            for y_sample_index in range(0, Y.shape[0]):
                #print(xx)
                #print(Y[y_sample_index])
                print(averaged_kullback_leibler(xx, Y[y_sample_index]))

        kld_x_and_all_y = lambda X, Y: numpy.array([averaged_kullback_leibler(X, Y[y_sample_index]) for y_sample_index in range(0, Y.shape[0])])
        kl_divergence_set = numpy.array([kld_x_and_all_y(X[x_i], Y) for x_i in range(0, X.shape[0])])
        return kl_divergence_set
    else:
        raise Exception("Exception case caused")

Recommended Posts

Definieren Sie Ihre eigene Distanzfunktion mit k-Mitteln des Scikit-Lernens
kmeans ++ mit scikit-learn
Ablauf beim Erstellen eines eigenen Pakets mit setup.py mit Python
Schreiben Sie Ihre eigene Aktivierungsfunktion mit Pytorch (hartes Sigmoid)
(Fortsetzung) Probieren Sie andere Entfernungsfunktionen mit kmeans in Scikit-learn aus
Parallele Verarbeitung mit Parallel von Scikit-Learn
Führen Sie die Intelligenz Ihrer eigenen Python-Bibliothek mit VScode aus.
Löse dein eigenes Labyrinth mit Q-Lernen
[Einführung in Style GAN] Einzigartiges Lernen von Animation mit Ihrer eigenen Maschine ♬
Trainiere UGATIT mit deinem eigenen Datensatz
Löse dein eigenes Labyrinth mit DQN
Berechnen Sie die AUC mit groupBy von PySpark DataFrame (definieren Sie die Aggregatfunktion mit pandas_udf).
Ihr eigener Twitter-Client mit Django
[Stärkung des Lernens] DQN mit Ihrer eigenen Bibliothek
Erstellen Sie mit Twisted Ihren eigenen DNS-Server
Erstellen Sie mit SQLAlchemy Ihren eigenen zusammengesetzten Wert
So importieren Sie Ihr eigenes Modul mit jupyter
Veröffentlichen Sie Ihre eigene Python-Bibliothek auf Homebrew
Holen Sie sich viele Ihrer Tweets mit Tweepy
Ich habe versucht, Runenfiguren mit Scikit-Learn handschriftlich zu erkennen
Versuchen Sie, Ihr eigenes AWS-SDK mit bash zu erstellen
Vergleichen Sie die Implementierungsbeispiele für scikit-learn und pyclustering k-means
So definieren Sie Ihr eigenes Ziel in Sage
Erstellen Sie schnell Ihr eigenes Modul mit setuptools (Python)
Prognostizieren Sie die zweite Runde des Sommers 2016 mit scikit-learn
Trainieren Sie Stanford NER Tagger mit Ihren eigenen Daten
Erstellen Sie ein Rad Ihres eigenen OpenCV-Moduls
Erstelle deinen eigenen Musik-Player mit Bottle0.13 + jPlayer2.5!
Schritte zum Installieren Ihrer eigenen Bibliothek mit pip