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.
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.
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 ...
Es scheint mehrere Möglichkeiten zu geben.
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üß ...
Die euklidische Entfernung, die k-means anruft, ist this.
Das Verhalten kann grob unterteilt werden.
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.
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 ...)
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