11-21

念念不忘 必有回响

A--集成算法的实现

In [54]:
import numpy as np
from scipy.special import comb #用于生成一次取k的N个事物的组合数
import math
import matplotlib.pyplot as plt
​
#解决中文显示问题
plt.rcParams['font.sans-serif'] = ['KaiTi'] # 指定默认字体
plt.rcParams['axes.unicode_minus'] = False # 解决保存图像是负号'-'显示为方块的问题
'''
组合分类器的误差率计算函数
'''
def ensemble_error(classfier_num,error):
    #计算k值
    k = math.ceil(classfier_num / 2.0)
    #获取集成系统出错的概率
    probs = [comb(classfier_num,k)*error**k*(1-error)**(classfier_num-k)
             for k in range(k,classfier_num+1)]
    return sum(probs)

 

组合分类器误差率计算公式:

 

sum(comd(k,i)a**i(1-a)**(k-i))

其中:k=基分类器个数

  i=k/2--k+1

  a=基分类器误差率
In [57]:
def ensemble_error(classfier_num,error):
    #计算k值
    k = math.ceil(classfier_num / 2.0)
    #获取集成系统出错的概率
    probs = [comb(classfier_num,k)*error**k*(1-error)**(classfier_num-k)
             for k in range(k,classfier_num+1)]
    return sum(probs)

if __name__ == "__main__":
    #定义错误率取值的范围
    error_range = np.arange(0,1.01,0.01)
    #当成员分类器的出错率不同时,计算集成系统的出错概率
    ensem_errors = [ensemble_error(11,error=error) for error in error_range]
    plt.plot(error_range,error_range,label="基分类器误差",linewidth=2,linestyle="--")
    plt.plot(error_range,ensem_errors,label="集成分类器误差",linewidth=2)
    plt.legend(loc="upper left")
    plt.grid()
    plt.show()

 

 

由图可知,基分类器的误差必须小于0.5,组合分类器的效果才比基分类器好,否者效果不如基分类器

 

另一个条件是,基分类器必须尽量的相互独立,而我们的集成算法用于解决这一问题

 

另:由公式可知,在我的基分类器误差相对较大的时候,我必须增加基分类器的数量,以此降低我的整体误差

 

1.构建组合分类器的基本方法

 

1.1通过处理理训练数据集

 

这种方法根据某种抽样分布,通过对原始数据进行再抽样来得到多个训练集。抽样分布决定一个样本选作训练的可能性大小,并且可能因试验而异。然后,使用特定的学习算法为每个训练集建立⼀个分类器。 装袋(bagging)和提升(boosting)是两种处理训练数据集的组合方法。

 

1.2通过处理输入特征

 

通过选择输入特征的子集来形成每个训练集。子集可以随机选择一些研究表明,对那些含有大量量冗余特征的数据集,这种方法的性能非常好,随机森林林(Randomforest)就是⼀一种处理理输入特征的组合方法, 它使用决策树作为基分类器,在随机选取训练子集的的情况下,又随机选取特征,但任然没有脱离bagging的范畴

 

1.3通过处理学习算法

 

在同一个训练数据集上多次执行算法可能得到不同的模型。例如,通过改变一个人工神经网络的拓扑结构或各个神经元之间联系的初始权值,就可以得到不同的模型。同样,通过在树生成过程中注入随机性,可以得到决策树的组合分类器。例如,在每一个结点上,可以随机地从最好的k个属性中选择一个属性,⽽不是选择该结点上最好的属性来进行划分

 

用Scikit-Learn实现装袋法(bagging)

In [10]:
import numpy as np
import pandas as pd
import matplotlib as mpl
import matplotlib.pyplot as plt
from sklearn.ensemble import BaggingRegressor#装袋法
from sklearn.tree import DecisionTreeRegressor#回归树
from sklearn.tree import DecisionTreeClassifier# 决策树
from sklearn.model_selection import cross_val_score #交叉验证模块
from tree_visualize import visualize_classifier #画图模块
from sklearn.model_selection import train_test_split #训练集与测试集划分模块
from sklearn.metrics import accuracy_score  #准确率计算模块
In [11]:
from sklearn.datasets import load_iris
iris = load_iris()
In [ ]:
iris.data#查看数据值

In [117]:

iris.target#查看数据标签
Out[117]:
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
       2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2])
In [12]:
Xtrain,Xtest,ytrain,ytest= train_test_split(iris.data,iris.target,random_state=42)

In [12]:

#决策树
clf=DecisionTreeClassifier() clf.fit(Xtrain,ytrain) clf.score(Xtest,ytest)
Out[12]:
1.0
In [15]:
clf.feature_importances_
Out[15]:
array([0.03575134, 0.        , 0.39794324, 0.56630542])
In [123]:
clf.classes_
Out[123]:
array([0, 1, 2])
In [19]:
y_clf = clf.predict(Xtest)#预测训练集
In [20]:
accuracy_score(ytest, y_clf)#查看准确率
Out[20]:
1.0
In [24]:
from sklearn import tree#画图
import graphviz 
dot_data = tree.export_graphviz(clf, out_file=None)
graphviz.Source(dot_data)
Out[24]:
<graphviz.files.Source at 0x1c0a8a00ba8>
In [145]:
dot_data = tree.export_graphviz(clf, out_file=None, #美化画图
feature_names=iris.feature_names,  
class_names=iris.target_names,  
filled=True, rounded=True,  
special_characters=True)  
graphviz.Source(dot_data)  
Out[145]:
<graphviz.files.Source at 0x1950730fdd8>
In [29]:
cross_val_score(clf,Xtest,ytest,cv=10)#交叉验证这里输出模型的准确率,然而对于决策树而言并没有什么
Out[29]:
array([1.  , 1.  , 1.  , 0.75, 1.  , 1.  , 1.  , 1.  , 1.  , 1.  ])
 
In [32]:
 
#装袋
from tree_visualize import visualize_classifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier
tree = DecisionTreeClassifier()
bag = BaggingClassifier(tree, n_estimators=100, max_samples=0.8,
random_state=1)
bag.fit(Xtrain, ytrain)
Out[32]:
BaggingClassifier(base_estimator=DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
            max_features=None, max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=1, min_samples_split=2,
            min_weight_fraction_leaf=0.0, presort=False, random_state=None,
            splitter='best'),
         bootstrap=True, bootstrap_features=False, max_features=1.0,
         max_samples=0.8, n_estimators=100, n_jobs=1, oob_score=False,
         random_state=1, verbose=0, warm_start=False)
In [34]:
bag.classes_ 
Out[34]:
array([0, 1, 2])
In [36]:
bag.estimators_features_ 
 
In [37]:
bag.n_classes_ 
Out[37]:
3
 

随机森林RF

In [4]:
from sklearn.model_selection import cross_val_score#交叉验证
from sklearn.datasets import make_blobs#数据集生成器
from sklearn.ensemble import RandomForestClassifier#随机森林
from sklearn.ensemble import ExtraTreesClassifier#非常随机森林
from sklearn.tree import DecisionTreeClassifier#决策树
这里我们使用了袋外评估策略oob_score=True,注意,随机有放回抽样只能抽取68%的数据,而袋外评估使用个数就是剩下的数据,所以随机森林是没有必要进行交叉验证的
In [66]:
clf = RandomForestClassifier(n_estimators=10, max_depth=None,min_samples_split=2, random_state=0,oob_score=True)
clf.fit(Xtrain,ytrain) 
#print(clf.feature_importances_)变量重要程度,越大越好
#print(clf.estimators_)
#print(clf.classes_)输出标签
#print(clf.n_classes_)#标签个数
print(clf.oob_score_ )#如果进行袋外估计,返回准确率
0.9196428571428571
In [60]:
clf.feature_importances_
Out[60]:
array([0.10637006, 0.04401153, 0.37865068, 0.47096772])
In [65]:
RandomForestClassifier?
AdaBoost
 

Adaboost-参数:

base_estimator:基分类器,默认是决策树,在该分类器基础上进行boosting,理论上可以是任意一个分类器,但是如果是其他分类器时需要指明样本权重。

n_estimators:基分类器提升(循环)次数,默认是50次,这个值过大,模型容易过拟合;值过小,模型容易欠拟合。

learning_rate:学习率,表示梯度收敛速度,默认为1,如果过大,容易错过最优值,如果过小,则收敛速度会很慢;该值需要和n_estimators进行一个权衡,当分类器迭代次数较少时,学习率可以小一些,当迭代次数较多时,学习率可以适当放大。

algorithm:boosting算法,也就是模型提升准则,有两种方式SAMME, 和SAMME.R两种,默认是SAMME.R,两者的区别主要是弱学习器权重的度量,前者是对样本集预测错误的概率进行划分的,后者是对样本集的预测错误的比例,即错分率进行划分的,默认是用的SAMME.R。

random_state:随机种子设置。

 

Adaboost-对象

estimators_:以列表的形式返回所有的分类器。

classes_:类别标签

estimatorweights:每个分类器权重

estimatorerrors:每个分类器的错分率,与分类器权重相对应。

featureimportances:特征重要性,这个参数使用前提是基分类器也支持这个属性。

In [73]:
 
from sklearn.ensemble import AdaBoostClassifier
clf =AdaBoostClassifier(n_estimators=100)#弱学习者的数量由参数控制n_estimators
clf.fit(Xtrain,ytrain) 
Out[73]:
AdaBoostClassifier(algorithm='SAMME.R', base_estimator=None,
          learning_rate=1.0, n_estimators=100, random_state=None)
In [77]:
clf.feature_importances_

Out[77]:

array([0. , 0. , 0.5, 0.5])
 

梯度提升树GBDT

In [78]:
from sklearn.ensemble import GradientBoostingClassifier
clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0,
max_depth=1, random_state=0).fit(Xtrain, ytrain)
clf.score(Xtest, ytest)
 
Out[78]:
0.9473684210526315
In [79]:
GradientBoostingClassifier?
In [80]:
clf.feature_importances_ 
Out[80]:
array([0.16      , 0.29666667, 0.13333333, 0.13      ])
In [83]:
clf.train_score_ 
Out[83]:
array([39.48986717, 20.49861272, 14.1491451 , 10.80329146,  9.41449938,
        7.92793047,  6.77100683,  6.32788123,  5.74089388,  5.06627182,
        4.66603555,  4.41655005,  4.10226212,  3.68149678,  3.49118428,
        3.35265634,  3.05402751,  2.92650443,  2.73179899,  2.52098857,
        2.31566024,  2.24755993,  2.13496349,  1.99269168,  1.89624994,
        1.79400742,  1.68511118,  1.62213796,  1.58079027,  1.4920668 ,
        1.38990634,  1.32857113,  1.29357608,  1.19436873,  1.13970321,
        1.11727698,  1.07087434,  1.04693502,  0.98242317,  0.94073107,
        0.92669309,  0.85105037,  0.82050673,  0.78493606,  0.73703611,
        0.71261745,  0.66860272,  0.64020402,  0.60962689,  0.57104641,
        0.53310292,  0.52041517,  0.49945761,  0.47737741,  0.45625857,
        0.42898426,  0.41355998,  0.40551851,  0.38799831,  0.37415785,
        0.36507975,  0.3432782 ,  0.32321921,  0.31193795,  0.29537462,
        0.28666085,  0.2749844 ,  0.25767507,  0.2490437 ,  0.24022598,
        0.23470545,  0.22732804,  0.22029144,  0.21318807,  0.20302671,
        0.18985496,  0.18323276,  0.17299429,  0.16678832,  0.16109752,
        0.15735228,  0.15132755,  0.14379988,  0.13590874,  0.12996159,
        0.12708604,  0.12091589,  0.11276615,  0.10854246,  0.10564669,
        0.10247818,  0.09894726,  0.09647812,  0.09465916,  0.08767427,
        0.08408   ,  0.08011432,  0.07684869,  0.07435759,  0.07125115])
In [84]:
clf.loss_#损失函数

Out[84]:

<sklearn.ensemble.gradient_boosting.MultinomialDeviance at 0x1c0a8c09320>
In [86]:
clf.estimators_ 
 

XGboost

In [87]:
from xgboost import XGBClassifier
In [88]:
model = XGBClassifier()
model.fit(Xtrain, ytrain)

 
 
Out[88]:
XGBClassifier(base_score=0.5, booster='gbtree', colsample_bylevel=1,
       colsample_bynode=1, colsample_bytree=1, gamma=0, learning_rate=0.1,
       max_delta_step=0, max_depth=3, min_child_weight=1, missing=None,
       n_estimators=100, n_jobs=1, nthread=None,
       objective='multi:softprob', random_state=0, reg_alpha=0,
       reg_lambda=1, scale_pos_weight=1, seed=None, silent=None,
       subsample=1, verbosity=1)
In [90]:
y_pred = model.predict(Xtest)
In [92]:
accuracy_score(ytest,y_pred)
Out[92]:
1.0
In [93]:
XGBClassifier?
使用网格搜索调整参数
In [2]:
from sklearn.model_selection import GridSearchCV #网格参数模块
In [3]:
GridSearchCV?
Parameters:

  estimator:所使用的分类器,或者pipeline

  param_grid:值为字典或者列表,即需要最优化的参数的取值

  scoring:准确度评价标准,默认None,这时需要使用score函数;或者如scoring='roc_auc',根据所选模型不同,评价准则不同。字符串(函数名),或是可调用对象,需要其函数签名形如:scorer(estimator, X, y);如果是None,则使用estimator的误差估计函数。

  n_jobs:并行数,int:个数,-1:跟CPU核数一致, 1:默认值。

  pre_dispatch:指定总共分发的并行任务数。当n_jobs大于1时,数据将在每个运行点进行复制,这可能导致OOM,而设置pre_dispatch参数,则可以预先划分总共的job数量,使数据最多被复制pre_dispatch次

  iid:默认True,为True时,默认为各个样本fold概率分布一致,误差估计为所有样本之和,而非各个fold的平均。

  cv:交叉验证参数,默认None,使用三折交叉验证。指定fold数量,默认为3,也可以是yield训练/测试数据的生成器。

  refit:默认为True,程序将会以交叉验证训练集得到的最佳参数,重新对所有可用的训练集与开发集进行,作为最终用于性能评估的最佳模型参数。即在搜索参数结束后,用最佳参数结果再次fit一遍全部数据集。

  verbose:日志冗长度,int:冗长度,0:不输出训练过程,1:偶尔输出,>1:对每个子模型都输出

 

Attributes:

  bestestimator:效果最好的分类器

  bestscore:成员提供优化过程期间观察到的最好的评分

  bestparams:描述了已取得最佳结果的参数的组合

  bestindex:对应于最佳候选参数设置的索引(cvresults数组的索引)

In [68]:
#对基分类器的最佳数量,划分子节点最小样本数,最大深度 进行网格搜索
param_grid1 = {'n_estimators':list(range(10,100,10))}
estimator1=RandomForestClassifier(min_samples_split=100,
#min_samples_split内部节点在划分所需要的最小样本数100,min_samples_leaf叶子节点最小样本数20
#max_depth最大深度8,max_features最大特特征数8 ,random_state=10 随机数种子,不使用袋外数据
min_samples_leaf=20,max_depth=8,max_features="sqrt",random_state=10)
gsearch1 = GridSearchCV(estimator =estimator1,
param_grid = param_grid1,cv=5,return_train_score=True) #scoring='roc_auc')#模型选用RandomForestClassifier,评估指标选用准确率,迭代5次,注意,scoring='roc_auc'只能用于二分类问题
In [20]:
RandomForestClassifier?
In [69]:
gsearch1.fit(Xtrain,ytrain)

Out[69]:

GridSearchCV(cv=5, error_score='raise',
       estimator=RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=8, max_features='sqrt', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=20, min_samples_split=100,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=10, verbose=0, warm_start=False),
       fit_params=None, iid=True, n_jobs=1,
       param_grid={'n_estimators': [10, 20, 30, 40, 50, 60, 70, 80, 90]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score=True,
       scoring=None, verbose=0)
In [39]:
GridSearchCV?
貌似对iri数据而言效果并不好
In [70]:
gsearch1.cv_results_
 
In [71]:
gsearch1.best_estimator_#得分最高的分类器
Out[71]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=8, max_features='sqrt', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=20, min_samples_split=100,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=10, verbose=0, warm_start=False)
In [72]:
gsearch1.best_score_#z最高评分,
Out[72]:
0.3482142857142857
In [73]:
gsearch1.best_params_ #基分类器最佳数量
Out[73]:
{'n_estimators': 10}
In [74]:
gsearch1.best_index_ #最佳值的索引

Out[74]:

0
In [75]:
gsearch1.scorer_ 
Out[75]:
<function sklearn.metrics.scorer._passthrough_scorer>
In [76]:
gsearch1.n_splits_ #迭代数量

Out[76]:

5
 

对金融数据而言效果又还行

In [77]:
train = pd.read_csv("train_modified.csv")
target='Disbursed'
IDcol = 'ID'
x_columns = [x for x in train.columns if x not in [target, IDcol]]
X = train[x_columns]
y = train['Disbursed']
 
In [78]:
gsearch1.fit(X,y)
Out[78]:
GridSearchCV(cv=5, error_score='raise',
       estimator=RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=8, max_features='sqrt', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=20, min_samples_split=100,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=10, verbose=0, warm_start=False),
       fit_params=None, iid=True, n_jobs=1,
       param_grid={'n_estimators': [10, 20, 30, 40, 50, 60, 70, 80, 90]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score=True,
       scoring=None, verbose=0)
In [79]:
gsearch1.best_estimator_
Out[79]:
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=8, max_features='sqrt', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=20, min_samples_split=100,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=10, verbose=0, warm_start=False)
In [80]:
gsearch1.cv_results_
 
In [81]:
gsearch1.best_params_
Out[81]:
{'n_estimators': 10}
In [82]:
gsearch1.best_score_

Out[82]:

0.984
In [84]:
#对划分子节点最小样本数,最大深度 进行网格搜索
param_grid2 = {'min_samples_split':list(range(50,201,20)),"max_depth":list(range(2,15,2))}
estimator1=RandomForestClassifier(n_estimators=10,
#min_samples_split内部节点在划分所需要的最小样本数100,min_samples_leaf叶子节点最小样本数20
#max_depth最大深度8,max_features最大特特征数8 ,random_state=10 随机数种子,不使用袋外数据
min_samples_leaf=20,max_features="sqrt",random_state=10)
gsarch2 = GridSearchCV(estimator =estimator1,
8
param_grid = param_grid2,scoring='roc_auc',cv=5,return_train_score=True) #scoring='roc_auc')#模型选用RandomForestClassifier,评估指标选用准确率,迭代5次,注意,scoring='roc_auc'只能用于二分类问题

 

In [85]:
gsearch2.fit(X,y)
Out[85]:
GridSearchCV(cv=5, error_score='raise',
       estimator=RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
            max_depth=None, max_features='sqrt', max_leaf_nodes=None,
            min_impurity_decrease=0.0, min_impurity_split=None,
            min_samples_leaf=20, min_samples_split=2,
            min_weight_fraction_leaf=0.0, n_estimators=10, n_jobs=1,
            oob_score=False, random_state=10, verbose=0, warm_start=False),
       fit_params=None, iid=True, n_jobs=1,
       param_grid={'min_samples_split': [50, 70, 90, 110, 130, 150, 170, 190], 'max_depth': [2, 4, 6, 8, 10, 12, 14]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score=True,
       scoring='roc_auc', verbose=0)
In [87]:
gsearch2.cv_results_
 
In [89]:
gsearch2.best_params_
Out[89]:
{'max_depth': 12, 'min_samples_split': 170}
In [90]:
gsearch2.best_score_
Out[90]:
0.8136849752286583
In [91]:
rf1 = RandomForestClassifier(n_estimators= 10, max_depth=12,
min_samples_split=170,
min_samples_leaf=20,max_features='sqrt',oob_score=True, random_state=10)
rf1.fit(X,y)
rf1.oob_score_
Out[91]:
0.984
 

posted on 2019-11-22 15:27  11-21  阅读(430)  评论(0编辑  收藏  举报

导航