集成算法介绍

森林里有很多树

通俗理解:
集成算法就是以各种形式将多种感知器算法揉搓成一个打算法,在实际应用中有,揉搓方式一般有:

  • Bagging:以随机森林为代表。
  • Boosting:Adaboost和Xgboost为代表,
  • stacking:使用不同分类器得到的结果同时作为第二次训练的输入

随机森林的简单介绍

例如:建立三课决策树,从100个样本里有放回的选择60到80个样本,分别放入三棵决策树中。在决策树选择特征的时候,也是从10里选择6到8特征。然后三棵树之间不存在相互影响,并行计算得到的分数按照上述公式取平均值即可得到最终结果。

特征重要性评估

例如:一批数据有ABCD四个特征,若想知道B特征对整个评估标准的重要程度,

  1. 首先使用这四个特征进行模型训练,得到错误率error1。
  2. 之后经过某种算法,破坏B特征中属性值的规律性,使B变成B',使用AB’CD进行训练得到error2。
  3. 若error1近似error2,证明B特征没什么用,如果error2>>error1,证明B特征重要。
  4. 在确认B特征确实无用后,在训练模型时可以去掉B特征。

⚠️:在实际使用中,并不是树越多越好。应该具体场景具体分析。

boosting简单介绍

假如:

  1. 有一个小偷,他此次真实偷取了1000块钱(真实的y值),
  2. 警察建立了一棵树,预测后他此次能偷取950块钱(预测目标其实想达到1000)
  3. 然后警察计算出了残差值R=1000-950=50,然后建立第二棵树,目标是结果要接近残差值50,结果得到了30。
  4. 再次计算与上一次的残差R=50-30=20,建立第三棵树,目标是结果要接近新的残差值20,结果得到15。
  5. 目前为止已经预测到的值为950+30+15=995,这个值看上去已经很漂亮了
Adaboost简单介绍

假如:

  1. 有一批数据,随机切分成5份为ABCDE,对应5个分类器
  2. 将每批数据分别赋予权重0.2,在进行一次预测后,ABDE都预测对了,而C预测错了。
  3. 根据预测结果,调整程序,加大对错误数据的权重,减轻预测正确的数据权重。如0.1_0.1_0.6_0.1_0.1。
  4. 经过新的权重训练后进行预测,可能会出现别的数据集预测错误的情况,那么继续调整相应权重,以此类推。

集成算法工具包推荐:ml-ens

ROC和AUC介绍

简单回顾一下混淆矩阵,横坐标是预测值,纵坐标是真实的ylabel。

真\预 0 1
0 TN FP
1 FN TP







roc曲线

AUC即为图中阴影面积,如图可知,面积越大,即AUC值越大,证明预测效果越好。

⚠️:经过实践,我们发现使用集成算法,在处理数据的时候,只要你牛逼,可以根据自己需要调整到很高的精度和很高的泛化能力,但是计算量真的不小,所以集成算法不适合处理实时数据。。

代码展示

以下,使用美国党派捐赠情况表,来通过各个特征预测某一次捐赠可能属于哪个党派的行为。表结构和部分数据为:


表结构和部分数据展示
  • 老样子,导入数据集,切分数据,同时将部分数据离散化,one-hot编码
SEED = 222
np.random.seed(SEED)

df = pd.read_csv('input.csv')

# 切分数据集
def get_train_test(test_size=0.95):

    y = 1 * (df.cand_pty_affiliation == "REP") # 标签值转变0。1值
    X = df.drop(["cand_pty_affiliation"], axis=1) #制作X,所以去掉y的那一列
    X = pd.get_dummies(X) #属性值离散化
    X.drop(X.columns[X.std() == 0], axis=1, inplace=True) #去掉标准差为0的列(因为这样的数据对程序没卵用)
    return train_test_split(X, y, test_size=test_size, random_state=SEED)

print("\nExample data:")
print(df.head())

xtrain, xtest, ytrain, ytest = get_train_test()
  • 查看两个党派的具体分布
df.cand_pty_affiliation.value_counts(normalize=True).plot(
    kind="bar", title="Share of No. donations")
plt.show()
两党数据分布
  • 构建一棵3层的决策树,并计算出AUC值
#打印出决策树的图片
def print_graph(clf, feature_names):
    graph = export_graphviz(
        clf,
        label="root",
        proportion=True,
        impurity=False,
        out_file=None,
        feature_names=feature_names,
        class_names={0: "D", 1: "R"},
        filled=True,
        rounded=True
    )
    graph = pydotplus.graph_from_dot_data(graph)
    img = Image(graph.create_png())
    graph.write_png("partycontri.png")
    return img

#构建深度为3的决策树
t2 = DecisionTreeClassifier(max_depth=3, random_state=SEED)
t2.fit(xtrain, ytrain)
p = t2.predict_proba(xtest)[:, 1]

#计算出AUC
print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.751
#绘制出决策树的图片,根据图中内容发现过拟合,
print_graph(t2, xtrain.columns)
三层决策树

我们可以发现,绝大部分数据通过预测,都落入了DEM里,这样的树极有可能出现过拟合现象。如果出现这种情况,我们可以通过去掉决策能力最强的Transaction_amt后重新建立第二个树模型,来看一看接下来会发生怎样的情况。

#去掉先前最重要特征,再看看新决策树是否会有好转
drop = ["transaction_amt"]
xtrain_slim = xtrain.drop(drop, axis=1)
xtest_slim = xtest.drop(drop, axis=1)
t3 = DecisionTreeClassifier(max_depth=3, random_state=SEED)
t3.fit(xtrain_slim, ytrain)
p = t3.predict_proba(xtest_slim)[:, 1]
print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.740
print_graph(t3, xtrain_slim.columns)
第二棵三层树模型
  • 不好意思打脸了。。。那么既然是介绍集成算法,不妨我们把两棵树集成起来,使用bagging思想,看一下有没有好转。
#使用bagging思想,手动求平均分
p1 = t2.predict_proba(xtest)[:, 1]
p2 = t3.predict_proba(xtest_slim)[:, 1]
p = np.mean([p1, p2], axis=0)#计算平均值
print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.783

我们发现AUC明显变高了。

  • 既然是两棵树集成的模型,不如我们直接使用随机森林,因为sklearn里有现成的随机森林库,代码少,活还好。
'''
max_features:随机森林允许单个决策树使用特征的最大数量。 Python为最大特征数提供了多个可选项。 下面是其中的几个:
    Auto/None :简单地选取所有特征,每颗树都可以利用他们。这种情况下,每颗树都没有任何的限制。
    sqrt :此选项是每颗子树可以利用总特征数的平方根个。 例如,如果变量(特征)的总数是100,所以每颗子树只能取其中的10个。“log2”是另一种相似类型的选项。
    0.2:此选项允许每个随机森林的子树可以利用变量(特征)数的20%。如果想考察的特征x%的作用, 我们可以使用“0.X”的格式
'''
rf = RandomForestClassifier(
    n_estimators=10,#搞10棵树
    max_features=3,
    random_state=SEED
)

rf.fit(xtrain, ytrain)
p = rf.predict_proba(xtest)[:, 1]
print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.844

AUC的值明显比之前又搞出了好多。

  • 接下来开始作死,尝试用不同分类器进行集成,得到一个庞大分类器,进行预测看看效果。一下包含两个方法,建立
#构建基础分类器(分类器大合集)
def get_models():

    nb = GaussianNB()
    svc = SVC(C=100, probability=True)
    knn = KNeighborsClassifier(n_neighbors=3)
    lr = LogisticRegression(C=100, random_state=SEED)
    nn = MLPClassifier((80, 10), early_stopping=False, random_state=SEED)
    gb = GradientBoostingClassifier(n_estimators=100, random_state=SEED)
    rf = RandomForestClassifier(n_estimators=10, max_features=3, random_state=SEED)

    models = {'svm': svc,
              'knn': knn,
              'naive bayes': nb,
              'mlp-nn': nn,
              'random forest': rf,
              'gbm': gb,
              'logistic': lr,
              }

    return models

#训练模型
def train_predict(model_list):

    P = np.zeros((ytest.shape[0], len(model_list))) # 初始化好结果集框架
    P = pd.DataFrame(P)

    print("Fitting models.")
    cols = list()
    for i, (name, m) in enumerate(model_list.items()):
        print("%s..." % name, end=" ", flush=False)
        m.fit(xtrain, ytrain)
        P.iloc[:, i] = m.predict_proba(xtest)[:, 1]
        cols.append(name)
        print("done")

    P.columns = cols #设置表头

    print("Done.\n")
    return P

#评估
def score_models(P, y):
    print("Scoring models.")
    for m in P.columns:
        score = roc_auc_score(y, P.loc[:, m]) #P.loc[:, m]含义:取列名为m的列的所有行(即取出名为m的列)
        print("%-26s: %.3f" % (m, score))
    print("Done.\n")

#开始作死
models = get_models()
P = train_predict(models)
score_models(P, ytest)

通过预测,我们得到了一下结果:

Scoring models.
svm                       : 0.845
knn                       : 0.779
naive bayes               : 0.803
mlp-nn                    : 0.873
random forest             : 0.844
gbm                       : 0.878
logistic                  : 0.853

直接取个平均值。这里仍然使用的是bagging思想

print("Ensemble ROC-AUC score: %.3f" % roc_auc_score(ytest, P.mean(axis=1)))#bagging一下,0.884

AUC提升至0.884。

  • 另外,我们可以通过mlens库,通过各算法产生的结果,反推出各个算法之间的相关性:
#使用mlens将集成算法的关系和计算结果可视化
corrmat(P.corr(), inflate=False)
plt.show()
相关性
  • 同学们可以看到,之前一直使用AUC进行模型评估,那么以上各个算法的ROC曲线到底长啥样?集成算法的ROC又长啥样?
#绘制roc曲线,y值,预测值,集成值,标签名列表,集成标签名
def plot_roc_curve(ytest, P_base_learners, P_ensemble, labels, ens_label):
    plt.figure(figsize=(10, 8))
    plt.plot([0, 1], [0, 1], 'k--') #'‐‐' 破折线

    cm = [plt.cm.rainbow(i)
          for i in np.linspace(0, 1.0, P_base_learners.shape[1] + 1)] #7个单独算法+1个集成算法

    for i in range(P_base_learners.shape[1]):
        p = P_base_learners[:, i]
        fpr, tpr, _ = roc_curve(ytest, p)
        plt.plot(fpr, tpr, label=labels[i], c=cm[i + 1])

    fpr, tpr, _ = roc_curve(ytest, P_ensemble)
    plt.plot(fpr, tpr, label=ens_label, c=cm[0])

    plt.xlabel('False positive rate')
    plt.ylabel('True positive rate')
    plt.title('ROC curve')
    plt.legend(frameon=False)
    plt.show()

plot_roc_curve(ytest, P.values, P.mean(axis=1), list(P.columns), "ensemble")
ROC曲线
  • 我们也可以展示出不同算法计算出的REP(真值)占比
#各个算法预测的共和党占比
p = P.apply(lambda x: 1*(x >= 0.5).value_counts(normalize=True))
p.index = ["DEM", "REP"]
p.loc["REP", :].sort_values().plot(kind="bar")
plt.axhline(0.25, color="k", linewidth=0.5)
plt.text(0., 0.23, "True share republicans")
plt.show()
各算法预测的REP占比

通过图像,我们可以看到,svm和mpl-nn预测出的占比和实际数据差太多了,索性干掉他们俩。操作的话,这里不做解释了,删掉相关代码即可。

  • 那么每次都要通过观察来删掉不好的算法,太人工了,一点也不智能。那么我们可以使用stacking的方式进行操作,在大集合算法拿到的预测值,再找一个装B的算法进行二阶段的训练,来调整每个算法的权重配比。
meta_learner = GradientBoostingClassifier(#第二阶段分类器
    n_estimators=1000,
    loss="exponential",
    max_features=4,
    max_depth=3,
    subsample=0.5,
    learning_rate=0.005,
    random_state=SEED
)
  • 当第一阶段的结果在第二阶段继续训练,已经产生了权重上的倾斜,即嚼过的饭再嚼一次,很容易出现过拟合,可采用交叉验证的思想。将训练集一分为二。

1.用交叉训练集训练模型,
2.交叉验证集产生第二阶段的输入即可解决(毕竟交叉验证集没有进行反向传播调整权重)

#切分交叉训练集和验证集
xtrain_base, xpred_base, ytrain_base, ypred_base = train_test_split(
    xtrain, ytrain, test_size=0.5, random_state=SEED)

#训练模型方法
def train_base_learners(base_learners, inp, out, verbose=True):
    if verbose: print("Fitting models.")
    for i, (name, m) in enumerate(base_learners.items()):
        if verbose: print("%s..." % name, end=" ", flush=False)
        m.fit(inp, out)
        if verbose: print("done")


# 第一阶段预测出作为第二阶段输入的值
def predict_base_learners(pred_base_learners, inp, verbose=True):

    P = np.zeros((inp.shape[0], len(pred_base_learners)))

    if verbose: print("Generating base learner predictions.")
    for i, (name, m) in enumerate(pred_base_learners.items()):
        if verbose: print("%s..." % name, end=" ", flush=False)
        p = m.predict_proba(inp)

        P[:, i] = p[:, 1]
        if verbose: print("done")

    return P

#对stacking模型进行训练
def ensemble_predict(base_learners, meta_learner, inp, verbose=True):

    P_pred = predict_base_learners(base_learners, inp, verbose=verbose)
    return P_pred, meta_learner.predict_proba(P_pred)[:, 1]

#开始训练
train_base_learners(base_learners, xtrain_base, ytrain_base)
#交叉预测,可拿到第二阶段的输入
P_base = predict_base_learners(base_learners, xpred_base)
#在第二阶段进行各个算法的权重训练,即完成对mata_learner的训练
meta_learner.fit(P_base, ypred_base)
#用测试集进行最终测试
P_pred, p = ensemble_predict(base_learners, meta_learner, xtest)
print("\nEnsemble ROC-AUC score: %.3f" % roc_auc_score(ytest, p)) #0.880

但我们发现效果并没有好多少,那是因为我们在训练阶段拿到的数据少了一半,效果肯定不好啊!那么我们可以采用真正的交叉验证来解决这种粗暴的拆分方式,具体代码这里不写了,请参考另一篇文章离散型随机变量的二分类预测案例
,里面有关于交叉验证具体的操作代码。

  • 然而之前推荐的mlens库中自带了集成算法的框架,就和随机森林一样,不用我们这样造轮子了,里面已经写好了并行训练多分类器,交叉验证等操作,上代码:
from mlens.ensemble import SuperLearner

# 集成算法分类器
sl = SuperLearner(
    folds=10,
    random_state=SEED,
    verbose=2,
    backend="multiprocessing"
)

# 指定各阶段的算法
sl.add(list(base_learners.values()), proba=True)
sl.add_meta(meta_learner, proba=True)

# 训练
sl.fit(xtrain, ytrain)

# 评分
p_sl = sl.predict_proba(xtest)

print("\nSuper Learner ROC-AUC score: %.3f" % roc_auc_score(ytest, p_sl[:, 1]))#0.889

效果不错。
以上内容介绍了集成算法的一些思想,通过代码从决策树,随机森林,stacking等角度实践了预测方法,对于数据的预处理没有进行过多操作。
完整代码:

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
import pydotplus
from IPython.display import Image
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn.ensemble import RandomForestClassifier
from mlens.visualization import corrmat
from sklearn.metrics import roc_curve


# 指定随机种子
SEED = 222
np.random.seed(SEED)

df = pd.read_csv('input.csv')

# 切分数据集
def get_train_test(test_size=0.95):

    y = 1 * (df.cand_pty_affiliation == "REP") # 标签值转变0。1值
    X = df.drop(["cand_pty_affiliation"], axis=1) #制作X,所以去掉y的那一列
    X = pd.get_dummies(X) #属性值离散化
    X.drop(X.columns[X.std() == 0], axis=1, inplace=True) #去掉标准差为0的列(因为这样的数据对程序没卵用)
    return train_test_split(X, y, test_size=test_size, random_state=SEED)

print("\nExample data:")
print(df.head())

xtrain, xtest, ytrain, ytest = get_train_test()



# #以占比形式展示两个党派的数据分布,normalize=True:以百分比形式展示
# df.cand_pty_affiliation.value_counts(normalize=True).plot(
#     kind="bar", title="Share of No. donations")
# plt.show()



# #打印出决策树的图片
# def print_graph(clf, feature_names):
#     graph = export_graphviz(
#         clf,
#         label="root",
#         proportion=True,
#         impurity=False,
#         out_file=None,
#         feature_names=feature_names,
#         class_names={0: "D", 1: "R"},
#         filled=True,
#         rounded=True
#     )
#     graph = pydotplus.graph_from_dot_data(graph)
#     img = Image(graph.create_png())
#     graph.write_png("partycontri.png")
#     return img
#
# #构建深度为3的决策树
# t2 = DecisionTreeClassifier(max_depth=3, random_state=SEED)
# t2.fit(xtrain, ytrain)
# p = t2.predict_proba(xtest)[:, 1]
#
# #计算出AUC
# print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.751
# #绘制出决策树的图片,根据图中内容发现过拟合,
# # print_graph(t2, xtrain.columns)
#
#
# #去掉先前最重要特征,再看看新决策树是否会有好转
# drop = ["transaction_amt"]
# xtrain_slim = xtrain.drop(drop, axis=1)
# xtest_slim = xtest.drop(drop, axis=1)
# t3 = DecisionTreeClassifier(max_depth=3, random_state=SEED)
# t3.fit(xtrain_slim, ytrain)
# p = t3.predict_proba(xtest_slim)[:, 1]
# print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.740
# print_graph(t3, xtrain_slim.columns)
#
# #开始集成部分!
# #使用bagging思想,手动求平均分
# p1 = t2.predict_proba(xtest)[:, 1]
# p2 = t3.predict_proba(xtest_slim)[:, 1]
# p = np.mean([p1, p2], axis=0)#计算平均值
# print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))#0.783


#使用bagging思想,使用sklearn提供的决策森林直接玩
# '''
# max_features:随机森林允许单个决策树使用特征的最大数量。 Python为最大特征数提供了多个可选项。 下面是其中的几个:
#     Auto/None :简单地选取所有特征,每颗树都可以利用他们。这种情况下,每颗树都没有任何的限制。
#     sqrt :此选项是每颗子树可以利用总特征数的平方根个。 例如,如果变量(特征)的总数是100,所以每颗子树只能取其中的10个。“log2”是另一种相似类型的选项。
#     0.2:此选项允许每个随机森林的子树可以利用变量(特征)数的20%。如果想考察的特征x%的作用, 我们可以使用“0.X”的格式
# '''
# rf = RandomForestClassifier(
#     n_estimators=10,#搞10棵树
#     max_features=3,
#     random_state=SEED
# )
#
# rf.fit(xtrain, ytrain)
# p = rf.predict_proba(xtest)[:, 1]
# print("Average of decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))


# #====================================================================================================================
#
#
# #使用bagging思想搞一个多种分类器的集成模型
from sklearn.svm import SVC, LinearSVC
from sklearn.naive_bayes import GaussianNB
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.neighbors import KNeighborsClassifier
from sklearn.neural_network import MLPClassifier
from sklearn.kernel_approximation import Nystroem
from sklearn.kernel_approximation import RBFSampler
from sklearn.pipeline import make_pipeline


#构建基础分类器(分类器大合集)
def get_models():

    nb = GaussianNB()
    svc = SVC(C=100, probability=True)
    knn = KNeighborsClassifier(n_neighbors=3)
    lr = LogisticRegression(C=100, random_state=SEED)
    nn = MLPClassifier((80, 10), early_stopping=False, random_state=SEED)
    gb = GradientBoostingClassifier(n_estimators=100, random_state=SEED)
    rf = RandomForestClassifier(n_estimators=10, max_features=3, random_state=SEED)

    models = {'svm': svc,
              'knn': knn,
              'naive bayes': nb,
              'mlp-nn': nn,
              'random forest': rf,
              'gbm': gb,
              'logistic': lr,
              }

    return models


#训练模型
def train_predict(model_list):

    P = np.zeros((ytest.shape[0], len(model_list))) # 初始化好结果集框架
    P = pd.DataFrame(P)

    print("Fitting models.")
    cols = list()
    for i, (name, m) in enumerate(model_list.items()):
        print("%s..." % name, end=" ", flush=False)
        m.fit(xtrain, ytrain)
        P.iloc[:, i] = m.predict_proba(xtest)[:, 1]
        cols.append(name)
        print("done")

    P.columns = cols #设置表头

    print("Done.\n")
    return P

#评估
def score_models(P, y):
    print("Scoring models.")
    for m in P.columns:
        score = roc_auc_score(y, P.loc[:, m]) #P.loc[:, m]含义:取列名为m的列的所有行(即取出名为m的列)
        print("%-26s: %.3f" % (m, score))
    print("Done.\n")


models = get_models()
P = train_predict(models)
score_models(P, ytest)

#使用mlens将集成算法的关系和计算结果可视化
corrmat(P.corr(), inflate=False)
plt.show()

print("Ensemble ROC-AUC score: %.3f" % roc_auc_score(ytest, P.mean(axis=1)))#bagging一下,0.884


#绘制roc曲线,y值,预测值,集成值,标签名列表,集成标签名
def plot_roc_curve(ytest, P_base_learners, P_ensemble, labels, ens_label):
    plt.figure(figsize=(10, 8))
    plt.plot([0, 1], [0, 1], 'k--') #'‐‐' 破折线

    cm = [plt.cm.rainbow(i)
          for i in np.linspace(0, 1.0, P_base_learners.shape[1] + 1)] #7个单独算法+1个集成算法

    for i in range(P_base_learners.shape[1]):
        p = P_base_learners[:, i]
        fpr, tpr, _ = roc_curve(ytest, p)
        plt.plot(fpr, tpr, label=labels[i], c=cm[i + 1])

    fpr, tpr, _ = roc_curve(ytest, P_ensemble)
    plt.plot(fpr, tpr, label=ens_label, c=cm[0])

    plt.xlabel('False positive rate')
    plt.ylabel('True positive rate')
    plt.title('ROC curve')
    plt.legend(frameon=False)
    plt.show()

plot_roc_curve(ytest, P.values, P.mean(axis=1), list(P.columns), "ensemble")


#各个算法预测的共和党占比
p = P.apply(lambda x: 1*(x >= 0.5).value_counts(normalize=True))
p.index = ["DEM", "REP"]
p.loc["REP", :].sort_values().plot(kind="bar")
plt.axhline(0.25, color="k", linewidth=0.5)
plt.text(0., 0.23, "True share republicans")
plt.show()
#
# 通过上一步展示的图片发现svm和mlp-nn和真实的共和党比例相差太大,那么我们手动直接干掉,
include = [c for c in P.columns if c not in ["mlp-nn"]]
print("Truncated ensemble ROC-AUC score: %.3f" % roc_auc_score(ytest, P.loc[:, include].mean(axis=1)))
#====================================================================================================
#手动去找麻烦,可利用stacking的思想,在第二阶段训练每个算法的权重值
base_learners = get_models()

meta_learner = GradientBoostingClassifier(#第二阶段分类器
    n_estimators=1000,
    loss="exponential",
    max_features=4,
    max_depth=3,
    subsample=0.5,
    learning_rate=0.005,
    random_state=SEED
)

#当第一阶段的结果在第二阶段继续训练,嚼过的饭再嚼一次,很容易出现过拟合,可采用交叉验证,用交叉训练集训练模型,交叉验证集产生第二阶段的输入即可解决(毕竟交叉验证集没有进行反向传播调整权重)

#切分交叉训练集和验证集
xtrain_base, xpred_base, ytrain_base, ypred_base = train_test_split(
    xtrain, ytrain, test_size=0.5, random_state=SEED)

#训练模型方法
def train_base_learners(base_learners, inp, out, verbose=True):
    if verbose: print("Fitting models.")
    for i, (name, m) in enumerate(base_learners.items()):
        if verbose: print("%s..." % name, end=" ", flush=False)
        m.fit(inp, out)
        if verbose: print("done")


# 第一阶段预测出作为第二阶段输入的值
def predict_base_learners(pred_base_learners, inp, verbose=True):

    P = np.zeros((inp.shape[0], len(pred_base_learners)))

    if verbose: print("Generating base learner predictions.")
    for i, (name, m) in enumerate(pred_base_learners.items()):
        if verbose: print("%s..." % name, end=" ", flush=False)
        p = m.predict_proba(inp)

        P[:, i] = p[:, 1]
        if verbose: print("done")

    return P

#对stacking模型进行训练
def ensemble_predict(base_learners, meta_learner, inp, verbose=True):

    P_pred = predict_base_learners(base_learners, inp, verbose=verbose)
    return P_pred, meta_learner.predict_proba(P_pred)[:, 1]

#开始训练
train_base_learners(base_learners, xtrain_base, ytrain_base)
#交叉预测,可拿到第二阶段的输入
P_base = predict_base_learners(base_learners, xpred_base)
#在第二阶段进行各个算法的权重训练,即完成对mata_learner的训练
meta_learner.fit(P_base, ypred_base)
#用测试集进行最终测试
P_pred, p = ensemble_predict(base_learners, meta_learner, xtest)
print("\nEnsemble ROC-AUC score: %.3f" % roc_auc_score(ytest, p)) #0.880


#由于之前的暴力切分验证集,导致数据损失了一半,可以进行真正的交叉验证,具体代码可参考信用卡欺诈

#现在利用现成的集成算法库mlens实现
from mlens.ensemble import SuperLearner

# 集成算法分类器
sl = SuperLearner(
    folds=10,
    random_state=SEED,
    verbose=2,
    backend="multiprocessing"
)

# 指定各阶段的算法
sl.add(list(base_learners.values()), proba=True)
sl.add_meta(meta_learner, proba=True)

# 训练
sl.fit(xtrain, ytrain)

# 评分
p_sl = sl.predict_proba(xtest)

print("\nSuper Learner ROC-AUC score: %.3f" % roc_auc_score(ytest, p_sl[:, 1]))#0.889

你可能感兴趣的:(集成算法介绍)