1.使用单一变量法用于特征选择
点一变量法的定义:
有一定统计学基础的同学可能了解,在统计学中,我们会分析在样本特征和目标之间是否会有明显的相关性。在进行统计分析的过程中,我们会选择那些置信度最高的样本特征来进行分析。当然这只适用于样本特征之间没有明显关联的情况,也就是大家常说的单一变量法(univariate)。
举个例子,在市场营销中,玩具厂商更关注目标人群的年龄,不同年龄段的儿童对于玩具的需求是不相同的,所以厂商更倾向于根据年龄来细分市场,并且进行产品设计。而小额贷公司更关心客户的偿债能力,因此会将目标客户的收入情况作为更重要的特征。在这种情况下,有些不是那么重要的特征就会被剔除。这种方法的优点是计算量较小,而且不需要建模,只用基本的方差分析就可以实现了。
在scikit-learn中,有若干种方法可以进行特征选择,其中最简单的两种是SelectPercentile和SelectKBest,其中SelectPercentile是自动选择原始特征的百分比,例如原石特征的特征数是200个,那么SelectPercentile的pecentile参数设置为50,就会选择100个原石特征中的50%,即100个,而SelectKBest是自动选择K个最重要的特征。
下面我们用一个非常刺激的数据集来做个试验。说这个数据集刺激,是因为它是来自中国股市。我们用证券交易软件导出了当日全部A股股票的交易数据,保存成为了一个csv文件,并且去掉了无效数据,具体获取方式如下:
中国股票市场的股价涨幅数据集收取
首先,需要一个股票交易软件,如果你在某个整卷交易公司开过户,就应该会用该公司提供的软件,如果没有开过户,可以使用一些第三方软件,如通达信、同花顺或者大智慧一类的软件来获取股票数据,这里我们使用通达信的软件为例进行展示:
1.下载安装通信达pc端软件,如下图:
双击打开股票交易软件,可以看到全部股票的信息,如下图:
2.使用软件自带的数据导出功能获取股票数据,点击系统菜单,选择数据导出功能,如下图:
点击“数据导出”按键后,弹出对话框,如下图:
在上图中,我么你选择导出格式为excel文件格式,选择导出报表中的所有数据,然后修改文件保存路径和文件名,单击导出按钮,就可以将数据导出为xls文件了。
数据导出之后,可以使用Excel软件打开,如下图所示:
上图中展示的只是所有数据中的一部分,仅做案例演示。
观察这个数据集,发现有几个问题。
1.在细分行业和地区这两列全部都是字符串类型的特征。我们可以使用之前学过的get_dummies把他们转成整型数值,但这里我们假定这两个特征对分析影响不大,因此将这两列删除处理。
2.我们看到在“未匹配量”这一列中,几乎全部都是“--”符号,表示无效数值,因此这一列我们也进行删除处理。
3.我们看到在其他的行和列中,零星散布着一些“--”符号,这些大部分是由于当日该股票处于停牌状态,因此相对应的数值缺失,所以我们把这些“--”符号全部替换为0.
另外还有一些其他的冗余信息,比如所导出的数据中,包含数据来源信息,这些也全部删除。在这些工作完成之后,我们把数据集保存为一个CSV文件,以供下一步使用。
我们试着用这个数据训练一个机器学习模型,输入代码如下:
import pandas as pd
stock = pd.read_csv('d:/stock dataset/071013.csv',encoding='GBK')
print(stock.head())
运行代码如下:
结果分析:可以看出,这个csv文件中包括26列。
我们的目标是通过回归分析,预测股票的涨幅,所以target是涨幅这一列,输入代码如下:
y = stock['涨幅%%']
print(y.shape)
print(y[0])
运行代码,结果:
(2860,)
-1.65
结果分析:样本一共有2860个,而第一个样本,也就是名称为平安银行的股票,当日的涨幅为-1.65%。这说明我们制定target成功。
接下来要指定样本的特征,输入代码如下:
features = stock.loc[:,'现价':'流通股(亿)']
X = features.values
print(X.shape)
print(X[:1])
运行代码如下:
结果分析:我们发现,这些特征值之间的数量级差别比较大,这样的话,在模型训练之前,需要用sklearn的预处理模块进行一下数据缩放,输入代码如下:
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
mlpr=MLPRegressor(random_state=62, hidden_layer_sizes=(100,100),alpha=0.001)
X_train, X_test, y_train, y_test=train_test_split(X,y,random_state=62)
scaler = StandardScaler()
scaler.fit(X_train)
X_train_scaled = scaler.transform(X_train)
X_test_scaled = scaler.transform(X_test)
mlpr.fit(X_train_scaled, y_train)
print('模型准确率:{:.2f}'.format(mlpr.score(X_test_scaled,y_test)))
运行代码,如下:
模型准确率:0.93
结果分析:可以看到,用神经网络对A股涨幅进行回归分析,模型的预测准确率达到了93%,是一个可以接受的成绩。
下面我们列出那些涨幅大于或等于9%的股票,输入代码如下:
wanted = stock.loc[:,'名称']
print(wanted[y>=9])
运行代码,得到股票名称如下:
使用SelectPercentile进行特征选择:
输入代码如下:
from sklearn.feature_selection import SelectPercentile
select = SelectPercentile(percentile=50)
select.fit(X_train_scaled, y_train)
X_train_selected = select.transform(X_train_scaled)
print('经过缩放的特征形态:{}'.format(X_train_scaled.shape))
print('特征选择后的特征形态:{}'.format(X_train_selected.shape))
我们制定SelectPercentile的百分比参数percentile为50,即保留在上一步缩放之后的数据50%的特征,运行代码,结果如下:
经过缩放的特征形态:(2145, 23)
特征选择后的特征形态:(2145, 11)
结果分析:可以看出,原石特征23个,经过特征选择之后,特征数仅为11个。
思考:究竟哪些特征被保留下来,哪些特征被去掉了呢?可以使用get_support方法来查看一下,输入代码:
mask = select.get_support()
print(mask)
运行:
结果分析:False代表该特征没有被选择,True代表被选择。如果有股票投资经验的朋友就可以看出,这几个交易数据确实是和涨幅有最直接的相关性。
还可以用图形直观地看一下特征选择的结果,输入代码如下:
plt.matshow(mask.reshape(1,-1),cmap=plt.cm.cool)
plt.xlabel("Features Selected")
plt.show()
运行代码,得到如下图结果:
用代码实验一下,经过特征选择后的数据集训练的神经网络模型表现会如何:
X_test_selected = select.transform(X_test_scaled)
mlpr_sp=MLPRegressor(random_state=62, hidden_layer_sizes=(100,100),
alpha=0.001)
mlpr_sp.fit(X_train_selected, y_train)
print('特征选择后模型得分:{:.2f}'.format(mlpr_sp.score(X_test_selected,
y_test)))
运行代码:
特征选择后模型得分:0.87
结果分析:在进行特征选择之后,模型的评分轻微降低了,这是非常正常的,因为我们的数据并不包括噪声,对于噪声特别多的数据集来说,进行特征选择之后模型评分会提高很多,而不是降低。
2.基于模型的特征选择
在上面的小节当中,我们使用了单一变量法对数据特征进行了选择,接下来我们要学习一个更加强大的工具来对数据特征进行选择,就是基于模型的特征选择。
基于模型的特征选择工作原理:
先使用一个有监督学习的模型对数据特征的重要性进行判断,然后把最重要的特征进行保留。当然,这一步中用到的模型和最终用来进行预测分析的模型不一定是同一个。
下面我们用scikit-learn中的selectFromModel功能来对股票数据集进行实验,输入代码如下:
#导人基于模型的特征选择工具
from sklearn.feature_selection import SelectFromModel
#导入随机森林模型
from sklearn . ensemble import RandomForestRegressor
#设置模型 estimators参数
sfm = SelectFromModel (RandomForestRegressor(n estimators=lOO ,
random state=38) ,
threshold= median 『)
#使用模型拟合数据
sfm .fit(X_train_scaled , y_train)
X train sfm = sfm . transform(X train scaled)
#打印结果
print (’ 基于随机森林模型迸行特征后的数据形态 {} ’. format (X _train,_ sfm . shape ) )
从上面的代码可以看到,我们使用了随机森林回归模型来进行特征选择。为什么要用随机森林呢?因为包括随机森林在内的基于决策树的算法都会内置一个称为feature_importances_的属性,我们可以让selectFromModel直接从这个属性中抽取特征的重要性。当然除了随机森林之外,其他算法也是可以的,例如使用L1正则化的线性模型,他们可以对数据空间的稀疏系数进行学习,从而可以当做特征重要性来抽取。原本这个系数是线性模型用来为自己建模的,我们可以额借助它来帮助其他模型进行数据预处理。
运行上面的代码,得到如下图的结果:
结果分析:可以看到,通过基于随机森林模型进行特征选择之后,数据集中样本的特征还剩下12个,比原始特征数量少了11个,而比用单一变量法进行特征选择的结果多了一个。
下面我么你看一下基于随机森林模型的特征选择有什么区别,输入代码如下:
#显示保留的特征
mask_sfm = sfm.get_support()
print(mask_sfm)
运行结果如下:
同样地,我们也对特征选择进行一下可视化,输入代码如下:
plt.matshow(mask.reshape(1,-1), cmap=plt.cm.cool)
plt.xlabel('Features Selected')
plt.show()
运行代码,得到如下图所示的结果:
结果分析:对比这张图和前面用但一变量法进行特征选择的那张图,可以很直观地看出两者特征选择的区别。
我们在进行特征选择的过程中,使用了一个有100棵决策树的随机森林,这使得模型相当复杂,但是他的结果会比但一变量法强悍很多。
下面我们实验一下经过随机森林模型选择的特征,在实际训练模型中表现如何,输入代码如下:
X_test_sfm = sfm.transform(X_test_scaled)
mlpr_sfm=MLPRegressor(random_state=62, hidden_layer_sizes=(100,100),
alpha=0.001)
mlpr_sfm.fit(X_train_sfm, y_train)
print('随机森林进行特征选择后的模型得分:{:.2f}'.format(
mlpr_sfm.score(X_test_sfm, y_test)))
运行代码,得到如下结果:
随机森林进行特征选择后的模型得分:0.97
结果分析:从结果中看出,使用随机森林模型进行特征选择之后,在其他参数都不变的情况下,模型的得分比使用单一变量法进行特征选择的份数高了很多,甚至比使用原始数据集的份数还要更高。
3.迭代式特征选择
迭代式特征选择的定义:
顾名思义,迭代式特征选择是基于若干个模型进行特征选择,在scikit-learn中,有一个称为递归特征剔除法(Recurise Feature Elimination,RFE)的功能就是通过这种方式来进行特征选择的。在最开始,RFE会用某个模型对特征进行选择,之后再建立两个模型,其中一个对已经被选择的特征进行筛选;另外一个对被剔除的模型进行筛选,然后一直重复这个步骤,直到达到我们制定的特征数量。这种方式笔签名我们学习的单个模型进行特征选择更加强悍,但是对计算能力的要求也比较高。
下面我们试一下用RFE对股票数据进行特征选择,看对预测结果会有什么样的影响,输入代码如下:
from sklearn.feature_selection import RFE
rfe = RFE(RandomForestRegressor(n_estimators=100,
random_state=38),
n_features_to_select=12)
rfe.fit(X_train_scaled, y_train)
mask = rfe.get_support()
print(mask)
为了和前面基于单个模型的特征选择进行比较,我们设置RFE筛选的特征数量也是12个,运行代码,看RFE保留的特征有哪些:
下面用可视化的方式表示一下,输入代码如下:
plt.matshow(mask.reshape(1,-1), cmap=plt.cm.cool)
plt.xlabel('Features Selected')
plt.show()
运行代码,如下图:
结果分析:从图中可以直观的看到,RFE选择的特征和单一变量法及基于单个模型的特征选择结果都不相同,那么RFE筛选的结果在相同的模型下,预测准确率会发生什么样的变化?
下面继续使用神经网络模型试验一下,输入代码如下:
X_train_rfe = rfe.transform(X_train_scaled)
X_test_rfe = rfe.transform(X_test_scaled)
mlpr_rfe = MLPRegressor(random_state=62, hidden_layer_sizes=(100,100),
alpha=0.001)
mlpr_rfe.fit(X_train_rfe, y_train)
print("RFE选择特征后的模型得分:{:.2f}".format(mlpr_rfe.score(X_test_rfe,
y_test)))
运行代码,得到模型的评分如下:
RFE选择特征后的模型得分:0.95
结果分析:从结果可以看出,使用RFE进行特征选择之后,模型得分比使用原始数据特征的得分略高,比单个模型选择的特征相比,得分基本一致。