查看原文
其他

应用PCA降维加速模型训练

大邓 大邓和他的Python 2019-04-26

昨天我分享一篇使用逻辑回归(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()
可以从上图中看出,降维后数据仍然可以很好地区分
png

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%


数据及代码获取

往期文章

100G Python学习资料:从入门到精通! 免费下载   

在校大学生如何用知识月入3000

上百G文本数据集等你来认领|免费领取

为什么你要为2019,而不是2018做计划?    

2017年度15个最好的数据科学领域Python库  

初识K-means算法   

机器学习之使用逻辑回归识别图片中的数字

机器学习|八大步骤解决90%的NLP问题  

使用sklearn做自然语言处理-1

复杂嵌套字典数据结构处理库-glom

读取pdf和docx文件,亲测有效

如何从文本中提取特征信息? 

对于中文,nltk能做哪些事情 

留在网上的每个字,都在泄露你的身份

优雅简洁的列表推导式

Get小技巧等分列表

如何对数据进行各种排序?

【视频讲解】Scrapy递归抓取简书用户信息

美团商家信息采集神器 

用chardect库解决网页乱码问题

gevent:异步理论与实战  

轻盈高效的异步访问库grequests库

selenium驱动器配置详解

爬虫神器PyQuery的使用方法

简易SQLite3数据库学习

Python通过字符串调用函数

Python圈中的符号计算库-Sympy

Python中处理日期时间库的使用方法 


    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存