赞
踩
无论是对于什么数据都存在两个非常经典的问题:问题一是,数据与标签之间,数据与数据之间的一些实际关系很难搞清楚。有些时候特征A,特征B可能都与标签存在正向关系。然而实际上的关系却可能是标签与特征A,B的乘积存在实际关系;问题二,在不同机器学习的模型中,特征的最佳选择往往并不一致。比如当模型选择为模型model1的时候,特征可能为特征ABC,而当模型变为model2的时候,最佳特征可能就变为了ACD。
为了解决这两个问题,有一个比较成熟的自动化方案可供我们使用。那就是多项式特征生成与自动特征选择。
这里我们借助sklearn中的多项式特征生成(sklearn.preprocessing.PolynomialFeatures)与RFECV(sklearn.feature_selection.RFECV,递归式特征消除)来解决这个问题。前者的作用是自动生成多项式特征,如,x1,x2,生成特征为x1**x1,x1*x2,x2**x2
等。而递归式特征消除,则是一种利用模型进行特征消除的方法,需要模型本身带有特征的重要程度这一项,之后则不断地递归调用自身,将不重要的特征去除,直到去除某个特征后,模型的预测效果下降为止。
特征的自由组合有时会带来性能提升,但并不一定一定是有效的。更多的时候我们需要要考虑的是实际业务的需要。这里我们选择UCI的红酒质量数据集进行处理,从实际业务上来说,红酒质量数据集中的特征都是单项的红酒指标,但是实际上红酒的评分本就并非直接与单项数据成正比,有些则是与特征之间的组合或者特征的几次方成有效关系。因此我们这里就是用多项式特征生成与递归特征消除来自动获取符合实际业务的模型。
该数据的下载可以前往:http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv
首先加载有关类库
import numpy as np
from sklearn.feature_selection import RFECV
from sklearn.linear_model import LassoCV
from sklearn.metrics import mean_squared_error
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
之后创建数据加载的方法,并调用数据;要注意的是我们这里使用的train_test_split方法进行数据的分割,其中test_size=0.30,表示分割出百分之三十的数据作为测试数据集,随机数种子为random_state=531,为随机数种子赋值后我们将
def GetDataByPandas():
import pandas as pd
wine = pd.read_csv("/home/fonttian/Data/dataset/wine/wine.csv")
y = np.array(wine.quality)
X = np.array(wine.drop("quality", axis=1))
columns = np.array(wine.columns)
return X, y, columns
X, y, wineNames = GetDataByPandas()
scalar = StandardScaler()
X = scalar.fit_transform(X)
train_data, test_data, train_labels, test_labels = train_test_split(X, y, test_size=0.30, random_state=531)
之后首先使用多项式特征生成方法进行特征的自动生成,具体代码如下:
from sklearn.preprocessing import PolynomialFeatures
poly = PolynomialFeatures(2)
print("原始数据的形状:")
print(train_data.shape)
train_data_new = poly.fit_transform(train_data)
test_data_new = poly.fit_transform(test_data)
print("生成多项式特征之后的数据形状:")
print(train_data_new.shape)
原始数据的形状:
(1119, 11)
生成多项式特征之后的数据形状:
(1119, 78)
此处参数2表示,特征生成的程度,如果需要生成3程度(也就是三次方和三个特征自由组合),只需要设置参数为3即可。另外还有一个参数interaction_only,表示是否只生成交互特征,如果为True,将不会生成特征与自身交互产生的特征(也就是几次方之类的),该参数默认为False。
之后我们需要选择一个模型进行数据的预测,同时为了方便观察以及避免超参数带来的偶然性。我们这里选择LassoCV方法进行建模,该方法会使用交叉验证自动选择Lasso的最佳超参数alpha,这样可以很大程度避免默认超参数对实际结果的影响。具体代码如下:
%matplotlib inline def LassoCV_plot(model): import matplotlib.pyplot as plot plot.figure() plot.plot(model.alphas_, model.mse_path_, ':') plot.plot(model.alphas_, model.mse_path_.mean(axis=-1), label='Average MSE Across Folds', linewidth=2) plot.axvline(model.alpha_, linestyle='--', label='CV Estimate of Best alpha') plot.semilogx() plot.legend() ax = plot.gca() ax.invert_xaxis() plot.xlabel('alpha') plot.ylabel('Mean Square Error') plot.axis('tight') plot.show() # print out the value of alpha that minimizes the Cv-error print("alpha Value that Minimizes CV Error ", model.alpha_) print("Minimum MSE ", min(model.mse_path_.mean(axis=-1))) # Call LassoCV from sklearn.linear_model lcv_1 = LassoCV(cv=10,n_jobs=-1) wineModel = lcv_1.fit(train_data, train_labels) LassoCV_plot(wineModel) lcv_2 = LassoCV(cv=10,n_jobs=-1) wineModel_new = lcv_2.fit(train_data_new, train_labels) LassoCV_plot(wineModel_new) estimator = LassoCV(cv=10,n_jobs=-1) selector = RFECV(estimator, step=1, cv=5,n_jobs=-1) selector = selector.fit(X, y) selector_train_data = selector.fit_transform(train_data, train_labels) test_data_selector = selector.transform(test_data)
alpha Value that Minimizes CV Error 0.005057237342969403
Minimum MSE 0.42849753501285
alpha Value that Minimizes CV Error 0.0061927974491236
Minimum MSE 0.4236178162163108
从最终结果来看,我们直接使用生成的67种特征+原11种特征进行建模的效果并不好于直接使用原11种特征,这是必然是因为产生了大量的无用特征的缘故。下一步我们就需要借助递归式特征消除进行特征选择,将真正有效的特征选择出来。
print("使用特征选择,并进行效果对比:") estimator = LassoCV(cv=10,n_jobs=-1) selector = RFECV(estimator, step=1, cv=5,n_jobs=-1) selector = selector.fit(X, y) selector_train_data = selector.fit_transform(train_data, train_labels) test_data_selector = selector.transform(test_data) print("特征选择之后数据的shape:",selector_train_data.shape) wineModel = lcv_1.fit(selector_train_data, train_labels) print("alpha Value that Minimizes CV Error ", wineModel.alpha_) print("Minimum MSE ", min(wineModel.mse_path_.mean(axis=-1))) selector_train_data_new = selector.fit_transform(train_data_new, train_labels) test_data_new_selector = selector.transform(test_data_new) print("特征选择之后数据的shape:",selector_train_data_new.shape) wineModel_new = lcv_2.fit(selector_train_data_new, train_labels) print("alpha Value that Minimizes CV Error ", wineModel_new.alpha_) print("Minimum MSE ", min(wineModel_new.mse_path_.mean(axis=-1)))
使用特征选择,并进行效果对比:
特征选择之后数据的shape: (1119, 7)
alpha Value that Minimizes CV Error 0.0008837665882418426
Minimum MSE 0.427181140352486
特征选择之后数据的shape: (1119, 38)
alpha Value that Minimizes CV Error 0.00038256145886961614
Minimum MSE 0.4002180554706169
上面即是进行特征选择后的实际结果,可以很明显的看到,如果仅仅对原始数据进行特征选择,那么大概能够降低0.00413的平均误差以及0.001的最小MSE;但是在对生成的多项式特征进行特征选择之后,其结果则得到的极大的下降(0.00588,0.234)。而且各位重要的是进行特征选择后的多项式数据集的拟合结果已经明显高于原有数据集的拟合结果。但是除了拟合结果之外更好地应该是预测结果的变化,下面的代码则是预测结果的变化:
# 输出预测值
def show_prediction(model, X, y):
prediction = model.predict(X)
print("RMSE", np.sqrt(mean_squared_error(y, prediction)))
print("MSE", mean_squared_error(y, prediction))
show_prediction(lcv_1, test_data_selector, test_labels)
show_prediction(lcv_2, test_data_new_selector, test_labels)
RMSE 0.6440234501860966
MSE 0.4147662043896037
RMSE 0.6390612669439588
MSE 0.40839930290801785
从预测结果看,很明显经过多项式特征生成与递归特征消除的模型效果依旧要好于原有模型很多。同时更重要的地方在于,目前对于模型效果具有正面效果的数据很有可能是有意义的特殊特征组合。利用该方法我们也可以快速的获得一个可能有用特殊意义的特征组合的集合,并引导我们发现这些特殊特征组合的现实意义。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。