2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型

本文目录

  • 2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型
    • 题目简析
      • C题题目
      • 简单解析
    • 简单说说 LSTM
    • 项目代码
      • 数据预处理
      • 数据的导入与训练
      • 模型训练效果验证
      • 未标注公司的评估
    • 写在最后

题目简析

C题题目

首先让我们来回顾一下题目:

在实际中,由于中小微企业规模相对较小,也缺少抵押资产,因此银行通常是依据信贷政策、企业的交易票据信息和上下游企业的影响力,向实力强、供求关系稳定的企业提供贷款,并可以对信誉高、信贷风险小的企业给予利率优惠。银行首先根据中小微企业的实力、信誉对其信贷风险做出评估,然后依据信贷风险等因素来确定是否放贷及贷款额度、利率和期限等信贷策略。

某银行对确定要放贷企业的贷款额度为 10 至 100 万元;年利率为 4% 至 15%;贷款期限为 1 年。附件1~3 分别给出了123家有信贷记录企业的相关数据、302 家无信贷记录企业的相关数据和贷款利率与客户流失率关系的 2019 年统计数据。该银行请你们团队根据实际和附件中的数据信息,通过建立数学模型研究对中小微企业的信贷策略,主要解决下列问题:

(1) 对附件 1 中 123 家企业的信贷风险进行量化分析,给出该银行在年度信贷总额固定时对这些企业的信贷策略。

(2) 在问题 1 的基础上,对附件 2 中 302 家企业的信贷风险进行量化分析,并给出该银行在年度信贷总额为1亿元时对这些企业的信贷策略。

(3) 企业的生产经营和经济效益可能会受到一些突发因素影响,而且突发因素往往对不同行业、不同类别的企业会有不同的影响。综合考虑附件 2 中各企业的信贷风险和可能的突发因素(例如:新冠病毒疫情)对各企业的影响,给出该银行在年度信贷总额为 1 亿元时的信贷调整策略。

简单解析

先让我们看看附件 1 的数据

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第1张图片
其中发票号码,开票具体日期,销方单位代号属于无用信号。同时信号本身属于时序信号,故需要选用适合处理时序信息的神经网络。由于 RNN 在处理长依赖问题具有较为严重的局限性,故最终决定选用 LSTM。

简单说说 LSTM

LSTM 的 全称为 Long Short Term Memory networks,即长短期记忆网络。LSTM 是一种特殊的循环神经网络(Recurrent Neural Networks),该网络设计出来是为了解决 RNN 未能解决的长依赖问题。

所有循环神经网络都具有神经网络的重复模块链的形式。 在标准的 RNN 中,该重复模块将具有非常简单的结构,例如单个 tanh 层。标准的 RNN 网络如下图所示

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第2张图片
LSTM 也具有这种链式结构,但是它的重复单元不同于标准 RNN 网络里的单元只有一个网络层,它的内部有四个网络层,同时具有遗忘门、输入门和输出门等几个部分。LSTM 的结构如下图所示

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第3张图片
其中

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第4张图片

项目代码

笔者使用百度的 AIStudio 线上平台进行模型的训练,环境配置为 Python 2.7 与 PaddlePaddle 1.6.2

数据预处理

由于题目数据量较为庞大,数据预处理部分的工作比较繁杂,处理好的数据如下所示
2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第5张图片
从左到右分别为金额,税额,价税合计与发票状态(0 为有效发票,1 为作废发票),标签为公司评级ABCD,分别用1234表示

不想自己处理的小伙伴可以直接白嫖已经处理好的训练数据,提取码如下

链接:https://pan.baidu.com/s/1RLhF5N3EW_xkiO7QZvNH4A
提取码:fit5

数据的导入与训练

引用库文件

import numpy as np
import math
import matplotlib.pyplot as plt
import paddle
import paddle.fluid as fluid 
from __future__ import print_function

文件读入

SAVE_DIRNAME = 'model'
f = open('work/data.txt') #修改数据集文件路径
df = f.readlines()    
f.close()
data = []
for line in df:
    data_raw = line.strip('\n').strip('\r').split('\t') 
    data.append(data_raw)
data = np.array(data, dtype='float32')

打印出来查看一下

print('数据类型:',type(data))
print('数据个数:', data.shape[0])
print('数据形状:', data.shape)
print('数据第一行:', data[0])

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第6张图片

划分训练集和验证集,由于数据量较大,故将训练集的比例划分到 99%,剩余两千左右的数据作为验证

ratio = 0.99
DATA_NUM = len(data)

train_len = int(DATA_NUM * ratio)
test_len = DATA_NUM - train_len

train_data = data[:train_len]
test_data = data[train_len:]

数据归一化,由于标签值的解算较为特殊,故对归一化公式做出一些改动

def normalization(data):
    avg = np.mean(data, axis=0)
    max_ = np.max(data, axis=0)
    min_ = np.min(data, axis=0)
    #result_data = (data - avg) / (max_- min_)
    result_data = data / (max_- min_)
    print(len(result_data))
    print(result_data[:][4])
    return result_data
train_data = normalization(train_data)
test_data = normalization(test_data)

构造 paddlepaddle 的 reader

def my_train_reader():
    def reader():
        for temp in train_data:
            yield temp[:-1], temp[-1]
    return reader
    
def my_test_reader():
    def reader():
        for temp in test_data:
            yield temp[:-1], temp[-1]    
    return reader

定义 batch size 大小

# 定义batch
train_reader = paddle.batch(
    my_train_reader(),
    batch_size=30000)

搭建LSTM模型

DIM = 1
hid_dim2 = 1
x = fluid.layers.data(name='x', shape=[DIM], dtype='float32', lod_level=1)  
label = fluid.layers.data(name='y', shape=[1], dtype='float32')
fc0 = fluid.layers.fc(input=x, size=DIM * 4)
fc1 = fluid.layers.fc(input=fc0, size=DIM * 4)
lstm_h, c = fluid.layers.dynamic_lstm(
    input=fc1, size=DIM * 4, is_reverse=False)

# 最大池化
lstm_max = fluid.layers.sequence_pool(input=lstm_h, pool_type='max')
# 激活函数
lstm_max_tanh = fluid.layers.tanh(lstm_max)
# 全连接层
prediction = fluid.layers.fc(input=lstm_max_tanh, size=hid_dim2, act='tanh')
# 代价函数
cost = fluid.layers.square_error_cost(input=prediction, label=label)
avg_cost = fluid.layers.mean(x=cost)
# acc = fluid.layers.accuracy(input=prediction, label=label)

开始训练,PASS_NUM 为轮数,这里设置为两百

from paddle.utils.plot import Ploter
train_title = "Train cost"
test_title = "Test cost"
plot_cost = Ploter(train_title, test_title)

# 定义优化器
adam_optimizer = fluid.optimizer.Adam(learning_rate=0.002)
adam_optimizer.minimize(avg_cost)

# 使用CPU
#place = fluid.CPUPlace()
# 使用CUDA
place = fluid.CUDAPlace(0)
exe = fluid.Executor(place)
exe.run( fluid.default_startup_program() )
feeder = fluid.DataFeeder(place=place, feed_list=[x, label])

def train_loop():
    step = 0 # 画图
    PASS_NUM = 200
    for pass_id in range(PASS_NUM):
        total_loss_pass = 0#初始化每一个epoch的损失值初始值为0
        for data in train_reader(): #data表示batch大小的数据样本          
            avg_loss_value, = exe.run(
                fluid.default_main_program(), 
                feed= feeder.feed(data), 
                fetch_list=[avg_cost])
            total_loss_pass += avg_loss_value
        # 画图
        plot_cost.append(train_title, step, avg_loss_value)
        step += 1
        plot_cost.plot()
    fluid.io.save_inference_model(SAVE_DIRNAME, ['x'], [prediction], exe)
train_loop()

训练误差如图

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第7张图片

模型训练效果验证

def convert2LODTensor(temp_arr, len_list):
    temp_arr = np.array(temp_arr) 
    temp_arr = temp_arr.flatten().reshape((-1, 1))
    print(temp_arr.shape)
    return fluid.create_lod_tensor(
        data=temp_arr,
        recursive_seq_lens =[len_list],
        place=fluid.CPUPlace()
        )
    

def get_tensor_label(mini_batch):  
    tensor = None
    labels = []
    
    temp_arr = []
    len_list = []
    for _ in mini_batch:   
        labels.append(_[1]) 
        temp_arr.append(_[0]) 
        len_list.append(len(_[0])) 
    tensor = convert2LODTensor(temp_arr, len_list)    
    return tensor, labels

my_tensor = None
labels = None

# 定义batch
test_reader = paddle.batch(
    my_test_reader(),
    batch_size=400000)


for mini_batch in test_reader():
    my_tensor,labels = get_tensor_label(mini_batch)
 
# 选择CPU或者CUDA进行验证   
#place = fluid.CPUPlace() 
place = fluid.CUDAPlace(0)

exe = fluid.Executor(place)
inference_scope = fluid.core.Scope()
with fluid.scope_guard(inference_scope):
    [inference_program, feed_target_names, fetch_targets] = (
        fluid.io.load_inference_model(SAVE_DIRNAME, exe))
    results = exe.run(inference_program,
                      feed= {
     'x': my_tensor}, 
                      fetch_list=fetch_targets)

最后绘制图像,由于标签之前被归一化了,这里我们需要对其进行解算

label = label*3 # 标签解算
result_print = results[0].flatten()
result_print = 3*result_print # 预测结果解算
plt.figure()
plt.plot(list(range(len(labels))), labels, color='b')  #蓝线为真实值
plt.plot(list(range(len(result_print))), result_print, color='r')  #红线为预测值
plt.show()

验证结果如下,其中蓝色为真实评级,红色为模型的预测评级

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第8张图片
误差不是很大,效果感觉还可以

未标注公司的评估

由于数据量实在是太大了,导致图片有些难以辨认

2020全国大学生数学建模C题初尝试——基于 PaddlePaddle LSTM 的中小微企业信贷决策模型_第9张图片

写在最后

本人以后会发布一些关于机器学习模型算法,自动控制算法的其他文章,也会聊一聊自己做的一些小项目,希望读者朋友们能够喜欢。

你可能感兴趣的:(整活小项目)