用Bagging优化模型的过程:
1、对于要使用的弱模型(比如线性分类器、岭回归),通过交叉验证的方式找到弱模型本身的最好超参数;
2、然后用这个带着最好超参数的弱模型去构建强模型;
3、对强模型也是通过交叉验证的方式找到强模型的最好超参数(比如弱模型的数量)
对于Bagging、RandomForest、Boosting这些组合算法,默认是用的弱模型是决策树,但是可以通过base_estimator参数调整。
1、查看数据,数据预处理
读入数据
train_df = pd.read_csv(filename,index_col=0)
dataframe.head()
观察数据分布
对于连续型数值变量,查看的是直方图。
对于分类型变量,查看的是频数图。其实和直方图差不多。
首先,查看因变量(y,房价)的分布,看原始分布的时候,还做了个转换,对房价取了个对数。同时查看两状态下的数据分布。
之所以看分布和做转换,是因为用线性回归有个条件是因变量符合正态分布,如果不是的话,最好做个平滑处理,让其尽可能符合高斯分布,否则效果不会好。
%matplotlib inline
pricesDf = pd.DataFrame( {"price":df['salePrice'] ,"log_price+1":np.log1p(df['salePrice']) })
这行代码其实是用原始数据中的房价和取对数后的房价创建了个新的DataFrame
log1p就是 log(x+1),可以避免出现负数结果,逼格很高。
不过,如果用平滑后的价格做模型,那么做预测时,预测结果也不要忘记反向操作,反向函数就是expm1,log反向是exp
priceDf.hist()
然后用柱状图绘制分布
测试数据和训练数据合并
合并的目的是后续的特征处理时,就一并把训练集和测试集的一并转换了。
当然,最后训练的时候还是要用训练数据集,验证时还是要用测试数据集。我们就直接用train_df.index和test_df.index把它们再提取出来就好了。
all_df = pd.concat((train_df,test_df), axis=0)
2、特征工程
把分类型变量数字化
当用数值型变量表达分类变量时,由于数字本身有大小的含义,所以乱给数字会给后来的模型学习带来麻烦,所以对于分类型变量,更好的方法是one-hot编码。
pandas方法
all_df['columnname'].value_count()
pd.get_dummies(all_df ['columnname'] , prefix='SomePrefix' ).head()
得到的one-hot column的名字是'SomePrefix_value'的样式
也可以一次性对所有分类变量one-hot
all_dummy_df = all_df.get_dummies(all_df)
all_dummy_df.head()
对数值变量的处理
首当其冲就是对缺失值的处理。
缺失值的处理
查看缺失值最多的列
all_dummy_df.isnull().sum().sort_values(ascending=False).head()
对于缺失值的处理,需要根据具体的情况作处理。
比如,用均值填充
mean_cols=all_dummy_df.mean()
mean_cols.head(10)
用均值填充
all_dummy_df.fillna(mean_cols,inplace=True) 就地填充
数据分布标准化处理
并不是所有的模型都需要做数据分布的标准化处理,但是像回归模型比较娇贵,最好把自变量放在一个标准正态分布里,不要让数据的差距太大。
当然对于哪些one-hot的列,因为只有0,1两个值,所以不需要标准化,我们的目标应该只是那些本来就是数值型变量。
先看哪些列是数值型的
numeric_cols = all_df.columns[add_df.dtypes != 'object']
这些列就是数值型列的索引
计算标准分布: (x-x`)/s
numeric_col_means = all_dummy_df.loc[:,numeric_cols].mean()
numeric_col_std = all_dummy_df.loc[:,numeric_cols].std()
all_dummy_df.loc[:,numeric_cols]=(all_dummy_df.loc[:,numeric_cols] - umeric_col_means) / numeric_col_std
3、建立模型
数据集分成训练/测试集
train_df=all_dummy_df.loc[train_df.index]
test_df=all_dummy_df.loc[test_df.index]
把pandas的DataFrame转换成numpy的Array,只是为了和sklearn更配
x_train = train_df.values
x_test=test_df.values
剩下就是用sklearn的岭回归Ridge训练模型了,这个模型需要一个alpha超参,我们用交叉验证得到最优的参数值。
交叉验证的代码套路是固定的:
alphas = np.logspace(-3,2,50)
test_scores=[]
for alpha in alphas:
clf = Ridge(alpha)
test_scores=np.sqrt(cross_val_score(clf,X_train,y_train,cv=10,scoring='neg_mean_squared_error'))
test_scores.append(np.mean(test_score))
这段代码运行完毕后,我们有两个列表,一个是alphas列表,一个是test_scores列表。用这两个列表画一个折线图,我们就可以观察到在alpha取什么值的时候,误差最小。
同样的数据集,也可以用RandomForestRegressor来做回归。这个模型有两个超参数,最大特征个数、最大采样数量。
max_features=[.1 ,.3 ,.5 ,.7 ,.9 ,.99]
test_scores=[]
for max_feat in max_features:
clf = RandomForestRegressor(n_estimators=200,max_features=max_feat)
#n_estimators 代表要多少棵树
test_scores=np.sqrt(-cross_val_score(clf,X_train,y_train,cv=5,scoring='neg_mean_squared_error')
test_scores.append(np.mean(test_scores))
通过交叉验证,我们可以找到两个模型的最佳超参数。
4、模型融合
简单的我们可以用bagging的方法,把两个模型最好测参数拿出来,组合成最终的model。每个模型都做个预测值,最终两个模型的预测值取平均。
5、提交结果
走你~
6、进阶优化 用高级的模型融合
一般来说,单个分类器的效果有效,我们会倾向于把N多的分类器合在一起,做一个综合分类器达到最好的效果。
sklearn中已经有现成框架,在sklearn.ensemble中,有bagging有Boosting。Bagging和Bossting又都有回归和分类之分。把bagging用在回归上,也是同时得到多个回归模型,比如这个案例中我们用Ridge做回归器,最后就是得到多个Ridge。
Bagging缺省的用的是DecisionTree,通过改变base_estimator参数的值就可以修改弱模型的类型了。
from sklearn.ensemble import BaggingRegressor
之前,我们通过交叉验证的方法,得到了Ridge岭回归alpha参数的最佳值。
我们就可以用这个最佳参数作为小分类器。
from sklearn.linear_model import Ridge
ridge = Ridge(alpha=15)
而我们在接下来是用Bagging时,同样是要用交叉验证,训练出来的其实是小分类器的个数的最佳值。
我们先定义小分类器的个数
params = [1,10,15,20,25,30,40]
....
找到最佳的小回归器的数量。
大杀器,xgboost
可以用xgboost,而且xgboost可以用一样的模式嵌入到sklearn中,代码套路完全一样
from xgboost import XGBRegressor
params = [1,2,3,4,5]
for param in params :
clf = XGBRegressor(max_depth=param)
test_score = np.sqrt(-cross_val_score(clf,x_train,y_train,cv=10,scoring=‘neg_mean_squared_error') )
test_scores.append(test_score)
完全一样的代码套路。