Я пытаюсь найти оптимальное количество кластеров в своих данных с помощью метода локтя и оценки силуэта при использовании KMeans. Хотя я тестирую эти методы с помощью уменьшения размерности.
Если я попробую PCA несколько раз, я каждый раз буду получать одни и те же графики для метода локтя и силуэта. Но если я попробую энкодер со структурой нейронной сети для той же цели, я каждый раз получаю разные графики. И, следовательно, у меня нет уверенности в использовании этого метода кодирования, поскольку он приводит к разным оптимальным числам кластеров.
Почему это происходит? Даже если я нормализую свои данные, результаты будут меняться.
Что я могу сделать, чтобы правильно использовать этот метод кодирования? Я знаю, что мог бы просто выбрать PCA для этого, но я хотел бы понять и посмотреть, не делаю ли я что-то не так.
Вот мой код, и вы можете запустить его несколько раз, чтобы понять, о чем я говорю. В качестве примера я использовал набор данных iris:
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans
from sklearn import datasets
from sklearn.metrics import silhouette_score, silhouette_samples
import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras import backend as K
iris = datasets.load_iris()
X = pd.DataFrame(iris.data)
def autoencoding(data):
n_input_layer = data.shape[1]
n_encoding_layer = 2
n_output_layer = n_input_layer
# AUTOENCODER
autoencoder = tf.keras.models.Sequential([
# ENCODER
Dense(n_input_layer, input_shape = (n_input_layer,), activation = 'relu'), # Input layer
# CENTRAL LAYER
Dense(n_encoding_layer, activation = 'relu', name = 'central_layer'),
# DECODER
Dense(n_output_layer, activation = 'relu') # Output layer
])
n_epochs = 2000
loss = tf.keras.losses.MeanSquaredError()
optimizer = tf.optimizers.Adam(learning_rate = 0.001, decay = 0.0001, clipvalue = 0.5)
loss_history = [] # save loss improvement
data = np.array(data, dtype=np.float)
for epoch in range(n_epochs):
with tf.GradientTape() as tape:
current_loss = loss(autoencoder(data), data)
gradients = tape.gradient(current_loss, autoencoder.trainable_variables) # get the gradient of the loss function
optimizer.apply_gradients(zip(gradients, autoencoder.trainable_variables)) # update the weights
loss_history.append(current_loss.numpy()) # save current loss in its history
# show loss improvement every 200 epochs
if (epoch+1) % 200 == 0:
print(str(epoch+1) + '.\tLoss: ' + str(current_loss.numpy()))
print('\nEncoding complete')
return autoencoder
X_autoencoded = autoencoding(X)
# ENCODER EXTRACTION
def encoded(autoencoder, data):
# create a Keras function
extract_encoded_data = K.function(inputs = autoencoder.layers[0].input,
outputs = autoencoder.layers[1].output)
# extract encoded dataframe
encoded_dataframe = extract_encoded_data(data.values)
encoded_data = pd.DataFrame(encoded_dataframe)
return encoded_data
X_encoded = encoded(X_autoencoded, X)
# ELBOW METHOD AND SILHOUETTE SCORE
inertia =[]
sil =[]
for k in range(2,14):
kmeans_rand = KMeans(n_clusters=k, init='k-means++', random_state=42)
kmeans_rand.fit(X_encoded)
y_pred = kmeans_rand.predict(X_encoded)
inertia.append(kmeans_rand.inertia_)
sil.append((k, silhouette_score(X_encoded, y_pred)))
sil_samples = silhouette_samples(X_encoded, y_pred)
fig, ax = plt.subplots(1, 2, figsize=(12,4))
ax[0].plot(range(2,14), inertia)
ax[0].set_title('Elbow Method')
ax[0].set_xlabel('Number of clusters')
ax[0].set_ylabel('Inertia')
x_sil = [x[0] for x in sil]
y_sil = [x[1] for x in sil]
ax[1].plot(x_sil, y_sil)
ax[1].set_xlabel('Number of Clusters')
ax[1].set_ylabel('Silhouetter Score')
ax[1].set_title('Silhouetter Score Curve')