神经网络可以像经典主成分分析一样执行降维吗?

介绍

主成分分析(PCA)是最流行的降维算法之一。PCA的工作原理是找出在数据中相互正交的方差很大的轴。在ᵗʰ轴被称为ᵗʰ主成分(PC)。执行PCA的步骤是:

  • 标准化数据。
  • 从协方差矩阵或相关矩阵中获取特征向量和特征值,或执行奇异值分解。

我们将通过实现sklearn来执行PCA:它使用scipy(scipy.linalg)中的奇异值分解(SVD )。SVD是2D矩阵A的分解。它写为:

S是一维数组瓦特ħ ICH中包含的奇异值; üV 2 H是酉(ûû = UU ᵗ= I)。大多数PCA实现都执行SVD,以提高计算效率。

另一方面,自动编码器(AE)是一种特殊的神经网络,经过训练可将其输入复制到其输出。首先,它将输入映射到一个尺寸减小的潜在空间,然后将潜在表示编码回输出。AE学习通过减少重构误差来压缩数据。

稍后我们将看到如何实现和比较PCA和自动编码器的结果。

我们将使用sklearn的make_classification生成数据,这还将为我们提供一些标签。我们将使用这些标签在我们的方法之间的聚类效率之间进行比较。
将分为三个部分。

在第一个中,我们将实现一个简单的不完全线性自动编码器:即,具有单层的自动编码器,其尺寸小于其输入。第二部分将介绍堆叠线性自动编码器。
在第三部分中,我们将尝试修改激活功能以解决更多的复杂性。

将结果与PCA进行图形比较,最后,我们将尝试使用带有交叉验证的简单随机森林分类算法来预测类别。

资料准备

在下面的代码中,您具有所有用于设置数据的代码:首先,我们导入必要的库,然后使用scikit-learn的“ make分类”方法生成数据。在50个功能中,我们将指定仅15个具有信息性,并且将约束我们的约简算法以仅选择5个潜在变量。

有了数据后,我们将其分为训练验证测试。我们将使用神经网络(NN)的验证数据,而测试集将最终用于检查某些分类性能。

最后,我们将数据标准化:请注意,我们将缩放器安装在训练数据集上,然后转换成验证和测试集。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn import datasets
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from tensorflow import keras

# generate data
X, y = datasets.make_classification(n_samples=10000, n_features=50, n_redundant=10, n_informative=10,
                           random_state=1, n_clusters_per_class=2,n_classes=3, class_sep=2)

# divide data in Train - Validation - Test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
X_tr, X_valid, y_tr, y_valid = train_test_split(X_train, y_train, test_size=0.2, random_state=42) 

# Standardize Data
sc = StandardScaler()
X_tr_std = sc.fit_transform(X_tr)
X_valid_std = sc.transform(X_valid)
X_test_std = sc.transform(X_test)

左侧的数据相关热图显示了一些相关特征,但大多数没有。在右侧,我们绘制了特征的方差,从中可以推断出只有10-15个变量对我们的数据集有用。

不完整的线性自动编码器

在本节中,如果执行以下操作,我们将看到数据发生了什么变化:

  1. 将数据压缩到5个潜在维度
  2. 使用线性激活功能
  3. 使用“ MSE”作为损耗指标

让我们设置这个AE

encoder = keras.models.Sequential([
    keras.layers.Dense(5, input_shape=[50]),
])

decoder = keras.models.Sequential([
    keras.layers.Dense(50, input_shape=[5]),
])

autoencoder = keras.models.Sequential([encoder, decoder])
autoencoder.compile(loss='mse', optimizer = keras.optimizers.SGD(lr=0.1))

history = autoencoder.fit(X_tr_std,X_tr_std, epochs=100,validation_data=(X_valid_std,X_valid_std),
                         callbacks=[keras.callbacks.EarlyStopping(patience=10)])

codings = encoder.predict(X_tr_std)

首先,我们定义编码器模型:请注意,将输入形状硬编码为数据集的维数,并且将潜在空间固定为5个维。解码器模型是对称的:在这种情况下,我们指定输入形状为5(潜在尺寸),其输出将为原始空间尺寸。最终模型“自动编码器”将两者结合在一起。

然后,我们使用随机梯度下降SGD优化器以均方误差度量编译自动编码器,固定学习率为0.1

在拟合步骤中,我们仅指定验证数据,如果验证损失没有改善,则使用提早停止的回调来停止训练。
最后,我们只能使用模型的第一部分“ encoder.predict(X_tr_std) ”来计算编码。该模型非常简单:

从学习曲线可以看出,拟合在60个周期后停止,损失约为0.7。结果显示的前两个编码如下所示:

PCA实施:使用sklearn可以轻松实现。

from sklearn.decomposition import PCA

pca = PCA(n_components=5,svd_solver='auto')
scores = pca.fit_transform(X_tr_std) # u

下面,我们为前三个组件绘制了PCA(左图)和Encoder(右图)的聚类训练数据。

从上面的图中可以看出,两种算法都以相似的方式执行了降维。推断哪个表现更好并不容易。让我们看看这些编码的一些属性。

下面我们绘制了PCA(上)和Autoencoder(下)组件的标准偏差。

从这些图表中,我们可以看到,对于PCA而言,我们具有主成分的标准偏差,正如预期的那样,每个主成分的标准偏差都会减小。另一方面,所有编码的标准偏差几乎相等。

下面,我们绘制了PCA(上)和Encoder(下)的组件的相关图。

从该图中还可以看到,尽管PC彼此正交:它们没有相关性,但对于编码而言却并非如此。它们之间显示出一些相关性。实际上,我们的神经网络模型并未对此行为施加任何限制。网络找到了在潜在空间中映射原始输入的最佳方法。

从原始空间到两个不同的潜在空间的分类性能如何?有什么区别吗?
我们可以使用交叉验证使用RandomForestClassifier并查看结果。这是代码:

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score

rfc = RandomForestClassifier(n_estimators=200, max_depth=5)

labels = ['Original', 'PCA','AE']
scores = pd.DataFrame(columns=labels)
scores['PCA'] = cross_val_score(rfc, scores_train, y_tr, cv=5)
scores['AE'] = cross_val_score(rfc, codings_train, y_tr, cv=5)
scores['Original'] = cross_val_score(rfc, X_tr_std, y_tr, cv=5)

sns.barplot(x='dataset', y='score', data = scores.melt(value_name='score', var_name='dataset'))
plt.ylim(0.9,1)

从上面的小节中我们可以看到,除去5以外的所有元素,都降低了预期的预测精度。尽管如此,PCA和AE数据还原的性能还是相当的,但AE的性能比PCA差一些。

现在,我们将尝试了解更复杂的AE堆叠是否会带来更好的结果。

线性堆叠式编解码器

在这里,我们像以前一样实现了编解码器网络结构,但是在这种情况下,我们将堆叠更多的隐藏层。这应该使网络具有更大的灵活性来学习不同的,最有用的功能。

编码器层为:50(输入)— 20–15–5。损失与以前的不良事件相当。解码器只是对称的。组件显示在下面。

在分类性能方面的结果是:

显然,堆叠隐藏层比简单AE具有更好的效果。但是,可以针对特定问题对底层的确切配置进行微调。

非线性堆叠式编解码器

非线性堆叠AE将很容易实现为堆叠AE,但具有激活功能。我们还通过SGD优化器引入了衰减常数,因此学习率将随着时间的推移而降低。我们选择“ selu”作为所有层的激活层。请注意,这里我们进一步增加了复杂性:针对特定问题,我们可以尝试找到最佳的隐藏层数,最佳的激活函数和每一层的形状。

nl_st_encoder = keras.models.Sequential([
    keras.layers.Dense(20, input_shape=[50], activation='relu'),
    keras.layers.Dense(15, activation='selu'),
    keras.layers.Dense(5, activation='selu'),
])

nl_st_decoder = keras.models.Sequential([
    keras.layers.Dense(15, input_shape=[5], activation='selu'),
    keras.layers.Dense(20, activation='selu'),
    keras.layers.Dense(50, activation='relu'),
])

nl_st_autoencoder = keras.models.Sequential([nl_st_encoder, nl_st_decoder])
nl_st_autoencoder.compile(loss='mse', optimizer = keras.optimizers.SGD(lr=1, decay=1e-4))
nl_st_autoencoder.summary()

history = nl_st_autoencoder.fit(X_tr_std,X_tr_std, epochs=500,validation_data=(X_valid_std,X_valid_std),
                         callbacks=[keras.callbacks.EarlyStopping(patience=10)],verbose=1)

nl_st_codings_train = nl_st_encoder.predict(X_tr_std)
nl_st_codings_test = nl_st_encoder.predict(X_test_std)

以下是前三个组件:

至于分类性能,允许网络学习非线性特征有助于提高整体性能,这似乎比PCA更好,但在误差范围内。

结论

我们使用sklearn的make_classification建立了一个玩具数据集,用于分类练习,具有50个功能。我们的目的是比较PCA和AutoEncoder神经网络,以查看降维是否具有可比性。

我们查看了得分/编码的属性,我们发现来自AE的编码具有一定的相关性(协变矩阵不像PCA中那样是对角线的),并且它们的标准偏差也相似。

从只有一层的简单线性不完全AE开始,我们看到,随着分类准确度的提高,复杂性的提高帮助模型达到了更好的性能。

最后,我们看到非线性模型仍然可以比其他两个模型(一层AE和堆叠式AE)更好,但是在该数据集中,其性能仍可与PCA媲美。

现在我们可以回答最初的问题:神经网络是否可以像经典成分分析一样执行降维?

答案是肯定的,它可以像PCA一样执行降维,从某种意义上说,网络将找到在潜在空间中编码原始矢量的最佳方法。但是不,潜在向量的属性是不同的,并且网络本身可能需要针对特定​任务进行调整,以便像我们对更多隐藏层所做的那样表现更好。

(0)

相关推荐