有关如何使用特征提取技术减少数据集维度的端到端指南

介绍

如今,使用具有数百个(甚至数千个)特征的数据集变得非常普遍。如果要素的数量变得与存储在数据集中的观测值的数量相似(甚至更大!),则很可能导致机器学习模型过度拟合。为了避免此类问题,有必要应用正则化或降维技术(特征提取)。在机器学习中,数据集的维数等于用来表示数据集的变量数。

使用正则化无疑可以帮助降低过度拟合的风险,但是使用特征提取技术也可以带来其他类型的优势,例如:

  • 准确性提高。
  • 减少过度拟合的风险。
  • 加快训练速度。
  • 改进的数据可视化。
  • 增加模型的可解释性。

特征提取旨在通过从现有特征中创建新特征(然后丢弃原始特征)来减少数据集中的特征数量。然后,这些新的简化功能集应该能够汇总原始功能集中包含的大多数信息。这样,可以从原始集合的组合中创建原始特征的摘要版本。

减少数据集中特征数量的另一种常用技术是特征选择。特征选择和特征提取之间的区别在于,特征选择的目的是对数据集中现有特征的重要性进行排名,并丢弃次要的特征(不创建新特征)。

在本文中,将引导如何使用Kaggle蘑菇分类数据集作为示例来应用特征提取技术。目标是通过查看给定的特征来尝试预测蘑菇是否有毒。这篇文章中使用的所有代码都可以在Kaggle和GitHub帐户上找到。

https://www.kaggle.com/uciml/mushroom-classification

https://www.kaggle.com/pierpaolo28/feature-extraction?scriptVersionId=21698205

https://github.com/pierpaolo28/Artificial-Intelligence-Projects/blob/master/Features%20Analysis/feature-extraction.ipynb

首先,需要导入所有必需的库。

import timeimport numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom matplotlib.pyplot import figureimport seaborn as snsfrom sklearn import preprocessingfrom sklearn.preprocessing import LabelEncoderfrom sklearn.preprocessing import StandardScalerfrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import classification_report,confusion_matrixfrom sklearn.ensemble import RandomForestClassifier

下图显示了本示例中将使用的数据集。

图1:蘑菇分类数据集

在将这些数据输入到机器学习模型之前,决定将数据划分为特征(X)和标签(Y),然后对所有分类变量进行一次热编码。

X = df.drop(['class'], axis = 1)Y = df['class']X = pd.get_dummies(X, prefix_sep='_')Y = LabelEncoder().fit_transform(Y)X = StandardScaler().fit_transform(X)

后来,决定创建一个函数(forest_test)将输入数据分为训练集和测试集,然后训练和测试随机森林分类器。

def forest_test(X, Y):    X_Train, X_Test, Y_Train, Y_Test = train_test_split(X, Y,                                                        test_size = 0.30,                                                        random_state = 101)    start = time.process_time()    trainedforest = RandomForestClassifier(n_estimators=700).fit(X_Train,Y_Train)    print(time.process_time() - start)    predictionforest = trainedforest.predict(X_Test)    print(confusion_matrix(Y_Test,predictionforest))    print(classification_report(Y_Test,predictionforest))

现在,可以使用整个数据集使用此函数,然后在使用简化版本而不是整个数据集时相继使用它来比较这些结果。

forest_test(X, Y)

如下所示,使用所有功能训练随机森林分类器可在约2.2s的训练时间内获得100%的准确性。在以下每个示例中,每个模型的训练时间都将打印在每个摘要的第一行,以供您参考。

2.2676709799999992[[1274    0] [   0 1164]]              precision    recall  f1-score   support            0       1.00      1.00      1.00      1274           1       1.00      1.00      1.00      1164     accuracy                           1.00      2438   macro avg       1.00      1.00      1.00      2438weighted avg       1.00      1.00      1.00      2438

特征提取

主成分分析(PCA)

PCA是最常用的线性降维技术之一。使用PCA时,将原始数据作为输入,并尝试找到可以最好地总结原始数据分布的输入特征的组合,从而减小其原始尺寸。PCA可以通过查看方对距离来最大化方差并最小化重构误差来实现此目的。在PCA中,原始数据被投影到一组正交轴中,并且每个轴都按重要性顺序排序。

PCA是一种无监督的学习算法,因此它并不关心数据标签,而只关心变化。在某些情况下,这可能导致数据分类错误。

在此示例中,将首先在整个数据集中执行PCA,以将数据缩小为二维,然后构造一个具有新功能及其各自标签的数据框。

from sklearn.decomposition import PCA pca = PCA(n_components=2)X_pca = pca.fit_transform(X)PCA_df = pd.DataFrame(data = X_pca, columns = ['PC1', 'PC2'])PCA_df = pd.concat([PCA_df, df['class']], axis = 1)PCA_df['class'] = LabelEncoder().fit_transform(PCA_df['class'])PCA_df.head()

图2:PCA数据集

使用新创建的数据框,现在可以在2D散点图中绘制数据分布。

figure(num=None, figsize=(8, 8), dpi=80, facecolor='w', edgecolor='k') classes = [1, 0]colors = ['r', 'b']for clas, color in zip(classes, colors):    plt.scatter(PCA_df.loc[PCA_df['class'] == clas, 'PC1'],                PCA_df.loc[PCA_df['class'] == clas, 'PC2'],                c = color)    plt.xlabel('Principal Component 1', fontsize = 12)plt.ylabel('Principal Component 2', fontsize = 12)plt.title('2D PCA', fontsize = 15)plt.legend(['Poisonous', 'Edible'])plt.grid()

图3:2D PCA可视化

现在,可以重复相同的过程,而是保留3个尺寸并使用Plotly创建动画(可以与下面的动画进行交互!)。

使用PCA时,还可以使用explicit_variance_ratio_Scikit-learn函数来探索保留了多少原始数据差异。一旦计算出方差比,就可以继续创建精美的可视化图。

使用由PCA构造的3个要素集(而不是整个数据集)再次运行随机森林分类器,可以达到98%的分类精度,而仅使用2个要素即可达到95%的精度。

pca = PCA(n_components=3,svd_solver='full')X_pca = pca.fit_transform(X)print(pca.explained_variance_) forest_test(X_pca, Y)
[10.31484926  9.42671062  8.35720548]2.769664902999999[[1261   13] [  41 1123]]              precision    recall  f1-score   support            0       0.97      0.99      0.98      1274           1       0.99      0.96      0.98      1164     accuracy                           0.98      2438   macro avg       0.98      0.98      0.98      2438weighted avg       0.98      0.98      0.98      2438

此外,使用二维数据集,现在还可以可视化随机森林使用的决策边界,以便对每个不同的数据点进行分类。

from itertools import product X_Reduced, X_Test_Reduced, Y_Reduced, Y_Test_Reduced = train_test_split(X_pca, Y,                                                                        test_size = 0.30,                                                                        random_state = 101)trainedforest = RandomForestClassifier(n_estimators=700).fit(X_Reduced,Y_Reduced) x_min, x_max = X_Reduced[:, 0].min() - 1, X_Reduced[:, 0].max() + 1y_min, y_max = X_Reduced[:, 1].min() - 1, X_Reduced[:, 1].max() + 1xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1))Z = trainedforest.predict(np.c_[xx.ravel(), yy.ravel()])Z = Z.reshape(xx.shape)plt.contourf(xx, yy, Z,cmap=plt.cm.coolwarm, alpha=0.4)plt.scatter(X_Reduced[:, 0], X_Reduced[:, 1], c=Y_Reduced, s=20, edgecolor='k')plt.xlabel('Principal Component 1', fontsize = 12)plt.ylabel('Principal Component 2', fontsize = 12)plt.title('Random Forest', fontsize = 15)plt.show()

图4:PCA随机森林决策边界

独立成分分析(ICA)

ICA是一种线性降维方法,将独立成分的混合作为输入数据,旨在正确识别每个成分(删除所有不必要的噪声)。如果两个输入特征的线性和非线性相关性都等于零[1],则可以认为它们是独立的。

独立成分分析通常在医学应用中使用,例如EEG和fMRI分析,以将有用信号与无用信号分开。

作为ICA应用程序的一个简单示例,考虑一个音频注册,其中有两个不同的人在说话。例如,使用ICA,可以尝试识别注册中的两个不同的独立组件(两个不同的人)。这样,可以使我们的无监督学习算法在对话中的不同说话者之间识别。

使用ICA,现在可以再次将数据集简化为三个特征,使用随机森林分类器测试其准确性并绘制结果。

from sklearn.decomposition import FastICA ica = FastICA(n_components=3)X_ica = ica.fit_transform(X) forest_test(X_ica, Y)
2.8933812039999793[[1263   11] [  44 1120]]              precision    recall  f1-score   support            0       0.97      0.99      0.98      1274           1       0.99      0.96      0.98      1164     accuracy                           0.98      2438   macro avg       0.98      0.98      0.98      2438weighted avg       0.98      0.98      0.98      2438

从下面的动画中,可以看到,即使PCA和ICA得出相同的精度结果,它们仍可以构造两个不同的3维空间分布。

线性判别分析(LDA)

LDA是监督学习降维技术和机器学习分类器。

LDA的目的是最大程度地增加每个类的均值之间的距离,并最大程度地减少类本身的散布。因此,LDA在班级内部和班级之间用作度量。这是一个不错的选择,因为在较低维度的空间中投影数据时,最大化每个类别的均值之间的距离会导致更好的分类结果(由于减少了不同类别之间的重叠)。

使用LDA时,假设输入数据遵循高斯分布(在这种情况下),因此将LDA应用于非高斯数据可能会导致较差的分类结果。

在此示例中,将运行LDA将数据集简化为一个特征,测试其准确性并绘制结果。

from sklearn.discriminant_analysis import LinearDiscriminantAnalysis lda = LinearDiscriminantAnalysis(n_components=1) # run an LDA and use it to transform the featuresX_lda = lda.fit(X, Y).transform(X)print('Original number of features:', X.shape[1])print('Reduced number of features:', X_lda.shape[1])
Original number of features: 117Reduced number of features: 1

由于数据分布严格遵循高斯分布,因此LDA的表现非常好,在这种情况下,使用随机森林分类器可以达到100%的准确性。

forest_test(X_lda, Y)
1.2756952610000099[[1274    0] [   0 1164]]              precision    recall  f1-score   support            0       1.00      1.00      1.00      1274           1       1.00      1.00      1.00      1164     accuracy                           1.00      2438   macro avg       1.00      1.00      1.00      2438weighted avg       1.00      1.00      1.00      2438

正如在本节开头提到的那样,LDA也可以用作分类器。因此,现在可以测试在这种情况下LDA分类器的性能。

X_Reduced, X_Test_Reduced, Y_Reduced, Y_Test_Reduced = train_test_split(X_lda, Y,                                                                        test_size = 0.30,                                                                        random_state = 101) start = time.process_time()lda = LinearDiscriminantAnalysis().fit(X_Reduced,Y_Reduced)print(time.process_time() - start)predictionlda = lda.predict(X_Test_Reduced)print(confusion_matrix(Y_Test_Reduced,predictionlda))print(classification_report(Y_Test_Reduced,predictionlda))
0.008464782999993758[[1274    0] [   2 1162]]              precision    recall  f1-score   support            0       1.00      1.00      1.00      1274           1       1.00      1.00      1.00      1164     accuracy                           1.00      2438   macro avg       1.00      1.00      1.00      2438weighted avg       1.00      1.00      1.00      2438

最后,现在可以形象地看到我们的两个类的分布看起来像创建一维数据的分布图。

图5:LDA类分离

局部线性嵌入(LLE)

到目前为止,已经考虑了PCA和LDA等方法,它们在不同特征之间存在线性关系的情况下确实能够很好地执行,现在将继续考虑如何处理非线性情况。

局部线性嵌入是基于流形学习的降维技术。歧管是D维尺寸的对象,它嵌入到更高维的空间中。流形学习的目的是使该对象在其原始D维度上可表示,而不是在不必要的更大空间中表示。

用于解释机器学习中的流形学习的一个典型示例是Swiss Roll流形(图6)。作为输入,获得了一些数据,该数据具有类似于一卷纸的分布(在3D空间中),然后可以对其展开,以便将数据缩小为二维空间。

流形学习算法的一些示例包括:Isomap,局部线性嵌入,修改的局部线性嵌入,Hessian特征映射等。

图6:流形学习[2]

现在,将在示例中逐步指导如何实现LLE。根据Scikit-learn文档[3]:

局部线性嵌入(LLE)寻求数据的低维投影,以保留局部邻域内的距离。可以将其视为一系列局部主成分分析,将其进行全局比较以找到最佳的非线性嵌入。

现在,可以在数据集上运行LLE,以将数据维数减少到3维,测试总体准确性并绘制结果。

from sklearn.manifold import LocallyLinearEmbedding embedding = LocallyLinearEmbedding(n_components=3)X_lle = embedding.fit_transform(X) forest_test(X_lle, Y)
2.578125[[1273    0] [1143   22]]              precision    recall  f1-score   support            0       0.53      1.00      0.69      1273           1       1.00      0.02      0.04      1165    micro avg       0.53      0.53      0.53      2438   macro avg       0.76      0.51      0.36      2438weighted avg       0.75      0.53      0.38      2438

t分布随机邻居嵌入(t-SNE)

t-SNE是非线性降维技术,通常用于可视化高维数据集。t-SNE的一些主要应用是自然语言处理(NLP),语音处理等…

t-SNE通过最小化由输入特征在原始高维空间中的成对概率相似性与其在缩减的低维空间中的等效特征构成的分布之间的差异来工作。然后t-SNE利用Kullback-Leiber(KL)散度来测量两个不同分布的不相似性。然后使用梯度下降将KL散度最小化。

使用t-SNE时,高维空间使用高斯分布建模,而低维空间则使用学生的t分布建模。这样做是为了避免由于转换成低维空间而导致的相邻点距离分布的不平衡。

现在,准备使用TSNE,并将数据集简化为3个要素。

from sklearn.manifold import TSNE start = time.process_time()tsne = TSNE(n_components=3, verbose=1, perplexity=40, n_iter=300)X_tsne = tsne.fit_transform(X)print(time.process_time() - start)
[t-SNE] Computing 121 nearest neighbors...[t-SNE] Indexed 8124 samples in 0.139s...[t-SNE] Computed neighbors for 8124 samples in 11.891s...[t-SNE] Computed conditional probabilities for sample 1000 / 8124[t-SNE] Computed conditional probabilities for sample 2000 / 8124[t-SNE] Computed conditional probabilities for sample 3000 / 8124[t-SNE] Computed conditional probabilities for sample 4000 / 8124[t-SNE] Computed conditional probabilities for sample 5000 / 8124[t-SNE] Computed conditional probabilities for sample 6000 / 8124[t-SNE] Computed conditional probabilities for sample 7000 / 8124[t-SNE] Computed conditional probabilities for sample 8000 / 8124[t-SNE] Computed conditional probabilities for sample 8124 / 8124[t-SNE] Mean sigma: 2.658530[t-SNE] KL divergence after 250 iterations with early exaggeration: 65.601128[t-SNE] KL divergence after 300 iterations: 1.909915143.984375

通过可视化结果功能的分布,我们可以清楚地看到,即使在缩小的空间中进行了转换,我们的数据也是如何很好地分离的。

使用t-SNE缩减子集测试随机森林准确性,证实了现在类可以轻松分离了。

forest_test(X_tsne, Y)
2.6462027340000134[[1274    0] [   0 1164]]              precision    recall  f1-score   support            0       1.00      1.00      1.00      1274           1       1.00      1.00      1.00      1164     accuracy                           1.00      2438   macro avg       1.00      1.00      1.00      2438weighted avg       1.00      1.00      1.00      2438

自动编码器

自动编码器是一类机器学习算法,可以用作降维技术。自动编码器与其他降维技术之间的主要区别在于,自动编码器使用非线性变换将数据从高维度投影到低维度。

存在不同类型的自动编码器,例如:

  • 去噪自动编码器
  • 可变自动编码器
  • 卷积自动编码器
  • 稀疏自动编码器

在此示例中,将从构建基本的自动编码器开始(图7)。自动编码器的基本体系结构可以分为两个主要组件:

  • 编码器:获取输入数据并压缩,以消除所有可能的噪音和无用的信息。编码器阶段的输出通常称为瓶颈或潜在空间。
  • 解码器:将编码后的潜在空间作为输入,并尝试仅使用其压缩形式(编码后的潜在空间)重现原始的自动编码器输入。

如果所有输入要素彼此独立,则自动编码器将特别难以编码和解码以将输入数据输入低维空间。

图7:自动编码器架构[4]

可以使用Keras API在Python中实现自动编码器。在这种情况下,在编码层中指定要减少输入数据的要素数量(对于本例3)。从下面的代码片段可以看出,自动编码器将X(我们的输入功能)作为功能和标签(X,Y)。

对于此示例,决定将ReLu用作编码阶段的激活函数并将Softmax用作解码阶段。如果不使用非线性激活函数,那么自动编码器将尝试使用线性变换来减少输入数据(因此,得到的结果类似于使用PCA的结果)。

from keras.layers import Input, Densefrom keras.models import Model input_layer = Input(shape=(X.shape[1],))encoded = Dense(3, activation='relu')(input_layer)decoded = Dense(X.shape[1], activation='softmax')(encoded)autoencoder = Model(input_layer, decoded)autoencoder.compile(optimizer='adam', loss='binary_crossentropy') X1, X2, Y1, Y2 = train_test_split(X, X, test_size=0.3, random_state=101) autoencoder.fit(X1, Y1,                epochs=100,                batch_size=300,                shuffle=True,                verbose = 30,                validation_data=(X2, Y2)) encoder = Model(input_layer, encoded)X_ae = encoder.predict(X)

现在,可以重复与前面的示例类似的工作流程,这次使用简单的自动编码器作为特征提取技术。

forest_test(X_ae, Y)
1.734375[[1238   36] [  67 1097]]              precision    recall  f1-score   support            0       0.95      0.97      0.96      1274           1       0.97      0.94      0.96      1164    micro avg       0.96      0.96      0.96      2438   macro avg       0.96      0.96      0.96      2438weighted avg       0.96      0.96      0.96      2438

参考书目

[1]通过独立成分分析(ICA),在纸空间中深入研究降维。访问以下网址:

https://blog.paperspace.com/dimension-reduction-with-independent-components-analysis/

[2]具有流形雕刻的迭代非线性降维,ResearchGate。访问网址:

https://www.researchgate.net/publication/220270207_Iterative_Non-linear_Dimensionality_Reduction_with_Manifold_Sculpting

[3]流形学习,Scikit学习文档。可通过以下网址访问:

https://scikit-learn.org/stable/modules/manifold.html#targetText=Manifold%20learning%20is%20an%20approach,sets%20is%20only%20artificially%20high

[4]可变自动编码器很漂亮,Comp Three Inc.史蒂文·弗洛雷斯(Steven Flores)。访问网址:http://www.compthree.com/blog/autoencoder/

本文分享自微信公众号 - 相约机器人(xiangyuejiqiren)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-10-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏折腾折腾再折腾

遗传算法程序设计

在单纯的遗传算法中,并不是总是收敛的,即使在单峰或者单调也是如此。这是因为种群的进化能力消失种群早熟。为避免这种现象,参数设计一般遵循以下原则:

8520
来自专栏思考是一种快乐

人工智能算法通俗讲解系列(四):xgboost

不要被这个名字吓唬到,其实它的基本原理并不复杂。要理解xgboost,需要首先理解决策树。还没有接触过决策树的同学可以看一下《人工智能算法通俗讲解系列(三):决...

12650
来自专栏折腾折腾再折腾

机器学习篇(一)

机器学习的常用数据:csv文件,mysql等数据库的读取速度是不够快的。同时格式也不符合。

12040
来自专栏折腾折腾再折腾

机器学习篇(四)

在相亲过程中可能年龄这个特征比较重要,但是在实际其他应用中,我们把哪个特征放在第一位?

5630
来自专栏思考是一种快乐

人工智能算法通俗讲解系列(三):决策树

这里的案例跟K临近法那一讲里的案例差不多,有一点变化。我把案例简述一下:某公司开发了一款游戏,并且得到了一些用户的数据。如下所示:

9910
来自专栏折腾折腾再折腾

数学建模篇——遗传算法

智能算法是智能技术领域的一个分支。智能算法出现的原因是,人们在知识新陈代谢速度快和知识繁杂的社会里,需要用高效的数据挖掘工具从各类数据中提取有用的信息和知识,以...

14020
来自专栏思考是一种快乐

xgboost小试

demo/binary_classification下是一个根据对蘑菇特征对其是否有毒进行判别对一个demo。数据源来自https://archive.ics....

11220
来自专栏折腾折腾再折腾

机器学习篇(三)

简单描述:在预测目标值的时候选择和自己相似的目标值。比如,有五个人分在在武汉的五个区域,小明不知道自己在什么区域,他计算自己和其他4个人的距离,谁离自己最近,他...

8550
来自专栏折腾折腾再折腾

机器学习实例篇

数据来源:https://www.kaggle.com/c/facebook-v-predicting-check-ins

9640
来自专栏Python数据科学

手把手教你入门和实践特征工程 的全方位万字笔记,附代码下载

(注:本节用到了两个数据集,分别是Salary_Ranges_by_Job_Classification 和 GlobalLandTemperaturesByC...

7410

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励