个性化阅读
专注于IT技术分析

Python中的主成分分析(PCA)

本文概述

介绍

主成分分析(PCA)是一种线性降维技术, 可通过将其投影到低维子空间中来从高维空间中提取信息。它试图保留数据变化较大的基本部分, 并删除变化较小的非必要部分。

维度不过是代表数据的要素。例如, A 28 X 28图像具有784个像素(像素), 这些像素或像素是一起表示该图像的尺寸或特征。

关于PCA的重要一件事是, 它是一种无监督的降维技术, 你可以基于相似的数据点之间的特征相关性对它们进行聚类, 而无需任何监督(或标签), 并且你将学习如何使用Python实际实现这一点。在本教程的后续部分中!

根据Wikipedia的介绍, PCA是一种统计过程, 它使用正交变换将一组可能相关的变量(每个实体具有不同的数值)的观测值转换为一组线性不相关的变量值(称为主成分)。

注意:特征, 尺寸和变量均指同一事物。你会发现它们可以互换使用。

Python中的主成分分析(PCA)1

但是你可以在哪里申请PCA?

  • 数据可视化:处理任何与数据相关的问题时, 当今世界面临的挑战是庞大的数据量以及定义该数据的变量/特征。要解决以数据为关键的问题, 你需要进行广泛的数据探索, 例如找出变量之间的相关性或了解一些变量的分布。考虑到数据分布的变量或维度很多, 可视化可能是一个挑战, 几乎是不可能的。

    因此, PCA可以为你做到这一点, 因为它会将数据投影到较低的维度, 从而使你可以用肉眼可视化2D或3D空间中的数据。

  • 加快机器学习(ML)算法的速度:由于PCA的主要思想是降维, 因此考虑到数据具有很多特征, 并且ML算法的学习速度太慢, 你可以利用它来加快机器学习算法的训练和测试时间。

在抽象级别上, 你将获得具有许多特征的数据集, 并通过从原始特征中选择一些主要成分来简化该数据集。

What is a Principal Component?

主要组件是PCA的关键。它们代表了数据的底层。用外行术语来说, 当数据从较高的空间投影到较低的维度(假设为三个维度)时, 这三个维度不过是捕获(或保存)数据大部分差异(信息)的三个主要成分。 。

主成分既有方向又有大小。方向代表数据在哪个主轴上散布最多或变化最大, 幅度表示当投影到该轴上时主分量捕获数据的变化量。主成分是一条直线, 第一个主成分在数据中具有最大的方差。每个后续主成分与最后一个正交, 且方差较小。这样, 给定y个样本上的x个相关变量, 就可以在相同y个样本上获得u个不相关的主成分。

你从原始要素获得不相关的主成分的原因是, 相关要素构成了相同的主成分, 从而将原始数据要素简化为不相关的主成分。每个代表具有不同变化量的一组不同的相关特征。

每个主成分代表从数据中捕获的总变化的百分比。

在今天的教程中, 你将主要在以下两个用例上应用PCA:

  • 数据可视化
  • 超速ML算法

为了完成上述两项任务, 你将使用两个著名的乳腺癌(数字)和CIFAR-10(图像)数据集。

了解数据

在继续加载数据之前, 最好先了解并查看将要使用的数据!

乳腺癌

乳腺癌数据集是由两个类别组成的实值多元数据, 其中每个类别表示患者是否患有乳腺癌。这两个类别是:恶性和良性。

恶性分类有212个样本, 而良性分类有357个样本。

它具有30个在所有类别中共享的特征:半径, 纹理, 周长, 面积, 平滑度, 分形尺寸等。

你可以从此处下载乳腺癌数据集, 或者一种简单的方法是在sklearn库的帮助下加载它。

CIFAR-10

CIFAR-10(加拿大高级科学研究所)数据集由60000张图像组成, 每张32x32x3彩色图像具有十个类别, 每个类别6000个图像。

数据集由50000张训练图像和10000张测试图像组成。

数据集中的类别是飞机, 汽车, 鸟类, 猫, 鹿, 狗, 青蛙, 马, 船, 卡车。

你可以从此处下载CIFAR数据集, 也可以在像Keras这样的深度学习库的帮助下即时加载。

数据探索

现在, 你将加载和分析乳腺癌和CIFAR-10数据集。现在, 你对两个数据集的维数有了一个想法。

因此, 让我们快速浏览这两个数据集。

乳腺癌数据探索

让我们首先探讨乳腺癌数据集。

你将使用sklearn的模块数据集并从中导入乳腺癌数据集。

from sklearn.datasets import load_breast_cancer

load_breast_cancer将为你提供标签和数据。要获取数据, 你将调用.data并获取标签.target。

数据包含569个具有30个特征的样本, 每个样本都有与之相关的标签。此数据集中有两个标签。

breast = load_breast_cancer()
breast_data = breast.data

让我们检查数据的形状。

breast_data.shape
(569, 30)

即使在本教程中, 你不需要标签, 但为了更好地理解, 让我们加载标签并检查形状。

breast_labels = breast.target
breast_labels.shape
(569, )

现在, 你将导入numpy, 因为你将重新调整breast_labels的形状以将其与breast_data连接起来, 以便最终创建一个同时包含数据和标签的DataFrame。

import numpy as np
labels = np.reshape(breast_labels, (569, 1))

重塑标签形状后, 你将沿着第二个轴连接数据和标签, 这意味着数组的最终形状将为569 x 31。

final_breast_data = np.concatenate([breast_data, labels], axis=1)
final_breast_data.shape
(569, 31)

现在, 你将导入熊猫以创建最终数据的DataFrame, 以表格形式表示数据。

import pandas as pd
breast_dataset = pd.DataFrame(final_breast_data)

让我们快速打印乳腺癌数据集中的特征!

features = breast.feature_names
features
array(['mean radius', 'mean texture', 'mean perimeter', 'mean area', 'mean smoothness', 'mean compactness', 'mean concavity', 'mean concave points', 'mean symmetry', 'mean fractal dimension', 'radius error', 'texture error', 'perimeter error', 'area error', 'smoothness error', 'compactness error', 'concavity error', 'concave points error', 'symmetry error', 'fractal dimension error', 'worst radius', 'worst texture', 'worst perimeter', 'worst area', 'worst smoothness', 'worst compactness', 'worst concavity', 'worst concave points', 'worst symmetry', 'worst fractal dimension'], dtype='<U23')

如果你在特征数组中注明, 则标签字段丢失。因此, 你将必须手动将其添加到features数组中, 因为你要将该数组等同于breast_dataset数据框的列名。

features_labels = np.append(features, 'label')

大!现在, 你将列名称嵌入到breast_dataset数据框中。

breast_dataset.columns = features_labels

让我们打印数据框的前几行。

breast_dataset.head()
平均半径 平均质地 平均周长 平均面积 平均平滑度 平均紧密度 平均凹度 平均凹点 平均对称 平均分形维数 最差的质地 最差的周长 最坏的地方 最差的光滑度 最差的紧密度 最差的凹度 最坏的凹点 最差的对称性 最差分形维数 标签
0 17.99 10.38 122.80 1001.0 0.11840 0.27760 0.3001 0.14710 0.2419 0.07871 17.33 184.60 2019.0 0.1622 0.6656 0.7119 0.2654 0.4601 0.11890 0.0
1 20.57 17.77 132.90 1326.0 0.08474 0.07864 0.0869 0.07017 0.1812 0.05667 23.41 158.80 1956.0 0.1238 0.1866 0.2416 0.1860 0.2750 0.08902 0.0
2 19.69 21.25 130.00 1203.0 0.10960 0.15990 0.1974 0.12790 0.2069 0.05999 25.53 152.50 1709.0 0.1444 0.4245 0.4504 0.2430 0.3613 0.08758 0.0
3 11.42 20.38 77.58 386.1 0.14250 0.28390 0.2414 0.10520 0.2597 0.09744 26.50 98.87 567.7 0.2098 0.8663 0.6869 0.2575 0.6638 0.17300 0.0
4 20.29 14.34 135.10 1297.0 0.10030 0.13280 0.1980 0.10430 0.1809 0.05883 16.67 152.20 1575.0 0.1374 0.2050 0.4000 0.1625 0.2364 0.07678 0.0

5行×31列

由于原始标签为0, 1格式, 因此你将使用.replace函数将标签更改为良性和恶性。你将使用inplace = True, 它将修改数据帧breast_dataset。

breast_dataset['label'].replace(0, 'Benign', inplace=True)
breast_dataset['label'].replace(1, 'Malignant', inplace=True)

让我们打印breast_dataset的最后几行。

breast_dataset.tail()
平均半径 平均质地 平均周长 平均面积 平均平滑度 平均紧密度 平均凹度 平均凹点 平均对称 平均分形维数 最差的质地 最差的周长 最坏的地方 最差的光滑度 最差的紧密度 最差的凹度 最坏的凹点 最差的对称性 最差分形维数 标签
564 21.56 22.39 142.00 1479.0 0.11100 0.11590 0.24390 0.13890 0.1726 0.05623 26.40 166.10 2027.0 0.14100 0.21130 0.4107 0.2216 0.2060 0.07115 良性
565 20.13 28.25 131.20 1261.0 0.09780 0.10340 0.14400 0.09791 0.1752 0.05533 38.25 155.00 1731.0 0.11660 0.19220 0.3215 0.1628 0.2572 0.06637 良性
566 16.60 28.08 108.30 858.1 0.08455 0.10230 0.09251 0.05302 0.1590 0.05648 34.12 126.70 1124.0 0.11390 0.30940 0.3403 0.1418 0.2218 0.07820 良性
567 20.60 29.33 140.10 1265.0 0.11780 0.27700 0.35140 0.15200 0.2397 0.07016 39.42 184.60 1821.0 0.16500 0.86810 0.9387 0.2650 0.4087 0.12400 良性
568 7.76 24.54 47.92 181.0 0.05263 0.04362 0.00000 0.00000 0.1587 0.05884 30.37 59.16 268.6 0.08996 0.06444 0.0000 0.0000 0.2871 0.07039 恶性的

5行×31列

CIFAR-10个数据探索

接下来, 你将探索CIFAR-10个图像数据集

你可以使用称为Keras的深度学习库来加载CIFAR-10数据集。

from keras.datasets import cifar10

导入后, 你将使用.load_data()方法下载数据, 它将下载数据并将其存储在Keras目录中。根据你的互联网速度, 这可能需要一些时间。

(x_train, y_train), (x_test, y_test) = cifar10.load_data()

上面的代码行返回训练和测试图像以及标签。

让我们快速打印训练和测试图像形状的形状。

print('Traning data shape:', x_train.shape)
print('Testing data shape:', x_test.shape)
Traning data shape: (50000, 32, 32, 3)
Testing data shape: (10000, 32, 32, 3)

让我们也打印标签的形状。

y_train.shape, y_test.shape
((50000, 1), (10000, 1))

我们还要找出标签的总数和数据具有的各种类别。

# Find the unique numbers from the train labels
classes = np.unique(y_train)
nClasses = len(classes)
print('Total number of outputs : ', nClasses)
print('Output classes : ', classes)
Total number of outputs :  10
Output classes :  [0 1 2 3 4 5 6 7 8 9]

现在要绘制CIFAR-10图像, 你将导入matplotlib并使用魔术(%)命令%matplotlib内联告诉jupyter笔记本在笔记本本身中显示输出!

import matplotlib.pyplot as plt
%matplotlib inline

为了更好地理解, 让我们创建一个字典, 该字典将具有带有相应类别分类标签的类名。

label_dict = {
 0: 'airplane', 1: 'automobile', 2: 'bird', 3: 'cat', 4: 'deer', 5: 'dog', 6: 'frog', 7: 'horse', 8: 'ship', 9: 'truck', }
plt.figure(figsize=[5, 5])

# Display the first image in training data
plt.subplot(121)
curr_img = np.reshape(x_train[0], (32, 32, 3))
plt.imshow(curr_img)
print(plt.title("(Label: " + str(label_dict[y_train[0][0]]) + ")"))

# Display the first image in testing data
plt.subplot(122)
curr_img = np.reshape(x_test[0], (32, 32, 3))
plt.imshow(curr_img)
print(plt.title("(Label: " + str(label_dict[y_test[0][0]]) + ")"))
Text(0.5, 1.0, '(Label: frog)')
Text(0.5, 1.0, '(Label: cat)')
Python中的主成分分析(PCA)2

即使以上两个图像模糊, 你仍然可以以某种方式观察到第一个图像是带有标签青蛙的青蛙, 而第二个图像是带有标签猫的猫。

使用PCA进行数据可视化

现在是本教程最激动人心的部分。正如你先前所了解的那样, PCA项目将高维数据转换为低维主成分, 现在是时候借助Python对其进行可视化了!

可视化乳腺癌数据

  • 由于PCA的输出受数据特征量的影响, 因此你首先要对数据进行标准化。

    在将数据提供给任何机器学习算法之前, 对数据进行规范化是一种常见的做法。

    要应用规范化, 你将从sklearn库中导入StandardScaler模块, 并仅从你在”数据浏览”步骤中创建的breast_dataset中选择特征。拥有要素后, 即可通过对要素数据执行fit_transform来应用缩放。

    在应用StandardScaler时, 应按正态分布数据的每个特征, 以便它将分布的平均值缩放为零, 标准偏差为1。

from sklearn.preprocessing import StandardScaler
x = breast_dataset.loc[:, features].values
x = StandardScaler().fit_transform(x) # normalizing the features
x.shape
(569, 30)

让我们检查标准化数据的平均值是否为零, 标准偏差是否为1。

np.mean(x), np.std(x)
(-6.826538293184326e-17, 1.0)

让我们借助DataFrame将规范化的特征转换为表格格式。

feat_cols = ['feature'+str(i) for i in range(x.shape[1])]
normalised_breast = pd.DataFrame(x, columns=feat_cols)
normalised_breast.tail()
特征0 特征1 特征2 特征3 特征4 特征5 特征6 特征7 特征8 特征9 特征20 Feature21 Feature22 Feature23 Feature24 特征25 特征26 特征27 特征28 特征29
564 2.110995 0.721473 2.060786 2.343856 1.041842 0.219060 1.947285 2.320965 -0.312589 -0.931027 1.901185 0.117700 1.752563 2.015301 0.378365 -0.273318 0.664512 1.629151 -1.360158 -0.709091
565 1.704854 2.085134 1.615931 1.723842 0.102458 -0.017833 0.693043 1.263669 -0.217664 -1.058611 1.536720 2.047399 1.421940 1.494959 -0.691230 -0.394820 0.236573 0.733827 -0.531855 -0.973978
566 0.702284 2.045574 0.672676 0.577953 -0.840484 -0.038680 0.046588 0.105777 -0.809117 -0.895587 0.561361 1.374854 0.579001 0.427906 -0.809587 0.350735 0.326767 0.414069 -1.104549 -0.318409
567 1.838341 2.336457 1.982524 1.735218 1.525767 3.272144 3.296944 2.658866 2.137194 1.043695 1.961239 2.237926 2.303601 1.653171 1.430427 3.904848 3.197605 2.289985 1.919083 2.219635
568 -1.808401 1.221792 -1.814389 -1.347789 -3.112085 -1.150752 -1.114873 -1.261820 -0.820070 -0.561032 -1.410893 0.764190 -1.432735 -1.075813 -1.859019 -1.207552 -1.305831 -1.745063 -0.048138 -0.751207

5行×30列

  • 现在是关键部分, 接下来的几行代码将把30维乳腺癌数据投影到二维主成分上。

    你将使用sklearn库导入PCA模块, 并且在PCA方法中, 将传递组件数(n_components = 2), 最后对聚合数据调用fit_transform。在这里, 几个组件代表较低的维度, 你将在其中投影较高的维度数据。

from sklearn.decomposition import PCA
pca_breast = PCA(n_components=2)
principalComponents_breast = pca_breast.fit_transform(x)

接下来, 让我们创建一个DataFrame, 它将具有所有569个样本的主要成分值。

principal_breast_Df = pd.DataFrame(data = principalComponents_breast
             , columns = ['principal component 1', 'principal component 2'])
principal_breast_Df.tail()
主成分1 主成分2
564 6.439315 -3.576817
565 3.793382 -3.584048
566 1.256179 -1.902297
567 10.374794 1.672010
568 -5.475243 -0.670637
  • 一旦有了主要组成部分, 就可以找到explained_variance_ratio。在将数据投影到较低维度的子空间后, 它将为你提供每个主成分所拥有的信息量或差异。
print('Explained variation per principal component: {}'.format(pca_breast.explained_variance_ratio_))
Explained variation per principal component: [0.44272026 0.18971182]

从上面的输出中, 你可以看到主成分1保留了44.2%的信息, 而主成分2仅保留了19%的信息。另外, 要注意的另一点是, 在将30维数据投影到二维数据时, 丢失了36.8%的信息。

让我们沿着主分量-1和主分量-2轴绘制569个样本的可视化。它应该使你对样本如何在两个类之间分配有很好的了解。

plt.figure()
plt.figure(figsize=(10, 10))
plt.xticks(fontsize=12)
plt.yticks(fontsize=14)
plt.xlabel('Principal Component - 1', fontsize=20)
plt.ylabel('Principal Component - 2', fontsize=20)
plt.title("Principal Component Analysis of Breast Cancer Dataset", fontsize=20)
targets = ['Benign', 'Malignant']
colors = ['r', 'g']
for target, color in zip(targets, colors):
    indicesToKeep = breast_dataset['label'] == target
    plt.scatter(principal_breast_Df.loc[indicesToKeep, 'principal component 1']
               , principal_breast_Df.loc[indicesToKeep, 'principal component 2'], c = color, s = 50)

plt.legend(targets, prop={'size': 15})
<matplotlib.legend.Legend at 0x14552a630>




<Figure size 432x288 with 0 Axes>
Python中的主成分分析(PCA)3

从上图可以看出, 当将良性和恶性这两个类别投影到二维空间时, 在某种程度上可以线性分离。其他观察结果可能是良性阶级比恶性阶级散布开来。

可视化CIFAR-10个数据

以下用于可视化CIFAR-10数据的代码行与乳腺癌数据的PCA可视化非常相似。

  • 让我们快速检查CIFAR-10训练图像的最大值和最小值, 并对介于0和1之间的像素进行归一化。
np.min(x_train), np.max(x_train)
(0.0, 1.0)
x_train = x_train/255.0
np.min(x_train), np.max(x_train)
(0.0, 0.00392156862745098)
x_train.shape
(50000, 32, 32, 3)

接下来, 你将创建一个DataFrame, 它将以行列格式保存图像的像素值及其各自的标签。

但是在此之前, 让我们将图像尺寸从三个调整为一维(展平图像)。

x_train_flat = x_train.reshape(-1, 3072)
feat_cols = ['pixel'+str(i) for i in range(x_train_flat.shape[1])]
df_cifar = pd.DataFrame(x_train_flat, columns=feat_cols)
df_cifar['label'] = y_train
print('Size of the dataframe: {}'.format(df_cifar.shape))
Size of the dataframe: (50000, 3073)

完善!数据帧的大小是正确的, 因为有50, 000个训练图像, 每个训练图像具有3072像素和一个附加的标签列, 因此总计3073。

PCA将应用于除最后一列(每张图像的标签)以外的所有列。

df_cifar.head()
像素0 像素1 像素2 像素3 像素4 像素5 像素6 像素7 像素8 像素9 像素3063 像素3064 像素3065 像素3066 像素3067 像素3068 像素3069 像素3070 像素3071 标签
0 0.231373 0.243137 0.247059 0.168627 0.180392 0.176471 0.196078 0.188235 0.168627 0.266667 0.847059 0.721569 0.549020 0.592157 0.462745 0.329412 0.482353 0.360784 0.282353 6
1 0.603922 0.694118 0.733333 0.494118 0.537255 0.533333 0.411765 0.407843 0.372549 0.400000 0.560784 0.521569 0.545098 0.560784 0.525490 0.556863 0.560784 0.521569 0.564706 9
2 1.000000 1.000000 1.000000 0.992157 0.992157 0.992157 0.992157 0.992157 0.992157 0.992157 0.305882 0.333333 0.325490 0.309804 0.333333 0.325490 0.313725 0.337255 0.329412 9
3 0.109804 0.098039 0.039216 0.145098 0.133333 0.074510 0.149020 0.137255 0.078431 0.164706 0.211765 0.184314 0.109804 0.247059 0.219608 0.145098 0.282353 0.254902 0.180392 4
4 0.666667 0.705882 0.776471 0.658824 0.698039 0.768627 0.694118 0.725490 0.796078 0.717647 0.294118 0.309804 0.321569 0.278431 0.294118 0.305882 0.286275 0.301961 0.313725 1

5行×3073列

  • 接下来, 你将创建PCA方法, 并将组件数作为两个传递, 并将fit_transform应用于训练数据, 这可能需要几秒钟, 因为有50, 000个样本
pca_cifar = PCA(n_components=2)
principalComponents_cifar = pca_cifar.fit_transform(df_cifar.iloc[:, :-1])

然后, 你将把50, 000张图像中的每张图像的主要成分从numpy数组转换为pandas DataFrame。

principal_cifar_Df = pd.DataFrame(data = principalComponents_cifar
             , columns = ['principal component 1', 'principal component 2'])
principal_cifar_Df['y'] = y_train
principal_cifar_Df.head()
主成分1 主成分2
0 -6.401018 2.729039 6
1 0.829783 -0.949943 9
2 7.730200 -11.522102 9
3 -10.347817 0.010738 4
4 -2.625651 -4.969240 1
  • 让我们快速找出主要成分所拥有的信息量或差异。
print('Explained variation per principal component: {}'.format(pca_cifar.explained_variance_ratio_))
Explained variation per principal component: [0.2907663  0.11253144]

好吧, 由于数据是从3072维度投影到仅有的两个主成分, 因此主成分1和2似乎保留了大量的信息。

是时候在二维空间中可视化CIFAR-10数据了。请记住, 此数据集中存在一些语义类别重叠, 这意味着青蛙可以具有猫或鹿与狗的形状稍相似的形状;特别是在二维空间中投影时。它们之间的差异可能无法很好地体现出来。

import seaborn as sns
plt.figure(figsize=(16, 10))
sns.scatterplot(
    x="principal component 1", y="principal component 2", hue="y", palette=sns.color_palette("hls", 10), data=principal_cifar_Df, legend="full", alpha=0.3
)
<matplotlib.axes._subplots.AxesSubplot at 0x12a5ba8d0>
Python中的主成分分析(PCA)4

从上图可以看到, 主成分捕获了一些变化, 因为沿两个主成分轴投影时, 点中存在某些结构。属于同一类的点彼此接近, 并且语义上非常不同的点或图像彼此相距更远。

结合使用PCA和CIFAR加快深度学习培训-10数据集

在本教程的最后一部分中, 你将学习如何使用PCA加快深度学习模型的培训过程。

注意:要了解本节中将使用的基本术语, 请随时查看本教程。

首先, 让我们标准化训练和测试图像。如果你记得在PCA可视化部分中对训练图像进行了归一化, 那么你只需要对测试图像进​​行归一化。所以, 让我们快速地做到这一点!

x_test = x_test/255.0
x_test = x_test.reshape(-1, 32, 32, 3)

让我们重塑测试数据。

x_test_flat = x_test.reshape(-1, 3072)

接下来, 你将创建PCA模型的实例。

在这里, 你还可以传递要PCA捕获的差异。让我们将0.9作为参数传递给PCA模型, 这意味着PCA将保留90%的方差, 并且将使用捕获90%的方差所需的组件数。

请注意, 你之前已将n_components作为参数传递, 然后可以发现这两个组件捕获了多少差异。但是在这里, 我们明确提到希望PCA捕获多少方差, 因此n_components将根据方差参数而变化。

如果你不传递任何方差, 那么组件的数量将等于数据的原始维度。

pca = PCA(0.9)

然后, 你将使PCA实例适合训练图像。

pca.fit(x_train_flat)
PCA(copy=True, iterated_power='auto', n_components=0.9, random_state=None, svd_solver='auto', tol=0.0, whiten=False)

现在让我们找出有多少个n_component PCA用于捕获0.9方差。

pca.n_components_
99

从上面的输出中, 你可以观察到要实现90%的差异, 尺寸从实际的3072尺寸减少到99个主要成分。

最后, 你将对训练集和测试集都应用转换, 以根据fit方法生成的参数生成转换后的数据集。

train_img_pca = pca.transform(x_train_flat)
test_img_pca = pca.transform(x_test_flat)

接下来, 让我们快速导入必要的库以运行深度学习模型。

from keras.models import Sequential
from keras.layers import Dense
from keras.utils import np_utils
from keras.optimizers import RMSprop

现在, 你将训练和测试标签转换为一键编码矢量。

y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)

让我们定义模型的纪元数, 类数和批处理大小。

batch_size = 128
num_classes = 10
epochs = 20

接下来, 你将定义你的顺序模型!

model = Sequential()
model.add(Dense(1024, activation='relu', input_shape=(99, )))
model.add(Dense(1024, activation='relu'))
model.add(Dense(512, activation='relu'))
model.add(Dense(256, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))

让我们打印模型摘要。

model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 1024)              102400    
_________________________________________________________________
dense_2 (Dense)              (None, 1024)              1049600   
_________________________________________________________________
dense_3 (Dense)              (None, 512)               524800    
_________________________________________________________________
dense_4 (Dense)              (None, 256)               131328    
_________________________________________________________________
dense_5 (Dense)              (None, 10)                2570      
=================================================================
Total params: 1, 810, 698
Trainable params: 1, 810, 698
Non-trainable params: 0
_________________________________________________________________

最后, 是时候编译和训练模型了!

model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy'])

history = model.fit(train_img_pca, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(test_img_pca, y_test))
WARNING:tensorflow:From /Users/adityasharma/blog/lib/python3.7/site-packages/keras/backend/tensorflow_backend.py:2704: calling reduce_sum (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.
Instructions for updating:
keep_dims is deprecated, use keepdims instead
WARNING:tensorflow:From /Users/adityasharma/blog/lib/python3.7/site-packages/keras/backend/tensorflow_backend.py:1257: calling reduce_mean (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.
Instructions for updating:
keep_dims is deprecated, use keepdims instead
Train on 50000 samples, validate on 10000 samples
Epoch 1/20
50000/50000 [==============================] - 7s - loss: 1.9032 - acc: 0.2962 - val_loss: 1.6925 - val_acc: 0.3875
Epoch 2/20
50000/50000 [==============================] - 7s - loss: 1.6480 - acc: 0.4055 - val_loss: 1.5313 - val_acc: 0.4412
Epoch 3/20
50000/50000 [==============================] - 7s - loss: 1.5205 - acc: 0.4534 - val_loss: 1.4609 - val_acc: 0.4695
Epoch 4/20
50000/50000 [==============================] - 7s - loss: 1.4322 - acc: 0.4849 - val_loss: 1.6164 - val_acc: 0.4503
Epoch 5/20
50000/50000 [==============================] - 7s - loss: 1.3621 - acc: 0.5120 - val_loss: 1.3626 - val_acc: 0.5081
Epoch 6/20
50000/50000 [==============================] - 7s - loss: 1.2995 - acc: 0.5330 - val_loss: 1.4100 - val_acc: 0.4940
Epoch 7/20
50000/50000 [==============================] - 7s - loss: 1.2473 - acc: 0.5529 - val_loss: 1.3589 - val_acc: 0.5251
Epoch 8/20
50000/50000 [==============================] - 7s - loss: 1.2010 - acc: 0.5669 - val_loss: 1.3315 - val_acc: 0.5232
Epoch 9/20
50000/50000 [==============================] - 7s - loss: 1.1524 - acc: 0.5868 - val_loss: 1.3903 - val_acc: 0.5197
Epoch 10/20
50000/50000 [==============================] - 7s - loss: 1.1134 - acc: 0.6013 - val_loss: 1.2722 - val_acc: 0.5499
Epoch 11/20
50000/50000 [==============================] - 7s - loss: 1.0691 - acc: 0.6160 - val_loss: 1.5911 - val_acc: 0.4768
Epoch 12/20
50000/50000 [==============================] - 7s - loss: 1.0325 - acc: 0.6289 - val_loss: 1.2515 - val_acc: 0.5602
Epoch 13/20
50000/50000 [==============================] - 7s - loss: 0.9977 - acc: 0.6420 - val_loss: 1.5678 - val_acc: 0.4914
Epoch 14/20
50000/50000 [==============================] - 8s - loss: 0.9567 - acc: 0.6567 - val_loss: 1.3525 - val_acc: 0.5418
Epoch 15/20
50000/50000 [==============================] - 9s - loss: 0.9158 - acc: 0.6713 - val_loss: 1.3525 - val_acc: 0.5540
Epoch 16/20
50000/50000 [==============================] - 10s - loss: 0.8948 - acc: 0.6816 - val_loss: 1.5633 - val_acc: 0.5156
Epoch 17/20
50000/50000 [==============================] - 9s - loss: 0.8690 - acc: 0.6903 - val_loss: 1.6980 - val_acc: 0.5084
Epoch 18/20
50000/50000 [==============================] - 9s - loss: 0.8586 - acc: 0.7002 - val_loss: 1.6325 - val_acc: 0.5247
Epoch 19/20
50000/50000 [==============================] - 8s - loss: 0.9367 - acc: 0.6853 - val_loss: 1.8253 - val_acc: 0.5165
Epoch 20/20
50000/50000 [==============================] - 8s - loss: 2.3761 - acc: 0.5971 - val_loss: 6.0192 - val_acc: 0.4409

从上面的输出中, 你可以观察到在CPU上训练每个时期所需的时间仅为7秒。该模型在训练数据上做得不错, 达到了70%的准确度, 而在测试数据上只有56%的准确度。这意味着它过度拟合了训练数据。但是, 请记住, 尽管数据做得很好, 但还是从3072个维度投影到了99个维度!

最后, 让我们看一下该模型在原始数据集上花费多少时间, 以及使用相同的深度学习模型可以达到多少精度。

model = Sequential()
model.add(Dense(1024, activation='relu', input_shape=(3072, )))
model.add(Dense(1024, activation='relu'))
model.add(Dense(512, activation='relu'))
model.add(Dense(256, activation='relu'))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy'])

history = model.fit(x_train_flat, y_train, batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(x_test_flat, y_test))
Train on 50000 samples, validate on 10000 samples
Epoch 1/20
50000/50000 [==============================] - 23s - loss: 2.0657 - acc: 0.2200 - val_loss: 2.0277 - val_acc: 0.2485
Epoch 2/20
50000/50000 [==============================] - 22s - loss: 1.8727 - acc: 0.3166 - val_loss: 1.8428 - val_acc: 0.3215
Epoch 3/20
50000/50000 [==============================] - 22s - loss: 1.7801 - acc: 0.3526 - val_loss: 1.7657 - val_acc: 0.3605
Epoch 4/20
50000/50000 [==============================] - 22s - loss: 1.7141 - acc: 0.3796 - val_loss: 1.6345 - val_acc: 0.4132
Epoch 5/20
50000/50000 [==============================] - 22s - loss: 1.6566 - acc: 0.4001 - val_loss: 1.6384 - val_acc: 0.4076
Epoch 6/20
50000/50000 [==============================] - 22s - loss: 1.6083 - acc: 0.4209 - val_loss: 1.7507 - val_acc: 0.3574
Epoch 7/20
50000/50000 [==============================] - 22s - loss: 1.5626 - acc: 0.4374 - val_loss: 1.7125 - val_acc: 0.4010
Epoch 8/20
50000/50000 [==============================] - 22s - loss: 1.5252 - acc: 0.4486 - val_loss: 1.5914 - val_acc: 0.4321
Epoch 9/20
50000/50000 [==============================] - 24s - loss: 1.4924 - acc: 0.4620 - val_loss: 1.5352 - val_acc: 0.4616
Epoch 10/20
50000/50000 [==============================] - 25s - loss: 1.4627 - acc: 0.4728 - val_loss: 1.4561 - val_acc: 0.4798
Epoch 11/20
50000/50000 [==============================] - 24s - loss: 1.4349 - acc: 0.4820 - val_loss: 1.5044 - val_acc: 0.4723
Epoch 12/20
50000/50000 [==============================] - 24s - loss: 1.4120 - acc: 0.4919 - val_loss: 1.4740 - val_acc: 0.4790
Epoch 13/20
50000/50000 [==============================] - 23s - loss: 1.3913 - acc: 0.4981 - val_loss: 1.4430 - val_acc: 0.4891
Epoch 14/20
50000/50000 [==============================] - 27s - loss: 1.3678 - acc: 0.5098 - val_loss: 1.4323 - val_acc: 0.4888
Epoch 15/20
50000/50000 [==============================] - 27s - loss: 1.3508 - acc: 0.5148 - val_loss: 1.6179 - val_acc: 0.4372
Epoch 16/20
50000/50000 [==============================] - 25s - loss: 1.3443 - acc: 0.5167 - val_loss: 1.5868 - val_acc: 0.4656
Epoch 17/20
50000/50000 [==============================] - 25s - loss: 1.3734 - acc: 0.5101 - val_loss: 1.4756 - val_acc: 0.4913
Epoch 18/20
50000/50000 [==============================] - 26s - loss: 5.5126 - acc: 0.3591 - val_loss: 5.7580 - val_acc: 0.3084
Epoch 19/20
50000/50000 [==============================] - 27s - loss: 5.6346 - acc: 0.3395 - val_loss: 3.7362 - val_acc: 0.3402
Epoch 20/20
50000/50000 [==============================] - 26s - loss: 6.4199 - acc: 0.3030 - val_loss: 13.9429 - val_acc: 0.1326

瞧!从上面的输出中, 很明显, 在CPU上训练每个时期所需的时间约为23秒, 几乎是在PCA输出上训练的模型的三倍。

此外, 训练和测试的准确性均低于使用99个主要组件作为模型输入获得的准确性。

因此, 通过将PCA应用于训练数据, 你不仅可以快速训练深度学习算法, 而且与使用原始训练数据训练的深度学习算法相比, 它还可以在测试数据上获得更高的准确性。

走得更远!

恭喜你完成了本教程。

本教程是Python中PCA的出色而全面的介绍, 它涵盖了PCA的理论和实践概念。

如果你想更深入地研究降维技术, 请考虑阅读有关t分布随机邻居嵌入(通常称为tSNE)的信息, tSNE是一种非线性概率降维技术。

如果你想了解有关PCA之类的无监督学习技术的更多信息, 请参加srcmini的Python无监督学习课程。

参考文献:

  • Sklearn中的PCA
  • R中的主成分分析
  • 使用Python的PCA(scikit-learn)

请随时在下面的评论部分中提出与本教程相关的任何问题。

赞(0)
未经允许不得转载:srcmini » Python中的主成分分析(PCA)

评论 抢沙发

评论前必须登录!