给定一个旨在用于后续无监督聚类分析的二元数据集(来自是/否问卷回答),具有显着的多重共线性和总共 31 个特征,约 50,000 个观察(受试者),降低输入的维数似乎是明智的执行聚类分析之前的数据。我尝试为此使用自动编码器,但令人惊讶的是,集群(通过 k-medoids 派生,由于基础数据的标称性质以及与异常值/噪声相关的稳定性比例如 k-means 更高的稳定性而选择)实际上是使用 MCA 时更加明显和清晰,在 k = 5 时具有明显的最大 Silhouette 系数。
考虑到在我尝试自动编码器方法之前使用了具有前 5 个 PC 的 MCA(仅解释约 75% 的方差,通过碎石图选择),令我惊讶的是,自动编码器在提取有意义的特征方面做得更差相同的瓶颈维度。 当前自动编码器的问题,似乎是用于聚类的瓶颈层中的数据被扭曲了......
下面是我用来构建自动编码器的代码。会不会是超参数关了,或者整体架构的一些细节?随机搜索特定数量的层数、学习率、批量大小、层中的维度等没有产生任何实质性的结果。训练和验证数据集之间的损失相似,并且在大约 40 个时期后稳定在 0.15 左右。
我还尝试确定使用此类数据的研究,但没有发现任何有用的东西。
import numpy as np
import tensorflow as tf
from tensorflow.keras.layers import Input, Dense
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
import matplotlib.pyplot as plt
input_dim = 31
layer_1_dim = 18
layer_2_dim = 10
bottleneck_dim = 5
learning_rate = 0.001
epochs = 100
batch_size = 300
# split data into training and validation
training_n = int(data.shape[0] * 0.8)
train_data = data[:training_n, :]
val_data = data[training_n:, :]
# define autoencoder initializer
initializer = tf.keras.initializers.GlorotUniform()
# autoencoder layers
input_layer = Input(shape=(input_dim,))
layer = Dense(layer_1_dim, activation='relu')(input_layer)
layer = Dense(layer_2_dim, activation='relu', kernel_initializer=initializer)(layer)
layer = Dense(bottleneck_dim, activation='relu', kernel_initializer=initializer, name="bottleneck-output")(layer)
layer = Dense(layer_2_dim, activation='relu', kernel_initializer=initializer)(layer)
layer = Dense(layer_1_dim, activation='relu', kernel_initializer=initializer)(layer)
output_layer = Dense(input_dim, activation='sigmoid', kernel_initializer=initializer)(layer)
# define and compile autoencoder model
autoencoder = Model(inputs=input_layer, outputs=output_layer)
optimizer = Adam(learning_rate=learning_rate)
autoencoder.compile(optimizer=optimizer, loss='binary_crossentropy')
# train the autoencoder model
history = autoencoder.fit(train_data, train_data, epochs=epochs, batch_size=batch_size, validation_data=(val_data, val_data))
# get bottleneck output
bottleneck_autoencoder = Model(inputs=autoencoder.input, outputs=autoencoder.get_layer('bottleneck-output').output)
bottleneck_output = bottleneck_autoencoder.predict(data)
# plot loss in traning and validation set
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.title('Autoencoder loss (binary cross-entropy)')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend(['Train', 'Validation'], loc='upper right')
plt.savefig('output/embedding.png')
如果您想要数据集的更好的低维表示,请使用 VAE 而不是常规自动编码器,它可以在 keras 中轻松完成(参见 https://keras.io/examples/generative/vae/)
class Sampling(layers.Layer):
"""Uses (z_mean, z_log_var) to sample z, the vector encoding a digit."""
def call(self, inputs):
z_mean, z_log_var = inputs
batch = tf.shape(z_mean)[0]
dim = tf.shape(z_mean)[1]
epsilon = tf.keras.backend.random_normal(shape=(batch, dim))
return z_mean + tf.exp(0.5 * z_log_var) * epsilon
latent_dim = 2
encoder_inputs = keras.Input(shape=(28, 28, 1))
x = layers.Conv2D(32, 3, activation="relu", strides=2, padding="same")(encoder_inputs)
x = layers.Conv2D(64, 3, activation="relu", strides=2, padding="same")(x)
x = layers.Flatten()(x)
x = layers.Dense(16, activation="relu")(x)
z_mean = layers.Dense(latent_dim, name="z_mean")(x)
z_log_var = layers.Dense(latent_dim, name="z_log_var")(x)
z = Sampling()([z_mean, z_log_var])
encoder = keras.Model(encoder_inputs, [z_mean, z_log_var, z], name="encoder")
encoder.summary()
由于这里的主要问题是多重共线性,您可以尝试使用考虑数据中非线性关系的降维方法。一个常见的例子是kernelPCA 然后你可以探索不同的核函数,我通常只用线性核就得到了有趣的结果。