对于数据X,分别选择两种预处理方案,在不同预处理方案中再建立不同模型,最终汇总所有模型结果。

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline
import os
#os.chdir('')

1. 导入数据

#设置随机种子
SEED=222
np.random.seed(SEED)

df=pd.read_csv(r'input.csv')
print(df.shape)
df.head(6)

python数据集大小 python数据集成案例_权重

python数据集大小 python数据集成案例_python数据集大小_02

2. 查看因变量分布

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

python数据集大小 python数据集成案例_建模_03

3. 分割数据集

'''
对cand_pty_affiliation是否为REP进行预测
'''
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score

def get_train_test(test_size=0.95):
    y=1*(df['cand_pty_affiliation']=='REP')  #因变量建立
    X=df.drop(['cand_pty_affiliation'],axis=1)
    X=pd.get_dummies(X,sparse=True)          #哑变量设置 为什么??
    X.drop(X.columns[X.std()==0],axis=1,inplace=True) #某列数值相同的删去
    return train_test_split(X,y,test_size=test_size,random_state=SEED)

X_train,X_test,y_train,y_test=get_train_test()
print(X_train.shape,X_test.shape)

(5000, 158) (95000, 158)

(其实这里个人有一个问题:现在的数据集有158个特征,是为了多特征而构造的吗?因为分类变量可以直接加入模型建模啊,为什么要进行哑变量设置?如果有小伙伴可以提点下,谢谢留言哈!)

4. 构建几个基础的决策树模型看看

import pydotplus
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):
    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())

5. 建模

5.1 第1个模型
#建模
t1=DecisionTreeClassifier(max_depth=1,random_state=SEED)
t1.fit(X_train,y_train)

#auc值
p=t1.predict_proba(X_test)[:,1]
print('DecisionTree ROC_AUC score:%.3f' %roc_auc_score(y_test,p))
#决策树图形
print_graph(t1,X_train.columns)

DecisionTree ROC_AUC score:0.672

python数据集大小 python数据集成案例_建模_04


上面的决策树没有用处,因为所有的预测结果是一样的。

5.2 再看第2个
t2=DecisionTreeClassifier(max_depth=3,random_state=SEED)
t2.fit(X_train,y_train)
p=t2.predict_proba(X_test)[:,1]
print('Decision tree roc-auc score:%.3f' % roc_auc_score(y_test,p))
print_graph(t2,X_train.columns)

Decision tree roc-auc score:0.751

python数据集大小 python数据集成案例_建模_05


47.3%的样本落在了最左边,还有35.9%落在了基本最右边,看起来模型基本过拟合

调整下策略,去掉个对结果有着最大影响的因素看看!

5.3 第3个模型
drop=['transaction_amt']
X_train_slim=X_train.drop(drop,1)
X_test_slim=X_test.drop(drop,1)

t3=DecisionTreeClassifier(max_depth=3,random_state=SEED)
t3.fit(X_train_slim,y_train)
p=t3.predict_proba(X_test_slim)[:,1]
print('DT roc_auc: %.3f' % roc_auc_score(y_test,p))

print_graph(t3,X_train_slim.columns)

DT roc_auc: 0.740

python数据集大小 python数据集成案例_决策树_06

5.4 将两个决策树模型结合

从以上两个树来看,模型评估结果差不多,但是树看起来很不一样,各自都有错误,可以综合利用

p1=t2.predict_proba(X_test)[:,1]
p2=t3.predict_proba(X_test_slim)[:,1]
p=np.mean([p1,p2],axis=0)
print('average of decision tree Roc_auc score:%.3f' % roc_auc_score(y_test,p))

average of decision tree Roc_auc score:0.783

果然预测的结果的得分比原来高许多!!

这么一来,应该是选择不同的特征会产生不同的结果,然后用不同的结果再进行组合得到一个提高!那我们多选几组不就是随机森林了嘛!

6. 随机森林

from sklearn.ensemble import RandomForestClassifier

rf=RandomForestClassifier(
    n_estimators=10,max_features=3,
    random_state=SEED)

rf.fit(X_train,y_train)
p=rf.predict_proba(X_test)[:,1]
print('rf roc_auc: %.3f' % roc_auc_score(y_test,p))

rf roc_auc: 0.844
显然比单棵决策树的auc值要高!!

7. 集成

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
7.1 定义函数
#定义模型字典函数
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=100,max_features=3,
                             random_state=SEED)
    
    models={'svm':svc,  #支持向量机
           'knn':knn,   #K近邻估计
           'naive bayes':nb,  #朴素贝叶斯
           'mlp-nn':nn,      
           'random forest':rf,    #随机森林
           'gbm':gb,              #梯度提升树
           'logistic':lr}         #逻辑回归
    return models
#定义预测函数
def train_predict(model_list):
    P=np.zeros((y_test.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)  #flush=F 请求完毕后输出相应内容
        m.fit(X_train,y_train)
        P.iloc[:,i]=m.predict_proba(X_test)[:,1]  #填入预测值
        cols.append(name)        #收集名称
        print('done')    
    print('Done.\n')
    P.colunms=cols              #数据框列名
    return P
#定义auc取值函数
def score_models(P,y_test):
    print('scoring models.')
    for m in P.columns:
        score=roc_auc_score(y_test,P.iloc[:,m])
        print('%-26s:%.3f' %(m,score))
    print('Done.\n')
cols=list()
for name in range(0,3):
    cols.append(name)
cols

[0, 1, 2]

7.2 建模
import warnings
warnings.filterwarnings('ignore')

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

python数据集大小 python数据集成案例_建模_07

7.3 比较多个模型结果
cols=list()
for name in models.keys():
    cols.append(name)
    
P.columns=cols
P.head(6)

python数据集大小 python数据集成案例_python数据集大小_08

from mlens.visualization import corrmat
corrmat(P.corr(),inflate=False)
plt.show()

python数据集大小 python数据集成案例_权重_09

print('Ensemble roc_auc score: %.3f' % roc_auc_score(y_test,P.mean(axis=1)))

Ensemble roc_auc score: 0.884
显然总结果的得分比每一个模型都高!

8. 多个模型的roc_auc曲线

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))
    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(y_test, p)
        plt.plot(fpr, tpr, label=labels[i], c=cm[i + 1])

    fpr, tpr, _ = roc_curve(y_test, 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(y_test, P.values, P.mean(axis=1), list(P.columns), "ensemble")

python数据集大小 python数据集成案例_决策树_10


roc曲线上每一个点对应一个threshold,对于一个分类器,每个threshold下会有一个TPR和FPR.随着阈值的减小,TP和FP都在减小,TPR和FPR也在减小,ROC点在向下移动。

可以看出,集成算法的曲线基本包含基础分类器的曲线

之前的集成是按照平均来算的,但是这样公平吗?有的拖后腿咋办?

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

python数据集大小 python数据集成案例_权重_11


个别模型捕捉不到一些类别!将效果最差的剔除掉

include=[c for c in P.columns if c not in [['svm','mlp-nn']]]
print('New roc_auc score:%.3f' % roc_auc_score(y_test,P.loc[:,include].mean(axis=1)))

New roc_auc score:0.884

能否让机器自己选择怎么用基础模型的结果呢?

对于每一个训练模型,选择一个最合适的权重,但是权重如何定义,我们可以训练一个模型来定义这些权重。

需要考虑的是,第二个模型的输入应该是什么?

9. Stacking模型

9.1 定义模型
base_learners=get_models()
9.2 定义权重分配模型
meta_learner = GradientBoostingClassifier(
    n_estimators=1000,
    loss="exponential",
    max_features=4,
    max_depth=3,
    subsample=0.5,
    learning_rate=0.005, 
    random_state=SEED
)
9.3 将基础模型分成两部分,主要供第二层使用
X_train_base,X_test_base,y_train_base,y_test_base=train_test_split(
    X_train,y_train,test_size=0.5,random_state=SEED)
9.4 训练基础模型
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")

train_base_learners(base_learners, X_train_base, y_train_base)