【数据挖掘】金融风控 Task04 建模与调参

  • 1. 常用模型对比及评估
  • 1.1. 逻辑回归与决策树模型
  • 1.2 集成方法
  • 1.2.1 bagging
  • 1.2.2 boosting
  • 1.2.3 bagging与boosting区别
  • 1.3 模型评估方法
  • 1.3.1 数据集划分条件
  • 1.3.2 数据集划分方法
  • 1.3.3 模型评价标准
  • 2. 模型训练
  • 2.1 导入数据并进行预处理
  • 2.2 使用lgb进行预测
  • 2.2.1 使用lgb进行预测
  • 2.2.2 对验证集进行预测,并画出roc曲线
  • 2.2.3 使用k折交叉验证进行模型评估
  • 2.3 模型调参
  • 2.3.1 贪心调参
  • 2.3.2 网格搜索
  • 2.3.3 贝叶斯调参
  • 2.4 调整参数后重新对验证集进行验证
  • 2.5 保存模型
  • 3.相关资料



1. 常用模型对比及评估

1.1. 逻辑回归与决策树模型

优点

缺点

逻辑回归

- 训练速度较快,分类的时候,计算量仅仅只和特征的数目相关;

- 简单易理解,模型的可解释性非常好,从特征的权重可以看到不同的特征对最后结果的影响;

- 适合二分类问题,不需要缩放输入特征;

- 内存资源占用小,只需要存储各个维度的特征值;

逻辑回归需要预先处理缺失值和异常值;

- 不能用Logistic回归去解决非线性问题,因为Logistic的决策面是线性的;

- 对多重共线性数据过于敏感,且很难处理数据不平衡的问题;

- 准确率并非很高,因为形式非常简单,很难去拟合数据的真实分布;

决策树

- 简单直观,生成的决策树可以可视化展示

- 数据不需要预先,不需要归一化,不需要处理缺失数据

- 既可以处理离散值,也可以处理连续值

- 决策树算法非常容易过拟合,导致泛化能力不强(可进行适当的剪枝)

- 采用的是贪心算法,容易得到局部最优解

1.2 集成方法

通过组合多个学习器来完成学习任务,通过集成方法,可以将多个弱学习器组合成一个强分类器,因此集成学习的泛化能力一般比单一分类器要好。

金融估值python 金融估值建模总结_金融估值python

集成方法主要包括装袋和装卸,装袋和装卸都是将现有的分类或回归算法通过某种方式组合起来,形成一个更加强大的分类。两种方法都是把几个分类器整合为一个分类器的常见的基于Baggin思想的集成模型有:随机森林,基于Boosting思想的集成模型有:Adaboost,GBDT,XgBoost,LightGBM等。

1.2.1 bagging

金融估值python 金融估值建模总结_数据_02


Bagging即套袋法,先说一下bootstrap,bootstrap也称为自助法,它是一种有放回的抽样方法,目的为了得到统计量的分布以及置信区间,其算法过程如下:

A)从原始样本集中抽取训练集。每轮从原始样本集中使用Bootstraping的方法抽取n个训练样本(在训练集中,有些样本可能被多次抽取到,而有些样本可能一次都没有被抽中)。共进行k轮抽取,得到k个训练集。(k个训练集之间是相互独立的)

B)每次使用一个训练集得到一个模型,k个训练集共得到k个模型。(注:这里并没有具体的分类算法或回归方法,我们可以根据具体问题采用不同的分类或回归方法,如决策树、感知器等)

C)对分类问题:将上步得到的k个模型采用投票的方式得到分类结果;对回归问题,计算上述模型的均值作为最后的结果。(所有模型的重要性相同)

1.2.2 boosting

金融估值python 金融估值建模总结_数据_03


其主要思想是将弱分类器组装成一个强分类器。在PAC(probably approximately correct,概率近似正确)学习框架下,则一定可以将弱分类器组装成一个强分类器。

关于Boosting的两个核心问题:

1)在每一轮如何改变训练数据的权值或概率分布?

通过提高那些在前一轮被弱分类器分错样例的权值,减小前一轮分对样例的权值,来使得分类器对误分的数据有较好的效果。

2)通过什么方式来组合弱分类器?

通过加法模型将弱分类器进行线性组合,比如:

- AdaBoost(Adaptive boosting)算法:刚开始训练时对每一个训练例赋相等的权重,然后用该算法对训练集训练t轮,每次训练后,对训练失败的训练例赋以较大的权重,也就是让学习算法在每次学习以后更注意学错的样本,从而得到多个预测函数。通过拟合残差的方式逐步减小残差,将每一步生成的模型叠加得到最终模型。

- GBDT(Gradient Boost Decision Tree),每一次的计算是为了减少上一次的残差,GBDT在残差减少(负梯度)的方向上建立一个新的模型。

1.2.3 bagging与boosting区别

1、Bagging和Boosting的区别:
(1)样本选择上:

  • Bagging:训练集是在原始集中有放回选取的,从原始集中选出的各轮训练集之间是独立的。
  • Boosting:每一轮的训练集不变,只是训练集中每个样例在分类器中的权重发生变化。而权值是根据上一轮的分类结果进行调整。

(2)样例权重:

  • Bagging:使用均匀取样,每个样例的权重相等
  • Boosting:根据错误率不断调整样例的权值,错误率越大则权重越大。

(3)预测函数:

  • Bagging:所有预测函数的权重相等。
  • Boosting:每个弱分类器都有相应的权重,对于分类误差小的分类器会有更大的权重。
    (4)并行计算:
  • Bagging:各个预测函数可以并行生成
  • Boosting:各个预测函数只能顺序生成,因为后一个模型参数需要前一轮模型的结果。

1.3 模型评估方法

对于模型来说,在其训练集上面的误差称之为训练误差或者经验误差,在而集测试的上称之为误差测试误差。

我们通常将已有的数据集划分为训练集和测试集两部分,其中训练集使用训练模型,而测试集则是用来评估模型关于新样本的判别能力的。

1.3.1 数据集划分条件

  • 训练集和测试集的分布要与样本真实分布一致,即训练集和测试集要保证是从样本真实分布中独立同分布采样而得;
  • 训练集和测试集要互斥

1.3.2 数据集划分方法

  • ①留出法

留出法是直接将数据集D划分为两个互斥的集合,其中一个集合作为训练集S,另一个作为测试集T。需要注意的是在划分的时候要保证数据分布的一致性,即避免因数据分割过程约会额外的偏差而对最终结果产生影响。为了保证数据分布的一致性,通常我们采用分段采样的方式来对数据进行采样。

提示:通常,重置数据集D中大约2/3〜4/5的样本作为训练集,其余的作为测试集。

  • ②交叉验证法

k折除验证通常将数据集D分为k份,其中k-1份作为训练集,剩余的一份作为测试集,这样就可以获得k组训练/测试集,可以进行k次训练与测试,最终返回的是k个测试结果的均值。对验证中数据集的划分依然是依据分段采样的方式来进行。

对于交叉验证法,其k值的选取经常决定了评估结果的稳定性和保真性,通常k值选取10。

当k = 1的时候,我们称为留一法

  • ③自助法

我们每次从数据集D中取一个样本作为训练集中的元素,然后把该样本放回,重复该行为m次,这样我们就可以得到大小为m的训练集,在这里面有的样本重复出现,有的样本则没有出现过,我们把那些没有出现过的样本作为测试集。

进行这样采样的原因是因为在D中约有36.8%的数据没有在训练集中出现过。留出法与交叉验证法都是使用分层采样的方式进行数据采样与划分,而自助法则是使用有放回重复采样的方式进行数据采样

1.3.3 模型评价标准

常见的标准有auc、ks、f1-score,具体见
【数据挖掘】金融风控 Task01 赛题理解


2. 模型训练

2.1 导入数据并进行预处理

导入相关包及配置

import pandas as pd 
import numpy as np
import warnings
warnings.filterwarnings('ignore')
import matplotlib.pyplot as plt
import seaborn as sns
import os
'''
sns相关配置
'''
#声明seaborn配置
sns.set()
#有五种seaborn绘图风格,它们分别是:darkgrid, whitegrid, dark, white, ticks。默认的主题是darkgrid。
sns.set_style('whitegrid')
#有四种预置环境,按大小从小到大排列分别为paper, notebook, talk, poster。其中,notebook是默认的。
sns.set_context('talk')
#中文字体设置-黑体
plt.rcParams['font.sans-serif'] = ['SimHei']
# 解决保存图像是负号'-'显示为方块的问题
plt.rcParams['axes.unicode_minus'] = False
# 解决Seaborn中文显示问题并调整字体大小
sns.set(font='SimHei')

读取数据,此处定义了一个reduce_mem_usage函数来调整数据类型,以减少数据在内存中占用的空间

def reduce_mem_usage(df):
    #利用start_mem来记录最开始的内存空间
    start_mem=df.memory_usage().sum()
    print('最开始dataframe占用的空间是{:.2f}MB'.format(start_mem))
    
    for col in df.columns: #col_type是df每个属性的类型
        col_type = df[col].dtype
        
        if col_type!=object: #如果不是对象类型
            c_max=df[col].max()
            c_min=df[col].min()
            
            #对int类型的进行处理
            if str(col_type)[:3]=='int':
                #通过iinfo来获得某个属性的最大/最小值
                if c_min > np.iinfo(np.int8).min and c_max < np.iinfo(np.int8).max:
                    df[col] = df[col].astype(np.int8)
                elif c_min > np.iinfo(np.int16).min and c_max < np.iinfo(np.int16).max:
                    df[col] = df[col].astype(np.int16)
                elif c_min > np.iinfo(np.int32).min and c_max < np.iinfo(np.int32).max:
                    df[col] = df[col].astype(np.int32)
                elif c_min > np.iinfo(np.int64).min and c_max < np.iinfo(np.int64).max:
                    df[col] = df[col].astype(np.int64)  
                    
                    
            else:
                if c_min > np.finfo(np.float16).min and c_max < np.finfo(np.float16).max:
                    df[col] = df[col].astype(np.float16)
                elif c_min > np.finfo(np.float32).min and c_max < np.finfo(np.float32).max:
                    df[col] = df[col].astype(np.float32)
                else:
                    df[col] = df[col].astype(np.float64)
                    
        else:
            df[col] = df[col].astype('category')
            '''
            实际应用pandas过程中,经常会用到category数据类型,
            通常以string的形式显示,包括颜色(红,绿,蓝),
            尺寸的大小(大,中,小),还有地理信息等(国家,省份)
            category类型处理
            '''
    end_mem=df.memory_usage().sum()
    print('经过处理后dataframe占用的空间是{:.2f}MB'.format(end_mem))
    print('节省的空间为{:.1f}%'.format(100 * (start_mem - end_mem) / start_mem))
    
    return df

读取训练集和测试集

#读取训练集
data_train=pd.read_csv('train.csv')
data_train=reduce_mem_usage(data_train)

金融估值python 金融估值建模总结_数据集_04

#读取测试集
data_test_a=pd.read_csv('testA.csv')
data_test_a=reduce_mem_usage(data_test_a)

金融估值python 金融估值建模总结_金融估值python_05


待补充特征工程部分

在这里插入代码片

切分标签

X_train=data_train.drop(['id','issueDate','isDefault'], axis=1)
y_train=data_train['isDefault']

划分训练集和验证集

X_train=data_train.drop(['id','issueDate','isDefault'], axis=1)
y_train=data_train['isDefault']

2.2 使用lgb进行预测

2.2.1 使用lgb进行预测

'''
很清晰的构建数据方式,记住这种用法
指定 feature names(特征名称)和 categorical features(分类特征):
train_data = lgb.Dataset(data, label=label, feature_name=['c1', 'c2', 'c3'], categorical_feature=['c3'])
'''

#将训练集和测试集分别放入到lgb模型中
train_matrix=lgb.Dataset(X_train_split,label=y_train_split)
valid_matrix=lgb.Dataset(X_val,label=y_val)
#设置lgb参数
params = {
            'boosting_type': 'gbdt', #boosting类型
            'objective': 'binary',
            'learning_rate': 0.1,   #学习率
            'metric': 'auc',       #评价标准auc
            'min_child_weight': 1e-3,  #最小权值10的负三次方
            'num_leaves': 31,  #叶子节点数
            'max_depth': -1,  #最大深度
            'reg_lambda': 0,
            'reg_alpha': 0,
            'feature_fraction': 1,
            'bagging_fraction': 1,
            'bagging_freq': 0,
            'seed': 2020,
            'nthread': 8,
            'silent': True,
            'verbose': -1,
}
#使用训练集进行训练
model=lgb.train(params,train_set=train_matrix,valid_sets=valid_matrix,num_boost_round=20000,verbose_eval=1000,early_stopping_rounds=2000)

金融估值python 金融估值建模总结_数据_06

2.2.2 对验证集进行预测,并画出roc曲线

from sklearn import metrics
from sklearn.metrics import roc_auc_score

"""预测并计算roc的相关指标"""
val_pre_lgb = model.predict(X_val, num_iteration=model.best_iteration)
fpr, tpr, threshold = metrics.roc_curve(y_val, val_pre_lgb)
roc_auc = metrics.auc(fpr, tpr)
print('未调参前lightgbm单模型在验证集上的AUC:{}'.format(roc_auc))
"""画出roc曲线图"""
plt.figure(figsize=(8, 8))
plt.title('Validation ROC')
plt.plot(fpr, tpr, 'b', label = 'Val AUC = %0.4f' % roc_auc)
plt.ylim(0,1)
plt.xlim(0,1)
plt.legend(loc='best')
plt.title('ROC')
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
# 画出对角线
plt.plot([0,1],[0,1],'r--')
plt.show()

金融估值python 金融估值建模总结_数据集_07

2.2.3 使用k折交叉验证进行模型评估

import lightgbm as lgb
from sklearn.model_selection import KFold 
"""使用lightgbm 5折交叉验证进行建模预测"""

folds = 5
seed = 2020
kf = KFold(n_splits=folds, shuffle=True, random_state=seed)

cv_scores = []
for i, (train_index, valid_index) in enumerate(kf.split(X_train, y_train)):
    print('************************************ {} ************************************'.format(str(i+1)))
    X_train_split, y_train_split, X_val, y_val = X_train.iloc[train_index], y_train[train_index], X_train.iloc[valid_index], y_train[valid_index]

    train_matrix = lgb.Dataset(X_train_split, label=y_train_split)
    valid_matrix = lgb.Dataset(X_val, label=y_val)

    params = {
                'boosting_type': 'gbdt',
                'objective': 'binary',
                'learning_rate': 0.1,
                'metric': 'auc',

                'min_child_weight': 1e-3,
                'num_leaves': 31,
                'max_depth': -1,
                'reg_lambda': 0,
                'reg_alpha': 0,
                'feature_fraction': 1,
                'bagging_fraction': 1,
                'bagging_freq': 0,
                'seed': 2020,
                'nthread': 8,
                'silent': True,
                'verbose': -1,
    }

    model = lgb.train(params, train_set=train_matrix, num_boost_round=20000, valid_sets=valid_matrix, verbose_eval=1000, early_stopping_rounds=200)
    val_pred = model.predict(X_val, num_iteration=model.best_iteration)

    cv_scores.append(roc_auc_score(y_val, val_pred))
    print(cv_scores)

print("lgb_scotrainre_list:{}".format(cv_scores))
print("lgb_score_mean:{}".format(np.mean(cv_scores)))
print("lgb_score_std:{}".format(np.std(cv_scores)))

金融估值python 金融估值建模总结_金融估值python_08

2.3 模型调参

2.3.1 贪心调参

(1)思想:先使用当前对模型影响最大的参数进行调优,达到当前参数下的模型最优化,再使用对模型影响次之的参数进行调优,如此下去,直到所有的参数调整完毕。

(2)缺点:可能会调到局部最优而不是全局最优,但是只需要一步一步的进行参数最优化调试即可,容易理解。

(3)注意事项:需要注意的是在树模型中参数调整的顺序,也就是各个参数对模型的影响程度,这里列举一下日常调参过程中常用的参数和调参顺序:

  • ①:max_depth、num_leaves
  • ②:min_data_in_leaf、min_child_weight
  • ③:bagging_fraction、 feature_fraction、bagging_freq
  • ④:reg_lambda、reg_alpha
  • ⑤:min_split_gain
from sklearn.model_selection import cross_val_score

# 调objective
best_obj = dict()
for obj in objective:
    model = LGBMRegressor(objective=obj)
    """预测并计算roc的相关指标"""
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    best_obj[obj] = score
    
# num_leaves
best_leaves = dict()
for leaves in num_leaves:
    model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0], num_leaves=leaves)
    """预测并计算roc的相关指标"""
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    best_leaves[leaves] = score
    
# max_depth
best_depth = dict()
for depth in max_depth:
    model = LGBMRegressor(objective=min(best_obj.items(), key=lambda x:x[1])[0],
                          num_leaves=min(best_leaves.items(), key=lambda x:x[1])[0],
                          max_depth=depth)
    """预测并计算roc的相关指标"""
    score = cross_val_score(model, X_train, y_train, cv=5, scoring='roc_auc').mean()
    best_depth[depth] = score

"""
可依次将模型的参数通过上面的方式进行调整优化,并且通过可视化观察在每一个最优参数下模型的得分情况
"""

2.3.2 网格搜索

(1)思想:网格搜索法是指定参数值的一种穷举搜索方法,通过将估计函数的参数通过交叉验证的方法进行优化来得到最优的学习算法。即将各个参数可能的取值进行排列组合,列出所有可能的组合结果生成“网格”。然后将各组合用于SVM训练,并使用交叉验证对表现进行评估。
(2)特点:相比起贪心调参,网格搜索的结果会更优,但是网格搜索只适合于小数据集,一旦数据的量级上去了,很难得出结果。

"""通过网格搜索确定最优参数"""
from sklearn.model_selection import GridSearchCV

def get_best_cv_params(learning_rate=0.1, n_estimators=581, num_leaves=31, max_depth=-1, bagging_fraction=1.0, 
                       feature_fraction=1.0, bagging_freq=0, min_data_in_leaf=20, min_child_weight=0.001, 
                       min_split_gain=0, reg_lambda=0, reg_alpha=0, param_grid=None):
    # 设置5折交叉验证
    cv_fold = StratifiedKFold(n_splits=5, random_state=0, shuffle=True, )
    
    model_lgb = lgb.LGBMClassifier(learning_rate=learning_rate,
                                   n_estimators=n_estimators,
                                   num_leaves=num_leaves,
                                   max_depth=max_depth,
                                   bagging_fraction=bagging_fraction,
                                   feature_fraction=feature_fraction,
                                   bagging_freq=bagging_freq,
                                   min_data_in_leaf=min_data_in_leaf,
                                   min_child_weight=min_child_weight,
                                   min_split_gain=min_split_gain,
                                   reg_lambda=reg_lambda,
                                   reg_alpha=reg_alpha,
                                   n_jobs= 8
                                  )
    grid_search = GridSearchCV(estimator=model_lgb, 
                               cv=cv_fold,
                               param_grid=param_grid,
                               scoring='roc_auc'
                              )
    grid_search.fit(X_train, y_train)

    print('模型当前最优参数为:{}'.format(grid_search.best_params_))
    print('模型当前最优得分为:{}'.format(grid_search.best_score_))
"""设置n_estimators 为581,调整num_leaves和max_depth,这里选择先粗调再细调"""
lgb_params = {'num_leaves': range(10, 80, 5), 'max_depth': range(3,10,2)}
get_best_cv_params(learning_rate=0.1, n_estimators=581, num_leaves=None, max_depth=None, min_data_in_leaf=20, 
                   min_child_weight=0.001,bagging_fraction=1.0, feature_fraction=1.0, bagging_freq=0, 
                   min_split_gain=0, reg_lambda=0, reg_alpha=0, param_grid=lgb_params)

"""num_leaves为30,max_depth为7,进一步细调num_leaves和max_depth"""
lgb_params = {'num_leaves': range(25, 35, 1), 'max_depth': range(5,9,1)}
get_best_cv_params(learning_rate=0.1, n_estimators=85, num_leaves=None, max_depth=None, min_data_in_leaf=20, 
                   min_child_weight=0.001,bagging_fraction=1.0, feature_fraction=1.0, bagging_freq=0, 
                   min_split_gain=0, reg_lambda=0, reg_alpha=0, param_grid=lgb_params)

"""
确定min_data_in_leaf为45,min_child_weight为0.001 ,下面进行bagging_fraction、feature_fraction和bagging_freq的调参
"""
lgb_params = {'bagging_fraction': [i/10 for i in range(5,10,1)], 
              'feature_fraction': [i/10 for i in range(5,10,1)],
              'bagging_freq': range(0,81,10)
             }
get_best_cv_params(learning_rate=0.1, n_estimators=85, num_leaves=29, max_depth=7, min_data_in_leaf=45, 
                   min_child_weight=0.001,bagging_fraction=None, feature_fraction=None, bagging_freq=None, 
                   min_split_gain=0, reg_lambda=0, reg_alpha=0, param_grid=lgb_params)

"""
确定bagging_fraction为0.4、feature_fraction为0.6、bagging_freq为 ,下面进行reg_lambda、reg_alpha的调参
"""
lgb_params = {'reg_lambda': [0,0.001,0.01,0.03,0.08,0.3,0.5], 'reg_alpha': [0,0.001,0.01,0.03,0.08,0.3,0.5]}
get_best_cv_params(learning_rate=0.1, n_estimators=85, num_leaves=29, max_depth=7, min_data_in_leaf=45, 
                   min_child_weight=0.001,bagging_fraction=0.9, feature_fraction=0.9, bagging_freq=40, 
                   min_split_gain=0, reg_lambda=None, reg_alpha=None, param_grid=lgb_params)

"""
确定reg_lambda、reg_alpha都为0,下面进行min_split_gain的调参
"""
lgb_params = {'min_split_gain': [i/10 for i in range(0,11,1)]}
get_best_cv_params(learning_rate=0.1, n_estimators=85, num_leaves=29, max_depth=7, min_data_in_leaf=45, 
                   min_child_weight=0.001,bagging_fraction=0.9, feature_fraction=0.9, bagging_freq=40, 
                   min_split_gain=None, reg_lambda=0, reg_alpha=0, param_grid=lgb_params)
# 设置5折交叉验证
# cv_fold = StratifiedKFold(n_splits=5, random_state=0, shuffle=True, )
final_params = {
                'boosting_type': 'gbdt',
                'learning_rate': 0.01,
                'num_leaves': 29,
                'max_depth': 7,
                'min_data_in_leaf':45,
                'min_child_weight':0.001,
                'bagging_fraction': 0.9,
                'feature_fraction': 0.9,
                'bagging_freq': 40,
                'min_split_gain': 0,
                'reg_lambda':0,
                'reg_alpha':0,
                'nthread': 6
               }

cv_result = lgb.cv(train_set=lgb_train,
                   early_stopping_rounds=20,
                   num_boost_round=5000,
                   nfold=5,
                   stratified=True,
                   shuffle=True,
                   params=final_params,
                   metrics='auc',
                   seed=0,
                  )

print('迭代次数{}'.format(len(cv_result['auc-mean'])))
print('交叉验证的AUC为{}'.format(max(cv_result['auc-mean'])))

注意:在实际调整过程中,可先设置一个较大的学习率(上面的例子中0.1),通过Lgb原生的cv函数进行树个数的确定,之后再通过上面的实例代码进行参数的调整优化。

最后针对最优的参数设置一个较小的学习率(例如0.05),同样通过cv函数确定树的个数,确定最终的参数。

需要注意的是,针对大数据集,上面每一层参数的调整都需要耗费较长时间。

2.3.3 贝叶斯调参

使用贝叶斯之前需要安装bayesian-optimization

pip install bayesian-optimization

(1)思想:给定优化的目标函数(广义的函数,只需指定输入和输出即可,无需知道内部结构以及数学性质),通过不断地添加样本点来更新目标函数的后验分布(高斯过程,直到后验分布基本贴合于真实分布)。简单的说,就是考虑了上一次参数的信息,从而更好的调整当前的参数。
(2)步骤

  • 定义优化函数(rf_cv)
  • 建立模型
  • 定义待优化的参数
  • 得到优化结果,并返回要优化的分数指标
from sklearn.model_selection import cross_val_score

"""定义优化函数"""
def rf_cv_lgb(num_leaves, max_depth, bagging_fraction, feature_fraction, bagging_freq, min_data_in_leaf, 
              min_child_weight, min_split_gain, reg_lambda, reg_alpha):
    # 建立模型
    model_lgb = lgb.LGBMClassifier(boosting_type='gbdt', bjective='binary', metric='auc',
                                   learning_rate=0.1, n_estimators=5000,
                                   num_leaves=int(num_leaves), max_depth=int(max_depth), 
                                   bagging_fraction=round(bagging_fraction, 2), feature_fraction=round(feature_fraction, 2),
                                   bagging_freq=int(bagging_freq), min_data_in_leaf=int(min_data_in_leaf),
                                   min_child_weight=min_child_weight, min_split_gain=min_split_gain,
                                   reg_lambda=reg_lambda, reg_alpha=reg_alpha,
                                   n_jobs= 8
                                  )
    
    val = cross_val_score(model_lgb, X_train_split, y_train_split, cv=5, scoring='roc_auc').mean()
    
    return val
from bayes_opt import BayesianOptimization
"""定义优化参数"""
bayes_lgb = BayesianOptimization(
    rf_cv_lgb, 
    {
        'num_leaves':(10, 200),
        'max_depth':(3, 20),
        'bagging_fraction':(0.5, 1.0),
        'feature_fraction':(0.5, 1.0),
        'bagging_freq':(0, 100),
        'min_data_in_leaf':(10,100),
        'min_child_weight':(0, 10),
        'min_split_gain':(0.0, 1.0),
        'reg_alpha':(0.0, 10),
        'reg_lambda':(0.0, 10),
    }
)

"""开始优化"""
bayes_lgb.maximize(n_iter=10)
"""显示优化结果"""
bayes_lgb.max

金融估值python 金融估值建模总结_权重_09

"""调整一个较小的学习率,并通过cv函数确定当前最优的迭代次数"""
base_params_lgb = {
                    'boosting_type': 'gbdt',
                    'objective': 'binary',
                    'metric': 'auc',
                    'learning_rate': 0.01,
                    'num_leaves': 14,
                    'max_depth': 19,
                    'min_data_in_leaf': 37,
                    'min_child_weight':1.6,
                    'bagging_fraction': 0.98,
                    'feature_fraction': 0.69,
                    'bagging_freq': 96,
                    'reg_lambda': 9,
                    'reg_alpha': 7,
                    'min_split_gain': 0.4,
                    'nthread': 8,
                    'seed': 2020,
                    'silent': True,
                    'verbose': -1,
}

cv_result_lgb = lgb.cv(
    train_set=train_matrix,
    early_stopping_rounds=1000, 
    num_boost_round=20000,
    nfold=5,
    stratified=True,
    shuffle=True,
    params=base_params_lgb,
    metrics='auc',
    seed=0
)

print('迭代次数{}'.format(len(cv_result_lgb['auc-mean'])))
print('最终模型的AUC为{}'.format(max(cv_result_lgb['auc-mean'])))

金融估值python 金融估值建模总结_金融估值python_10

2.4 调整参数后重新对验证集进行验证

import lightgbm as lgb
"""使用lightgbm 5折交叉验证进行建模预测"""
cv_scores = []
for i, (train_index, valid_index) in enumerate(kf.split(X_train, y_train)):
    print('************************************ {} ************************************'.format(str(i+1)))
    X_train_split, y_train_split, X_val, y_val = X_train.iloc[train_index], y_train[train_index], X_train.iloc[valid_index], y_train[valid_index]
    
    train_matrix = lgb.Dataset(X_train_split, label=y_train_split)
    valid_matrix = lgb.Dataset(X_val, label=y_val)

    params = {
                'boosting_type': 'gbdt',
                'objective': 'binary',
                'metric': 'auc',
                'learning_rate': 0.01,
                'num_leaves': 14,
                'max_depth': 19,
                'min_data_in_leaf': 37,
                'min_child_weight':1.6,
                'bagging_fraction': 0.98,
                'feature_fraction': 0.69,
                'bagging_freq': 96,
                'reg_lambda': 9,
                'reg_alpha': 7,
                'min_split_gain': 0.4,
                'nthread': 8,
                'seed': 2020,
                'silent': True,
    }
    
    model = lgb.train(params, train_set=train_matrix, num_boost_round=14269, valid_sets=valid_matrix, verbose_eval=1000, early_stopping_rounds=200)
    val_pred = model.predict(X_val, num_iteration=model.best_iteration)
    
    cv_scores.append(roc_auc_score(y_val, val_pred))
    print(cv_scores)

print("lgb_scotrainre_list:{}".format(cv_scores))
print("lgb_score_mean:{}".format(np.mean(cv_scores)))
print("lgb_score_std:{}".format(np.std(cv_scores)))

结果为

lgb_scotrainre_list:[0.7329726464187137, 0.7294292852806246, 0.7341505801564857, 0.7328331383185244, 0.7317405262608612]
lgb_score_mean:0.732225235287042
lgb_score_std:0.0015929470575114753

2.5 保存模型

"""保存模型到本地"""
# 保存模型
import pickle
pickle.dump(final_model_lgb, open('dataset/model_lgb_best.pkl', 'wb'))