Blending集成学习算法
简介
Blending集成学习方式如下:
(1) 将数据划分为训练集和测试集(test_set),其中训练集需要再次划分为训练集(train_set)和验证集(val_set);
在此步骤中,总的数据集被分成训练集(80%)和测试集(20%),在这80%的训练集中再拆分训练集(70%)和验证集(30%)。因此拆分后的数据集由三部分组成:训练集80%* 70% 、测试集20%、验证集80%* 30% 。训练集是为了训练模型,测试集是为了调整模型(调参),测试集则是为了检验模型的优度。
(2) 创建第一层的多个模型,这些模型可以使同质的也可以是异质的;
(3) 使用train_set训练步骤2中的多个模型,然后用训练好的模型预测val_set和test_set得到val_predict, test_predict1;
在2-3步中,使用训练集创建K个模型,如SVM/random forests, XGBoost等作为第一层的模型。训练好的模型将验证集输入模型进行预测,得到K组不同的输出(记作A_1,…,A_K),然后将测试集输入K个模型也得到K组输出(记作B_1,…,B_K),其中(A_i的样本数与验证集一致,B_i的样本数与测试集一致。
如果总的样本数有10000个样本,那么使用5600个样本训练了K个模型,输入验证集2400个样本得到K组2400个样本的结果A_1,…,A_K,输入测试集2000个得到K组2000个样本的结果B_1,…,B_K。
(4) 创建第二层的模型,使用val_predict作为训练集训练第二层的模型;
使用K组2400个样本的验证集结果A_1,…,A_K作为第二层分类器的特征,验证集的2400个标签为因变量,训练第二层分类器,得到2400个样本的输出。
(5) 使用第二层训练好的模型对第二层测试集test_predict1进行预测,该结果为整个测试集的结果。
将输入测试集2000个得到K组2000个样本的结果B_1,…,B_K放入第二层分类器,得到2000个测试集的预测结果。
示例
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
plt.style.use("ggplot")
%matplotlib inline
import seaborn as sns
from sklearn import datasets
from sklearn.datasets import make_blobs
from sklearn.model_selection import train_test_split
data,target=make_blobs(n_samples=10000, centers=2, random_state=1,cluster_std=1.0)
X_train1, X_test, y_train1, y_test=train_test_split(data,target,test_size=0.2,random_state=1)
X_train,X_val,y_train,y_val=train_test_split(X_train1,y_train1,test_size=0.3,random_state=1)
#第一层分类器
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
from sklearn.neighbors import KNeighborsClassifier
clfs=[SVC(probability=True),RandomForestClassifier(n_estimators=5, n_jobs=-1, criterion='gini'), KNeighborsClassifier()]
#第二层分类器
from sklearn.linear_model import LinearRegression
lr=LinearRegression()
#第一层的验证集结果与测试集结果
val_features=np.zeros((X_val.shape[0],len(clfs)))
test_features=np.zeros((X_test.shape[0],len(clfs)))
for i, clf in enumerate(clfs):
clf.fit(X_train,y_train)
val_feature = clf.predict_proba(X_val)[:, 1]
test_feature = clf.predict_proba(X_test)[:,1]
val_features[:,i] = val_feature
test_features[:,i] = test_feature
# 将第一层的验证集的结果输入第二层训练第二层分类器
lr.fit(val_features,y_val)
# 输出预测的结果
from sklearn.model_selection import cross_val_score
cross_val_score(lr,test_features,y_test,cv=5)
array([1., 1., 1., 1., 1.])
参考
Stacking集成学习算法
简介
在Blending中,产生验证集的方式是使用分割的方式,产生一组训练集和一组验证集,如果采用交叉验证的方式对数据多次利用呢?
- 首先将所有数据集生成测试集和训练集(假如训练集为10000,测试集为2500行),那么上层会进行5折交叉检验,使用训练集中的8000条作为训练集,剩余2000行作为验证集(橙色)。
- 每次验证相当于使用了蓝色的8000条数据训练出一个模型,使用模型对验证集进行验证得到2000条数据,并对测试集进行预测,得到2500条数据,这样经过5次交叉检验,可以得到中间的橙色的5* 2000条验证集的结果(相当于每条数据的预测结果),5* 2500条测试集的预测结果。
- 接下来会将验证集的52000条预测结果拼接成10000行长的矩阵,标记为 𝐴1 ,而对于52500行的测试集的预测结果进行加权平均,得到一个2500一列的矩阵,标记为 𝐵1 。
- 上面得到一个基模型在数据集上的预测结果 𝐴1 、 𝐵1 , 这样当我们对3个基模型进行集成的话,相于得到了 𝐴1 、 𝐴2 、 𝐴3 、 𝐵1 、 𝐵2 、 𝐵3六个矩阵。
- 之后将 𝐴1 、 𝐴2 、 𝐴3 并列在一起成10000行3列的矩阵作为training data, 𝐵1 、𝐵2 、 𝐵3 合并在一起成2500行3列的矩阵作为testing data,让下层学习器基于这样的数据进行再训练。
- 再训练是基于每个基础模型的预测结果作为特征(三个特征),次学习器会学习训练如果往这样的基学习的预测结果上赋予权重w,来使得最后的预测最为准确。
示例
#3折CV分类
from sklearn import datasets
iris = datasets.load_iris()
X, y = iris.data[:, 1:3], iris.target
from sklearn.model_selection import cross_val_score
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from mlxtend.classifier import StackingCVClassifier
RANDOM_SEED = 42
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=RANDOM_SEED)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf = StackingCVClassifier(classifiers=[clf1, clf2, clf3], # 第一层分类器
meta_classifier=lr, # 第二层分类器
random_state=RANDOM_SEED)
print('3-fold cross validation:\n')
for clf, label in zip([clf1, clf2, clf3, sclf], ['KNN', 'Random Forest', 'Naive Bayes','StackingClassifier']):
scores = cross_val_score(clf, X, y, cv=3, scoring='accuracy')
print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
3-fold cross validation:
Accuracy: 0.91 (+/- 0.01) [KNN]
Accuracy: 0.90 (+/- 0.03) [Random Forest]
Accuracy: 0.92 (+/- 0.03) [Naive Bayes]
Accuracy: 0.93 (+/- 0.02) [StackingClassifier]
#决策边界
#参考:http://rasbt.github.io/mlxtend/user_guide/plotting/plot_decision_regions/
from mlxtend.plotting import plot_decision_regions
import matplotlib.gridspec as gridspec
import itertools
import matplotlib.pyplot as plt
%matplotlib inline
gs=gridspec.GridSpec(2,2)
fig=plt.figure(figsize=(10,8))
for clf,lable,grd in zip([clf1,clf2,clf3,sclf],
['kNN',
'Random Forest',
'Naive Bayes',
'StackingCVClassifier'],
itertools.product([0,1],repeat=2)):
clf.fit(X,y)
ax=plt.subplot(gs[grd[0],grd[1]])
fig=plot_decision_regions(X=X, y=y, clf=clf)
plt.title(label)
plt.show()
#使用概率作为元特征
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=1)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf=StackingCVClassifier(classifiers=[clf1,clf2,clf3],
use_probas=True,
meta_classifier=lr,
random_state=42)
print('3-fold cross validation:\n')
for clf, label in zip([clf1, clf2, clf3, sclf],
['KNN',
'Random Forest',
'Naive Bayes',
'StackingClassifier']):
scores = cross_val_score(clf, X, y,cv=3, scoring='accuracy')
print("Accuracy: %0.2f (+/- %0.2f) [%s]" % (scores.mean(), scores.std(), label))
3-fold cross validation:
Accuracy: 0.91 (+/- 0.01) [KNN]
Accuracy: 0.93 (+/- 0.05) [Random Forest]
Accuracy: 0.92 (+/- 0.03) [Naive Bayes]
Accuracy: 0.95 (+/- 0.04) [StackingClassifier]
使用第一层所有基分类器所产生的类别概率值作为meta-classfier的输入。需要在StackingClassifier 中增加一个参数设置:use_probas = True。
另外,还有一个参数设置average_probas = True,那么这些基分类器所产出的概率值将按照列被平均,否则会拼接。
例如:
基分类器1:predictions=[0.2,0.2,0.7]
基分类器2:predictions=[0.4,0.3,0.8]
基分类器3:predictions=[0.1,0.4,0.6]
1)若use_probas = True,average_probas = True,
则产生的meta-feature 为:[0.233, 0.3, 0.7]
2)若use_probas = True,average_probas = False,
则产生的meta-feature 为:[0.2,0.2,0.7,0.4,0.3,0.8,0.1,0.4,0.6]
#5折CV分类结合网格搜索调参优化
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import GridSearchCV
from mlxtend.classifier import StackingCVClassifier
clf1 = KNeighborsClassifier(n_neighbors=1)
clf2 = RandomForestClassifier(random_state=RANDOM_SEED)
clf3 = GaussianNB()
lr = LogisticRegression()
sclf = StackingCVClassifier(classifiers=[clf1, clf2, clf3],
meta_classifier=lr,
random_state=42)
params = {'kneighborsclassifier__n_neighbors': [1, 5],
'randomforestclassifier__n_estimators': [10, 50],
'meta_classifier__C': [0.1, 10.0]}
grid = GridSearchCV(estimator=sclf,
param_grid=params,
cv=5,
refit=True)
grid.fit(X, y)
cv_keys = ('mean_test_score', 'std_test_score', 'params')
for r, _ in enumerate(grid.cv_results_['mean_test_score']):
print("%0.3f +/- %0.2f %r"
% (grid.cv_results_[cv_keys[0]][r],
grid.cv_results_[cv_keys[1]][r],
grid.cv_results_[cv_keys[2]][r]))
print('Best parameters: %s' % grid.best_params_)
print('Accuracy: %.2f' % grid.best_score_)
# 4.在不同特征子集上运行的分类器的堆叠,不同的1级分类器可以适合训练数据集中的不同特征子集。
from mlxtend.classifier import StackingCVClassifier
from mlxtend.feature_selection import ColumnSelector
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression
from sklearn.datasets import load_iris
iris = load_iris()
X = iris.data
y = iris.target
pipe1 = make_pipeline(ColumnSelector(cols=(0, 2)), # 选择第0,2列
LogisticRegression())
pipe2 = make_pipeline(ColumnSelector(cols=(1, 2, 3)), # 选择第1,2,3列
LogisticRegression())
sclf = StackingCVClassifier(classifiers=[pipe1, pipe2],
meta_classifier=LogisticRegression(),
random_state=42)
sclf.fit(X, y)
ROC曲线(过程略)
参考
http://rasbt.github.io/mlxtend/user_guide/regressor/StackingCVRegressor/
https://machinelearningmastery.com/stacking-ensemble-machine-learning-with-python/