机器学习收藏Data science

【实战篇】集成算法建模(三)

2022-01-31  本文已影响0人  山药鱼儿

Hello,大家好~ 今天是农历 2021 年的最后一天 - 除夕,小鱼在这里先给大家拜年啦,祝您和您的家人虎虎生威,虎年大吉!

下面,我们正式开始充电啦~

书接上一篇连载:我们分别使用决策树、以及随机森林实现了建模,并最终在未进行任何调参的情况下,使用随机森林得到了 0.869 的 ROC-AUC Score 值。

其中,随机森林其实就是 Bagging 的集成思想,通过构造一批不同的决策树,来综合考虑每棵树的结果,得到最终的值。相比于单棵树,结果得到了更大的提升,不仅泛化能力强,过拟合风险小,而且大幅提升了模型的准确性。

今天,我们将进一步提升模型的泛化能力以及准确性。随机森林的基础模型都是决策树,那我们是否可以使用不同的算法,构造出不同的基础模型呢?如 KNN,LR,SVM,RF 等等。

最后将所有模型得到的预测结果取平均,做为最终的预测值:

下面,我们不妨来尝试一下~

代码实现

导入集成时用到的各类型分类器:

from sklearn.svm import SVC
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

构建基础的模型,并以字典的形式批量返回所有模型:

def get_models():
    """Generate a library of base learners."""
    nb = GaussianNB()
    svc = SVC(C=100, probability=True)
    knn = KNeighborsClassifier(n_neighbors=3)
    lr = LogisticRegression(C=100, random_state=SEED, solver="liblinear")
    nn = MLPClassifier((80,10), early_stopping=False, random_state=SEED)
    gb = GradientBoostingClassifier(n_estimators=100, random_state=SEED)
    rf = RandomForestClassifier(n_estimators=10, max_depth=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(models):
    """Fit models in list on training set and return preds"""
    P = np.zeros((ytest.shape[0], len(models)))
    P = pd.DataFrame(P)
    
    print("Fitting models.")
    cols = list()
    
    for i, (name, m) in enumerate(models.items()):
        print("{} ...".format(name), end=" ", flush=False)
        m.fit(x_over_sample_train, y_over_sample_train)
        P.iloc[:, i] = m.predict_proba(xtest)[:, 1]
        cols.append(name)
        print("done")
        
    P.columns = cols
    print("Fitting models Done.")
    return P

其中 P 用来存放所有模型的预测结果,P 中的行对应测试集中每个样本通过不同的模型预测的结果值,列为具体的算法模型的所有预测值。因此,测试集有多少个样本,P 就有多少行;有多少个模型,P 就有多少列。

接下来,就是使用 for 循环,分别使用不同的模型进行训练以及预测,并将预测结果保存在 P 中。此处小鱼没有并行地训练多个分类器,一方面小鱼训练集的数据比较少,另一方面呢,没有交叉验证,调参的过程。整个过程还是比较快的。

最后,将预测结果 P 进行返回。

拿到预测结果的组合 P 之后,就可以分别计算各模型的 AUC-ROC Score 啦~

def score_model(P, y):
    """Score model in prediction DF"""
    print("Scoring models.")
    s = pd.Series()
    
    for m in P.columns:
        score = roc_auc_score(y, P.loc[:, m])
        s.loc[m] = score
        
    print(s.sort_values())
    print("Scoring models Done.")

训练模型,观察结果

models = get_models()
P = train_predict(models)

训练和预测过程的终端输出:

Fitting models.
svm ... done
knn ... done
naive bayes ... done
mlp-nn ... done
random forest ... done
gbm ... done
logistic ... done
Fitting models Done.

各模型预测的 ROC-AUC Score:

>> score_model(P, ytest)
Scoring models.
svm              0.721109
naive bayes      0.739966
knn              0.804353
random forest    0.805589
logistic         0.852700
mlp-nn           0.865270
gbm              0.876627
dtype: float64
Scoring models Done.

其中,各模型预测的结果 P 如下:

P.head()

通过计算 P 的相关系数,可以了解各模型之间的相似层度:

P.corr()

每个模型自然和自身的相关性最强,因此对角线上的值为 1 ;值越大,相关系越强,反之,相关系越弱。

当然了,也可以借助 ML-Ensemble 为我们提供的可视化工具来直观地观察出模型的相似层度:

from mlens.visualization import corrmat

corrmat(P.corr(), inflate=False)

注:需要安装 pip install mlens 库。

绘制结果:

通过观察相关性矩阵,可以发现 mlp-nn 模型、gbm 模型以及 logistic 模型的相关度是比较高的。

计算所有模型预测的结果

最后,我们将所有模型预测的结果值取平均,计算 ROC-AUC Score:

>> print("Ensemble ROC-AUC score: %.3f" % roc_auc_score(ytest, P.mean(axis=1)))
Ensemble ROC-AUC score: 0.880

在 bagging 集成时,通过集成不同算法类型的模型,获得的结果值又得到了提升。可见,继承算法一方面可以使得边界更平稳,降低过拟合的风险,提高模型的泛化能力;另一方面可以有效地提高模型的评分。

下面,是逻辑回归、随机森林、SVM 以及集成算法分类的示意图:

绘制 ROC 曲线

定义绘制 ROC 曲线的函数:

from sklearn.metrics import roc_curve

def plot_roc_curve(ytest, P_base_learners, P_ensemble, labels, ens_label):
    """Plot the roc curve for base learners and ensemble."""
    plt.figure(figsize=(5, 4), dpi=120)
    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)]
    
    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()

上述代码中,plt.plot([0, 1], [0, 1], 'k--') 在 (0,0)和(1,1)之间绘制一条虚线,表示随机的预测结果。ROC 曲线基本会分布在该曲线上方。

cm 为绘制不同模型的 ROC 曲线时使用的 Clolor Map。plt.plot() 绘图时,首先使用 for 循环绘制了所有的基础模型的 ROC 曲线,之后单独绘制集成模型的 ROC 曲线。

from sklearn.metrics import roc_curve 可以根据真实值和预测值,计算出 False Positive Rate 和 True Positive Rate。

绘图:

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

emsemble 曲线既平滑,面积又是最大的!此外,逻辑回归作为机器学习中最简单的模型,结果也是非常棒的。正如小鱼前面所说,在机器学习中,模型并非越复杂越好,逻辑回归也是一把宝刀~

以上就是今天的内容啦~小鱼里一个思考问题:我们上述使用 Bagging 思想集成都是按照平均来算的,但是这样公平吗?有些拖后腿的模型是不是应该把它去掉呢?我们下节见~

上一篇 下一篇

猜你喜欢

热点阅读