总体来说,良好的数据特征组合不需太多,便可以使得模型的性能表现突出。比如我们在“良/恶性乳腺癌肿瘤预测“问题中,仅仅使用两个描述肿瘤形态的特征便取得较高的识别率。冗余的特征虽然不会影响模型性能,但会浪费cpu的计算。主成分分析主要用于去除多余的那些线性相关的特征组合,这些冗余的特征组合并不会对模型训练有更多贡献。
特征筛选与PCA这类通过选择主成分对特征进行重建的方法略有区别:对于PCA而言,我们经常无法解释重建之后的特征;但是特征筛选不存在对特征值的修改,而更加侧重于寻找那些对模型的性能提升较大的少量特征。
我们在下面的代码中继续使用Titanic数据集,这次试图通过特征筛选来寻找最佳的特征组合,并且达到提高预测准确性的目标。
使用Titanic数据集,通过特征筛选的方法一步步提升决策树的预测性能
# 导入pandas并且更名为pd。
import pandas as pd
# 从互联网读取titanic数据。
titanic = pd.read_csv('http://biostat.mc.vanderbilt.edu/wiki/pub/Main/DataSets/titanic.txt')
# 分离数据特征与预测目标。
y = titanic['survived']
X = titanic.drop(['row.names', 'name', 'survived'], axis = 1)
# 对对缺失数据进行填充。
X['age'].fillna(X['age'].mean(), inplace=True)
X.fillna('UNKNOWN', inplace=True)
# 分割数据,依然采样25%用于测试。
from sklearn.cross_validation import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25, random_state=33)
# 类别型特征向量化。
from sklearn.feature_extraction import DictVectorizer
vec = DictVectorizer()
X_train = vec.fit_transform(X_train.to_dict(orient='record'))
X_test = vec.transform(X_test.to_dict(orient='record'))
# 输出处理后特征向量的维度。
print len(vec.feature_names_)
474
# 使用决策树模型依靠所有特征进行预测,并作性能评估。
from sklearn.tree import DecisionTreeClassifier
dt = DecisionTreeClassifier(criterion='entropy')
dt.fit(X_train, y_train)
dt.score(X_test, y_test)
0.81762917933130697
# 从sklearn导入特征筛选器。
from sklearn import feature_selection
# 筛选前20%的特征,使用相同配置的决策树模型进行预测,并且评估性能。
fs = feature_selection.SelectPercentile(feature_selection.chi2, percentile=20)
X_train_fs = fs.fit_transform(X_train, y_train)
dt.fit(X_train_fs, y_train)
X_test_fs = fs.transform(X_test)
dt.score(X_test_fs, y_test)
0.82370820668693012
# 通过交叉验证(下一节将详细介绍)的方法,按照固定间隔的百分比筛选特征,并作图展示性能随特征筛选比例的变化。
from sklearn.cross_validation import cross_val_score
import numpy as np
percentiles = range(1, 100, 2)
results = []
for i in percentiles:
fs = feature_selection.SelectPercentile(feature_selection.chi2, percentile = i)
X_train_fs = fs.fit_transform(X_train, y_train)
scores = cross_val_score(dt, X_train_fs, y_train, cv=5)
results = np.append(results, scores.mean())
print results
# 找到提现最佳性能的特征筛选的百分比。
opt = np.where(results == results.max())[0]
print 'Optimal number of features %d' %percentiles[opt[0]]
[0.85063904 0.85673057 0.87501546 0.88622964 0.8618223 0.86589363
0.86487322 0.86590394 0.86894455 0.87199546 0.86488353 0.86386312
0.86997526 0.86591424 0.86283241 0.87099567 0.86083282 0.86689342
0.86487322 0.86792414 0.86486291 0.86385281 0.86995465 0.86995465
0.86997526 0.87505669 0.86896516 0.86691404 0.86588332 0.86792414
0.87198516 0.86895485 0.87201608 0.87302618 0.86791383 0.86689342
0.86792414 0.87299526 0.86894455 0.86996496 0.86692435 0.86587302
0.8597918 0.86895485 0.86389404 0.86285302 0.85876108 0.86487322
0.85779221 0.8608122 ]
Optimal number of features 7
import pylab as pl
pl.plot(percentiles, results)
pl.xlabel('percentiles of features')
pl.ylabel('accuracy')
pl.show()
# 使用最佳筛选后的特征,利用相同配置的模型在测试集上进行性能评估。
from sklearn import feature_selection
fs = feature_selection.SelectPercentile(feature_selection.chi2, percentile=7)
X_train_fs = fs.fit_transform(X_train, y_train)
dt.fit(X_train_fs, y_train)
X_test_fs = fs.transform(X_test)
dt.score(X_test_fs, y_test)
0.8571428571428571
通过上面代码的几个关键输出,我们可以总结如下:
- 经过初步的特征处理后,最终的训练与测试数据均有474个维度的特征;
- 如果直接使用全部474个特征用于训练决策树模型进行分类预测,那么模型在测试集上的准确性约为81.76%;
- 如果筛选前20%维度的特征,在相同的模型配置下进行预测,那么在测试集上的准确性约为82.37%;
- 如果按照固定间隔采用不同百分比的特征进行训练和测试,作图后可发现,通过交叉验证得出的准确性有很大的波动,并且最好的模型性能表现在选取前7%的维度特征的时候;
- 如果使用7%的特征,那么最终决策树模型在该分类预测任务的测试集上表现出85.71%的准确性,比起最初使用全部特征的模型性能高出接近4个百分点。