ML6自学笔记

集成算法实战

集成算法工具包:http://ml-ensemble.com/

集成算法的思想

X数据通过不同的数据处理可以变成X1,X2,通过不同的处理算法f可以得到不同的结果pi,最后平均成最终的结果P。
在这里插入图片描述

导包 预处理数据

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt
%matplotlib inline

### Import data
# 随机种子,设置随机种子,无论切分为训练集和测试集多少遍,每次切分都是一样的。
SEED = 222
np.random.seed(SEED)
#读入数据
df = pd.read_csv('input.csv')

### Training and test set
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score
# 使用roc曲线评估结果
# 划分数据
def get_train_test(test_size=0.95):
    """Split Data into train and test sets."""
    #这一列值是REF的就变成1
    y = 1 * (df.cand_pty_affiliation == "REP")
    #删去标签列
    X = df.drop(["cand_pty_affiliation"], axis=1)
    # 得到编码方式 get_dummies用于做独热编码
    X = pd.get_dummies(X, sparse=True)
    # std()求标准差,对于某一列的数据,如果标准差为零(就说明此列值都是一样的,也就没有参考价值),删掉
    X.drop(X.columns[X.std() == 0], axis=1, inplace=True)
    return train_test_split(X, y, test_size=test_size, random_state=SEED)

xtrain, xtest, ytrain, ytest = get_train_test()

# A look at the data
print("\nExample data:")
df.head()

ROC 与AUC指标

准确率与召回率。ROC是曲线,AUC是曲线下的面积,清楚四个点的含义。希望面积越大越好,因为越往上TPR越大。曲线围成面积最大为1。y=x这条曲线,预测正确与预测错误相同,也就是类似于“猜”,所以评估模型一般不会比猜还差。希望AUC的值越大越好,用AUC的值来评估模型。
在这里插入图片描述

基础模型

对标签一列技术映射到0-1展示。即查看类别分布。

df.cand_pty_affiliation.value_counts(normalize=True).plot(
    kind="bar", title="Share of No. donations")
plt.show()

在这里插入图片描述
创建决策树模型

import pydotplus  # you can install pydotplus with: pip install pydotplus 
#安装graphviz  http://download.csdn.net/download/shouwangzhelv/9492517
#将安装或者解压的graphviz下的bin目录添加到系统的path中,重启notebook
from IPython.display import Image
from sklearn.metrics import roc_auc_score
from sklearn.tree import DecisionTreeClassifier, export_graphviz
#创建好树之后调用画图
def print_graph(clf, feature_names):
    """Print decision tree."""
    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)  
    return Image(graph.create_png())

max_depth:树的深度;fit训练数据,predict_proba预测,将预测指标拿出来
roc_auc_acore计算指标,将真实值,预测值都传入

t1 = DecisionTreeClassifier(max_depth=1, random_state=SEED)
t1.fit(xtrain, ytrain)
p = t1.predict_proba(xtest)[:, 1]

print("Decision tree ROC-AUC score: %.3f" % roc_auc_score(ytest, p))
print_graph(t1, xtrain.columns)

这颗决策树的决策100%都是D类。
在这里插入图片描述
将深度改为3,会改善很多。
但是。47.3%的样本落到了最左边, 还有35.9% 落在了基本最右边. 这看起来模型基本已经过拟合了。(试着调整,去掉对结果影响最大的因素(根节点以什么往下划分)再次试验)
在这里插入图片描述

调整模型

drop = ["transaction_amt"]

xtrain_slim = xtrain.drop(drop, 1)
xtest_slim = xtest.drop(drop, 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))
print_graph(t3, xtrain_slim.columns)

在这里插入图片描述

集成

经过上一步模型调整,我们获得了两个不同的树,下面就可以进行集成了。
p1,p2两个预测结果,mean取均值。

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))

结果变好了。接下来通过不同特征得到不同结果,组合结果构成随机森林。
在这里插入图片描述
n_estimators=10:建立10颗树

from sklearn.ensemble import RandomForestClassifier

rf = RandomForestClassifier(
    n_estimators=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))

在这里插入图片描述
使用下面的这些模型,分别预测结果,再组合结果。
在这里插入图片描述

# A host of Scikit-learn models
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():
    """Generate a library of base learners."""
    nb = GaussianNB()#朴素贝叶斯
    svc = SVC(C=100, probability=True)#支持向量机
    knn = KNeighborsClassifier(n_neighbors=3)#KNN
    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):
    """Fit models in list on training set and return preds"""
    P = np.zeros((ytest.shape[0], len(model_list)))
    P = pd.DataFrame(P)

    print("Fitting models.")
    cols = list()
    #遍历每一个模型,对数据进行训练预测,并返回结果
    for i, (name, m) in enumerate(models.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

#算出各个模型的结果ROC值
def score_models(P, y):
    """Score model in prediction DF"""
    print("Scoring models.")
    for m in P.columns:
        score = roc_auc_score(y, P.loc[:, m])
        print("%-26s: %.3f" % (m, score))
    print("Done.\n")

执行

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

得到每个模型的ROC值
在这里插入图片描述
可以使用corrmat方法查看模型之间的相似度。将模型预测结果作为参数传入。

# You need ML-Ensemble for this figure: you can install it with: pip install mlens
from mlens.visualization import corrmat

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

在这里插入图片描述
各个模型结果集成

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

简单集成,结果明显提高。
在这里插入图片描述
不过集成算法不适合做实时处理,因为每个模型训练得比较好,训练多个模型会消耗大量时间。

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=(10, 8))
    #画出基本线,连接(0,1),(1,0),对角线
    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()


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

在这里插入图片描述

Stacking 集成

因为之前的集成是直接求均值,这样可能有些模型结果不好会影响总体准确率,下面做进一步优化。
对于不同模型的预测结果情况。

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()

可以看出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模型

给每一个模型施加权重。分为两层处理。
在这里插入图片描述

在这里插入图片描述

  1. 定义基础模型,之前定义的函数
base_learners = get_models()
  1. 定义权重分配模型。选择一个分类器。
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. 将基础模型分为两部分,供第二层使用。因为第一阶段得到的结果是训练集的结果,如果第二阶段再用这个数据会引起过拟合的风险,所以需要第二阶段没看过数据。所以将第一阶段的数据分为两部分,使用train训练,使用test得到第一阶段结果。
xtrain_base, xpred_base, ytrain_base, ypred_base = train_test_split(
    xtrain, ytrain, test_size=0.5, random_state=SEED)
  1. 训练模型
def train_base_learners(base_learners, inp, out, verbose=True):
    """Train all base learners in the library."""
    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")

在这里插入图片描述
二阶段的输入是第一阶段没有用作训练的数据的预测结果。
5. 准备二阶段权重分配分类器的训练数据。得到第一阶段的输出值

def predict_base_learners(pred_base_learners, inp, verbose=True):
    """Generate a prediction matrix."""
    #参数 数据样本个数,几个分类器
    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)
        # With two classes, need only predictions for one class
        P[:, i] = p[:, 1]
        if verbose: print("done")

    return P
P_base = predict_base_learners(base_learners, xpred_base)
  1. 训练二阶段得出分类结果
meta_learner.fit(P_base, ypred_base)
def ensemble_predict(base_learners, meta_learner, inp, verbose=True):
    """Generate predictions from the ensemble."""
    P_pred = predict_base_learners(base_learners, inp, verbose=verbose)
    return P_pred, meta_learner.predict_proba(P_pred)[:, 1]
P_pred, p = ensemble_predict(base_learners, meta_learner, xtest)
print("\nEnsemble ROC-AUC score: %.3f" % roc_auc_score(ytest, p))

在这里插入图片描述

效果改进

因为在第一阶段进行了数据切分,所以相当于损失了一半的数据,对结果有影响。
可以通过交叉验证改进,如图所示12训练3测试,23训练1测试,13训练2测试,最后数据集还是123三部分。在这里插入图片描述

from sklearn.base import clone

def stacking(base_learners, meta_learner, X, y, generator):
    """Simple training routine for stacking."""

    # Train final base learners for test time
    print("Fitting final base learners...", end="")
    train_base_learners(base_learners, X, y, verbose=False)
    print("done")

    # Generate predictions for training meta learners
    # Outer loop:
    print("Generating cross-validated predictions...")
    cv_preds, cv_y = [], []
    for i, (train_idx, test_idx) in enumerate(generator.split(X)):

        fold_xtrain, fold_ytrain = X[train_idx, :], y[train_idx]
        fold_xtest, fold_ytest = X[test_idx, :], y[test_idx]

        # Inner loop: step 4 and 5
        fold_base_learners = {name: clone(model)
                              for name, model in base_learners.items()}
        train_base_learners(
            fold_base_learners, fold_xtrain, fold_ytrain, verbose=False)

        fold_P_base = predict_base_learners(
            fold_base_learners, fold_xtest, verbose=False)

        cv_preds.append(fold_P_base)
        cv_y.append(fold_ytest)
        print("Fold %i done" % (i + 1))

    print("CV-predictions done")
    
    # Be careful to get rows in the right order
    cv_preds = np.vstack(cv_preds)
    cv_y = np.hstack(cv_y)

    # Train meta learner
    print("Fitting meta learner...", end="")
    meta_learner.fit(cv_preds, cv_y)
    print("done")

    return base_learners, meta_learner

做2折验证

from sklearn.model_selection import KFold

# Train with stacking
cv_base_learners, cv_meta_learner = stacking(
    get_models(), clone(meta_learner), xtrain.values, ytrain.values, KFold(2))

P_pred, p = ensemble_predict(cv_base_learners, cv_meta_learner, xtest, verbose=False)
print("\nEnsemble ROC-AUC score: %.3f" % roc_auc_score(ytest, p))

结果改善。
在这里插入图片描述
因为使用交叉验证,所以时间上又有所延长。所以引入一些并行的东西。

from mlens.ensemble import SuperLearner

# Instantiate the ensemble with 10 folds
sl = SuperLearner(
    folds=10,
    random_state=SEED,
    verbose=2,
    backend="multiprocessing"
)

# Add the base learners and the meta learner
#添加第一阶段和第二阶段模型
sl.add(list(base_learners.values()), proba=True) 
sl.add_meta(meta_learner, proba=True)

# Train the ensemble
sl.fit(xtrain, ytrain)

# Predict the test set
p_sl = sl.predict_proba(xtest)

print("\nSuper Learner ROC-AUC score: %.3f" % roc_auc_score(ytest, p_sl[:, 1]))
plot_roc_curve(ytest, p.reshape(-1, 1), P.mean(axis=1), ["Simple average"], "Super Learner")

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值