应用PCA降维加速模型训练
昨天我分享一篇使用逻辑回归(LogisticRgression)算法识别图片中手写数字的文章 《机器学习之识别图片中的数字》,当使用大规模数据MNIST时,使用不同的solver,训练模型的时间相差近60倍(65s VS 3840s)。实际上提高训练速度,除了改变LogisticRgression模型中的solver参数,还可以通过降低数据维度来加速训练过程。
本文将使用主成分分析(Principal Component analysis)实现无监督数据降维这一任务。当然PCA降低维度还可以帮助我们可视化,例如高维度数据是无法可视化,但是当我们将数据降低到三维以内,我们就可以对其进行可视化。
为了让大家便于理解PCA,我们先用小数据iris数据集做可视化,之后再用MNIST做降维以加速模型训练过程。
一、用PCA做可视化
对于2维或者3维数据来说,做可视化十分容易。但是,本文使用的iris数据集是有4维(变量)。我们可以使用PCA将4维压缩到2维度或者3维度以此来帮助我们可视化iris数据集。
1.1 导入数据
sklearn中自带iris数据集
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data
target = iris.target
print(X)
print(target)
运行结果
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[4.7 3.2 1.3 0.2]
。。。。
[6.5 3. 5.2 2. ]
[6.2 3.4 5.4 2.3]
[5.9 3. 5.1 1.8]]
[0 0 0 0 0 0 0 2 2 1 1 2 2。。。。。 2 2 2 2 2 2 1 2 2 2 0 2 1 2 0 2]
1.2 标准化
PCA对数据进行降维时,会受到量纲影响。所以我们要在PCA之前对数据进行标准化,这里我们将数据转化为标准差为1,均值为0的新数据。sklearn中的preprocessing包含有标准化类StandardScaler。
from sklearn.preprocessing import StandardScaler
X = StandardScaler().fit_transform(X)
print(X)
运行结果
[[-9.00681170e-01 1.03205722e+00 -1.34127240e+00 -1.31297673e+00]
[-1.14301691e+00 -1.24957601e-01 -1.34127240e+00 -1.31297673e+00]
[-9.00681170e-01 1.72626612e+00 -1.28440670e+00 -1.18150376e+00]
。。。。。。。。。
[ 7.95669016e-01 -1.24957601e-01 8.19624347e-01 1.05353673e+00]
[ 4.32165405e-01 8.00654259e-01 9.33355755e-01 1.44795564e+00]
[ 6.86617933e-02 -1.24957601e-01 7.62758643e-01 7.90590793e-01]]
1.3 降维(4D -> 2D)
需要注意的是维度压缩后的新维度并没有具体的含义,例如,压缩前数据的4维(变量)依次代表sepal length, sepal width, petal length, petal width。但是维度压缩后得到的两个维度,我们并不清楚实际上它代表什么。如果非要赋予含义,我会将其命名为PC1、PC2.
from sklearn.decomposition import PCA
import pandas as pd
#压缩至两个成分(两个维度)
pca = PCA(n_components=2)
#对数据进行PCA处理
principalComponents = pca.fit_transform(X)
#将数据化为dataframe,命名
principalDf = pd.DataFrame(data=principalComponents, columns=['PC1', 'PC2'])
#随机抽选出5条数据
principalDf.sample(5)
1.4 将数据整合到dataframe中
最终我们将target也整理到dataframe中
#将target转化为datafrmae
target_df = pd.DataFrame(target, columns=['target'])
#将两个dataframe按照axis=1方向(行)合并
finalDf = pd.concat([principalDf, target_df], axis = 1)
finalDf.sample(5)
1.5 对2D数据可视化
使用matplotlib对2维数据进行可视化,我们会发现数据能较好的区分开来,说明PCA效果很好的起到了降低维度的效果。
%matplotlib inline
import matplotlib.pyplot as plt
plt.figure(figsize = (8, 8))
plt.xlabel('PC1', )
plt.ylabel('PC2')
plt.title("2 components's PCA", size=20)
#花的种类
targets = ['Iris-setosa', 'Iris-versicolor', 'Iris-virginica']
#在图中对三种花依次标注红绿蓝
colors = ['r', 'g', 'b']
#将三种花选出来;
#finalDf[finalDf['target']==0] 挑选出target为0的花
flower_datas = [finalDf[finalDf['target']==0],
finalDf[finalDf['target']==1],
finalDf[finalDf['target']==2]]
for flower_data, color in zip(flower_datas, colors):
plt.scatter(flower_data.PC1, flower_data.PC2 , c=color, s=50)
plt.legend(targets)
plt.grid()
1.6 降维后的信息量
通过方差可以体现信息量,比如我如果说['我','我', '我'],那么基本没说什么信息方差为a。
而如果我说['我','是','学生'],这句话差异较大,方差比较大,信息量也大。
这里我们想看看从4维压缩到2维数据信息量方面的信息,这里就要使用PCA的explained_variance_ratio_
#PC1、PC2方差(相当于原来数据经过压缩后保留的信息量占比)
print(pca.explained_variance_ratio_)
#将数据压缩到2D,保留了95.8%的信息量
print(pca.explained_variance_ratio_.sum())
运行结果
[0.72770452 0.23030523]
0.9580097536148198
二、使用PCA加速模型训练
昨天的文章,最快的训练也需要65s,今天我们使用PCA看看速度还能不能再快点。
2.1 导入MNIST数据
MNIST一共有70000张手写数字图片,其中训练集60000, 测试集10000张。
每一张照片尺寸为(28,28),但是由于是以数组形成存储,实际上图片数据以28*28=784长度存储于一维数组中
import pandas as pd
import numpy as np
train = pd.read_csv('mnist_train.csv', header = None)
test = pd.read_csv('mnist_test.csv', header = None)
y_train = train.loc[:, 0] #pd.series
#注意:train.loc[:, 1:]返回的是pd.DataFrame类。
#这里我们使用values方法将其转化数组类型数据
X_train = train.loc[:, 1:].values
y_test = test.loc[:, 0]
X_test = test.loc[:, 1:].values
#我们看看这些MNIST维度
print('X_train 维度: {}'.format(X_train.shape))
print('y_train 维度: {}'.format(y_train.shape))
print('X_test 维度: {}'.format(X_test.shape))
print('y_test 维度: {}'.format(y_test.shape))
运行结果
X_train 维度: (60000, 784)
y_train 维度: (60000,)
X_test 维度: (10000, 784)
y_test 维度: (10000,)
2.2 标准化
重要事要多说几遍,PCA会受到数据量纲影响,所以PCA之前我们要对数据进行标准化处理。
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
#注意fit时我们仅仅对训练集进行。
scaler.fit(X_train)
#再对训练集和测试集均进行transform
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
2.3 对数据进行PCA降维
注意n_components参数即可以设置为整数,表示保留几个维度。
n_components参数也可以设置为百分比,表示保留多少信息量。
所以这里我们使用保留95%的信息量
from sklearn.decomposition import PCA
pca = PCA(n_components = 0.95)
#再次注意,fit只读训练数据fit。
#实际上这里是要学习特征空间
pca.fit(X_train)
#之后对训练集和测试集进行数据压缩
X_train = pca.transform(X_train)
X_test = pca.transform(X_test)
2.4 比较模型准确率和训练时间
上篇文章,我们使用LogisticRegression模型,其中参数solver设置为fbfgs。因为之前的数据都已经被更改了,所以我们这里重新导入依次数据。
我们查看信息量压缩后模型准确率和训练时间
from sklearn.linear_model import LogisticRegression
from sklearn.preprocessing import StandardScaler
from sklearn.decomposition import PCA
import numpy as np
import pandas as pd
import time
def read_data():
#读取数据
train = pd.read_csv('mnist_train.csv', header = None)
test = pd.read_csv('mnist_test.csv', header = None)
y_train = train.loc[:, 0]
X_train = train.loc[:, 1:].values
y_test = test.loc[:, 0]
X_test = test.loc[:, 1:].values
#标准化数据
scaler = StandardScaler()
scaler.fit(X_train)
X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)
return X_train,X_test, y_train, y_test
def time_and_score(n_component):
"""
查看模型训练时间及其准确率
"""
#读取数据,返回标准化的数据
X_train,X_test, y_train, y_test = read_data()
pca = PCA(n_components = n_component)
#学习特征空间,只fit训练数据
pca.fit(X_train)
#之后对训练集和测试集进行数据压缩
X_train = pca.transform(X_train)
X_test = pca.transform(X_test)
#PCA后保留的变量数目
varience_num = pca.n_components_
#开始计时
start = time.time()
#初始化LogisticRegression模型
logisticRegr = LogisticRegression(solver='lbfgs')
#使用训练集数据训练模型
logisticRegr.fit(X_train, y_train)
score = logisticRegr.score(X_test, y_test)
end = time.time()
print('PCA后保留%-5.2f信息量; 保留%-5d个变量; 模型准确率%-10.5f; 训练时间%-8.5fs'%(n_component, varience_num, score, end-start))
查看不同压缩比例后,模型训练时间、准确率、保留的变量数目信息。
#信息量压缩比例(PCA的n_components参数)
component_percentages = np.arange(0.8, 1.0, 0.02)
for n_component in component_percentages:
time_and_score(n_component)
运行结果(可以滑动手指看看准确率和运行时间)
PCA后保留0.80 信息量; 保留149 个变量; 模型准确率0.91530 ; 训练时间15.06597s
PCA后保留0.82 信息量; 保留162 个变量; 模型准确率0.91610 ; 训练时间17.15219s
PCA后保留0.84 信息量; 保留177 个变量; 模型准确率0.91710 ; 训练时间17.42961s
PCA后保留0.86 信息量; 保留194 个变量; 模型准确率0.91780 ; 训练时间17.89379s
PCA后保留0.88 信息量; 保留213 个变量; 模型准确率0.91750 ; 训练时间19.61466s
PCA后保留0.90 信息量; 保留236 个变量; 模型准确率0.91950 ; 训练时间21.78779s
PCA后保留0.92 信息量; 保留266 个变量; 模型准确率0.92130 ; 训练时间28.77281s
PCA后保留0.94 信息量; 保留305 个变量; 模型准确率0.92160 ; 训练时间29.93846s
PCA后保留0.96 信息量; 保留362 个变量; 模型准确率0.92260 ; 训练时间36.63086s
PCA后保留0.98 信息量; 保留459 个变量; 模型准确率0.92260 ; 训练时间38.65022s
可以发现,相比于昨天65s,今天使用PCA降维后,训练速度大大提高,而且准确率依然保持在90%以上。
而且,我们发现,信息量压缩为原来的80%,准确率达到91.5%。而信息量压缩为98%, 准确率为92.3%。但是我们牺牲准确率不到1%,却能提高训练时间将近200%