金融风控-Task4学习笔记

本文介绍了阿里云天池龙珠计划金融风控训练营中的关键知识点,包括逻辑回归模型的原理、非线性决策边界、树模型(决策树与随机森林)、集成模型(如XGBoost与LightGBM)以及模型调参策略。通过实例演示,深入浅出地讲解了各类模型的应用和优化技巧。
摘要由CSDN通过智能技术生成

本学习笔记为阿里云天池龙珠计划金融风控训练营的学习内容,学习链接为:https://tianchi.aliyun.com/specials/activity/promotion/aicampfr

一、学习知识点概要

1.逻辑回归模型
2.树模型
3.集成模型
4.模型调参

二、学习内容

1、逻辑回归模型

  • 逻辑回归一种线性回归模型,它假设数据服从伯努利分布,通过极大似然函数的方法,运用梯度下降法来求解参数,进而大道二分类的目的。
  • 逻辑回归,不是回归,而是分类器,二分类,多分类。
  • 逻辑回归分类示例(线性判定边界):
    在这里插入图片描述
    数据在空间的分布,代码如下:
from numpy import loadtxt, where
from pylab import scatter, show, legend, xlabel, ylabel
 
#load the dataset
data = loadtxt('/home/HanXiaoyang/data/data1.txt', delimiter=',')
 
X = data[:, 0:2]
y = data[:, 2]
 
pos = where(y == 1)
neg = where(y == 0)
scatter(X[pos, 0], X[pos, 1], marker='o', c='b')
scatter(X[neg, 0], X[neg, 1], marker='x', c='r')
xlabel('Feature1/Exam 1 score')
ylabel('Feature2/Exam 2 score')
legend(['Fail', 'Pass'])
show()

在这里插入图片描述
计算sigmoid函数、代价函数、和梯度下降的程序:

def sigmoid(X):
    '''Compute sigmoid function '''
    den =1.0+ e **(-1.0* X)
    gz =1.0/ den
    return gz
def compute_cost(theta,X,y):
    '''computes cost given predicted and actual values'''
    m = X.shape[0]#number of training examples
    theta = reshape(theta,(len(theta),1))
    
    J =(1./m)*(-transpose(y).dot(log(sigmoid(X.dot(theta))))- transpose(1-y).dot(log(1-sigmoid(X.dot(theta)))))
    
    grad = transpose((1./m)*transpose(sigmoid(X.dot(theta))- y).dot(X))
    #optimize.fmin expects a single value, so cannot return grad
    return J[0][0]#,grad
def compute_grad(theta, X, y):
    '''compute gradient'''
    theta.shape =(1,3)
    grad = zeros(3)
    h = sigmoid(X.dot(theta.T))
    delta = h - y
    l = grad.size
    for i in range(l):
        sumdelta = delta.T.dot(X[:, i])
        grad[i]=(1.0/ m)* sumdelta *-1
    theta.shape =(3,)
    return  grad

在这里插入图片描述
使用我们的判定边界对training data做一个预测,然后比对一下准确率:

def predict(theta, X):
    '''Predict label using learned logistic regression parameters'''
    m, n = X.shape
    p = zeros(shape=(m,1))
    h = sigmoid(X.dot(theta.T))
    for it in range(0, h.shape[0]):
        if h[it]>0.5:
            p[it,0]=1
        else:
            p[it,0]=0
    return p
#Compute accuracy on our training set
p = predict(array(theta), it)
print'Train Accuracy: %f'%((y[where(p == y)].size / float(y.size))*100.0)

计算出来的结果是89.2%

  • 逻辑回归分类示例(非线性判定边界):
    在这里插入图片描述
    要对给定的两个feature做一个多项式特征的映射
def map_feature(x1, x2):
    '''
    Maps the two input features to polonomial features.
    Returns a new feature array with more features of
    X1, X2, X1 ** 2, X2 ** 2, X1*X2, X1*X2 ** 2, etc...
    '''
    x1.shape =(x1.size,1)
    x2.shape =(x2.size,1)
    degree =6
    mapped_fea = ones(shape=(x1[:,0].size,1))
    m, n = mapped_fea.shape
    for i in range(1, degree +1):
        for j in range(i +1):
            r =(x1 **(i - j))*(x2 ** j)
            mapped_fea = append(mapped_fea, r, axis=1)
    return mapped_fea
mapped_fea = map_feature(X[:,0], X[:,1])

梯度下降和在数据点上画出判定边界后得到
在这里插入图片描述

2、树模型

在这里插入图片描述

  • 创建决策树所需要用到的函数:
    1、createDataSet():创建数据集
    2、calShannoEnt(dataSet):计算香农熵
    3、splitDataSet(dataSet,axis, value):根据特征划分数据集
    4、chooseBestFeaturesToSplit(dataSet):选择最佳特征
    5、majorityCnt(classList):确定类别
    6、createTree(dataSet, labels, featLabels):创建决策树
  • 创建数据集
def createDataSet(): 
    dataSet = [
        [0,0,0,0,'no'],
        [0,0,0,1,'no'],
        [0,1,0,1,'yes'],
        [0,1,1,0,'yes'],
        [0,0,0,0,'no'],
        [1,0,0,0,'no'],
        [1,0,0,1,'no'],
        [1,1,1,1,'yes'],
        [1,0,1,1,'yes'],
        [1,0,1,2,'yes'],
        [2,0,1,2,'yes'],
        [2,0,1,1,'yes'],
        [2,1,0,1,'yes'],
        [2,1,0,2,'yes'],
        [2,0,0,0,'no']
    ]
    labels = ['年龄', '有工作', '有自己的房子', '信贷情况']
    return dataSet,labels

  • 计算香农熵
"""
    函数说明:
        计算数据集的香农熵
    param :dataSet-数据集
    return:  shannonEnt-香农熵
    """
def calShannoEnt(dataSet):
    numEntires = len(dataSet)   #数据集行数
    labelCounts = {}    #该字典用于保存每个标签出现的次数
    for featVec in dataSet:
        currentLabel = featVec[-1]  #for循环,来处理每一个数据的标签
        if currentLabel not in labelCounts.keys():  #对字典进行初始化
            labelCounts[currentLabel] = 0   #令两类初始值分别为0
        labelCounts[currentLabel] += 1  #统计数据

    shannonEnt = 0.0
    for key in labelCounts:     #根据公式,利用循环求香农熵
        prob = float(labelCounts[key])/numEntires
        shannonEnt -= prob*log(prob,2)
    return shannonEnt

  • 划分数据
def splitDataSet(dataSet,axis, value):
    """
    函数说明:
        对数据集根据某个特征进行划分
    :param dataSet: 被划分的数据集
    :param axis: 划分根据的特征
    :param value: 需要返回的特征的值
    :return: 无
    """
    retDataSet = []     #建立空列表,存储返回的数据集
    for featVec in dataSet:     #遍历数据,一个对象一个对象的进行操作
        if featVec[axis] == value:      #找到axis特征,等于value值得数据
            reducedFeatVec = featVec[:axis]    #选出去除axis特征,只保留其他特征的数据
            reducedFeatVec.extend(featVec[axis+1:])     #保留后面的
            retDataSet.append(reducedFeatVec)       #对数据进行连接,按照列表形式
    return retDataSet   #返回划分后被取出的数据集,即满足条件的数据


  • 选择最佳分类属性
def chooseBestFeaturesToSplit(dataSet):
    """
    函数说明:
        选择最佳的分类属性
    :param :dataSet-数据集
    :return: bestFeature-最佳划分属性
    """
    numFeatures = len(dataSet[0]) - 1       #特征数量,去除最后一个标签值
    baseEntropy = calShannoEnt(dataSet)     #计算原始数据的香农熵
    bestInfoGain = 0.0      #信息增益初始化
    bestFeature = -1        #最有特征索引
    for i in range(numFeatures):        #遍历所有特征
        #该特征的所有值,组成的列表
        featList = [example[i] for example in dataSet]
        uniqueVals = set(featList)      #创建集合,元素不可重复
        newEntropy = 0.0        #经验条件熵
        for value in uniqueVals:        #计算信息增益
            #根据第i特征,value值对数据进行划分
            subDataSet = splitDataSet(dataSet, i, value)
            #求划分后数据的经验条件熵
            prob = len(subDataSet)/float(len(dataSet))
            newEntropy += prob * calShannoEnt(subDataSet)
        infoGain = baseEntropy - newEntropy     #求划分前后的信息增益
        print("第%d个特征的增益是%.3f" %(i,infoGain))
        if(infoGain > bestInfoGain):
            bestInfoGain = infoGain
            bestFeature = i
    return bestFeature

  • 选择类别
def majorityCnt(classList):
    """
    函数说明:
        当划分结束,遍历所有特征,但是依然不能彻底划分数据时
        将这多个类别中,出现次数最多的作为该类别
    :param classList-类别列表
    :return: sortedClassCount[0][0]-类别
    """
    classCount = {}
    for vote in classList:
        if vote not in classCount.keys():
            classCount[vote] = 0
        classCount[vote] += 1       #统计出现各个类别出现的次数
    #对类别列表进行排序
    sortedClassCount = sorted(classCount.items(), key=operator.itemgetter(1), reverse = True)
    return sortedClassCount[0][0]

  • 创建决策树
def createTree(dataSet, labels, featLabels):
    """
    函数说明:
        创建决策树
    :param dataSet-训练集
    :param labels-训练集数据标签
    :param featLabels:
    :return:
    """
    classList = [example[-1] for example in dataSet]        #取分类标签(是否放贷:yes or no)
    #注意条件,对列表的某一类计数,若为列表长度,则类别完全相同
    if classList.count(classList[0]) == len(classList):      #如果类别完全相同则停止继续划分
        return classList[0]
    if len(dataSet[0]) == 1:         #遍历完所有特征时返回出现次数最多的类标签
        return majorityCnt(classList)
    bestFeat = chooseBestFeaturesToSplit(dataSet)       #最优特征
    bestFeatLabel = labels[bestFeat]        #最优特征的标签
    featLabels.append(bestFeatLabel)        #
    myTree = {bestFeatLabel:{}}     #根据最优特征的标签建立决策树
    del(labels[bestFeat])       #删除已经使用的特征标签
    #训练集中,最优特征所对应的所有数据的值
    featValues = [example[bestFeat] for example in dataSet]
    uniqueVals = set(featValues)        #去掉重复特征
    for value in uniqueVals:        #遍历特征创建决策树
        #通过此句实现字典的叠加
        myTree[bestFeatLabel][value] = createTree(splitDataSet(dataSet, bestFeat, value),labels,featLabels)
    return myTree

3、集成模型

在这里插入图片描述

  • 随机森林模型

  • Bagging即套袋法,其算法过程如下:

    (A)从原始样本集中抽取训练集。每轮从原始样本集中使用Bootstraping的方法抽取n个训练样本(有放回的抽样)。共进行k轮抽取,得到k个训练集。(k个训练集之间是相互独立的)

    (B)每次使用一个训练集得到一个模型,k个训练集共得到k个模型。

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

  • XGBoost模型
    在这里插入图片描述

我们把一个家庭的成员分成不同的叶子,并把他们分配到相应的叶子节点上。 CART 与 decision trees(决策树)有些许的不同,就是叶子只包含决策值。在 CART 中,每个叶子都有一个 real score(真实的分数).

使用多棵树预测
在这里插入图片描述
树的集成归根到底是Boosting模型,Boosting的实质是个加性模型。
在这里插入图片描述

categorical_features_indices = np.where(X_train.dtypes != np.float)[0]
model = CatBoostClassifier(iterations=100, depth=5,cat_features=categorical_features_indices,learning_rate=0.5, loss_function='Logloss',
                            logging_level='Verbose')

然后将数据进行训练,通过plot = True,还可以将损失函数可视化。

model.fit(X_train,y_train,eval_set=(X_validation, y_validation),plot=True)

训练结束后,通过model.feature_importances_属性,我们可以拿到这些特征的重要程度数据,特征的重要性程度可以帮助我们分析出一些有用的信息。

import matplotlib.pyplot as plt 
fea_ = model.feature_importances_
fea_name = model.feature_names_
plt.figure(figsize=(10, 10))
plt.barh(fea_name,fea_,height =0.5)

4、模型调参

  • 贪心调参

  • 日常调参过程中常用的参数和调参顺序:

    ①:max_depth、num_leaves
    ②:min_data_in_leaf、min_child_weight
    ③:bagging_fraction、 feature_fraction、bagging_freq
    ④:reg_lambda、reg_alpha
    ⑤:min_split_gain

  • 网格搜索

  • sklearn 提供GridSearchCV用于进行网格搜索,只需要把模型的参数输进去,就能给出最优化的结果和参数。相比起贪心调参,网格搜索的结果会更优,但是网格搜索只适合于小数据集,一旦数据的量级上去了,很难得出结果。

  • 贝叶斯调参

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

"""定义优化函数"""
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
"""定义优化参数"""
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.max
{'target': 0.7282530196283977,
 'params': {'bagging_fraction': 0.9815471914843896,
  'bagging_freq': 96.14757648686668,
  'feature_fraction': 0.6961281791730929,
  'max_depth': 19.45450235568963,
  'min_child_weight': 1.6266132496156782,
  'min_data_in_leaf': 37.697878831472295,
  'min_split_gain': 0.4184947943942168,
  'num_leaves': 14.221122487200399,
  'reg_alpha': 7.056502173310882,
  'reg_lambda': 9.924023764203156}}

三、学习问题与解答

在这里插入图片描述
在这里插入图片描述

寻求解决方法

四、学习思考与总结

这一部分内容有点多,主要是对各种模型的了解,树模型跟之前数据结构学过的内容有点像,稍稍能够理解一点。逻辑回归模型跟之前学过的线性回归有关联,像是被掰弯的线性回归。集成模型的种类有点多,根据它们的思想分为几种类型,但是还是很难去理解它,总觉得和树模型有点像,跟之前学过的二叉树也有那么一点相似,总之,是非常的乱了……

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值