前言
本来因为ACM竞赛培训的原因没有参加数学建模的培训和系列赛事,开学被同学拉过来凑数,就这样阴差阳错的参加了一次数学建模国赛。由于没有系统的学习数学建模,还是第一次接触数学建模正式赛事,所以论文写的比较水。主要用到的方法都是烂大街的没有新意的方法,都是我在平时做数据练习时的一些偏机器学习的模型。前期想着队长能有什么模型想出来,结果队长啥也没想出来只好自己上,导致正式开始动笔建模时已经比较晚。其实论文还有很多可以改进的地方,比如没有查阅足够的文献资料,综合前人的结果,其实前人已经做出一些信用风险评估模型,其次集成学习比较仓促,没有分配分类器权重系数,时间够的话还应该可以做一下信用迁移矩阵,将题目中的时间用到。但最终还是写出了一个可行但并非最优解,也算完成论文。
最近好多童鞋在问我要论文,这里统一回复一下,当时做的实在太烂了,没有留下相关资源
2020年国赛明令提出不能使用topsis等算法,我使用了,其实做的很烂
题目

摘要

说明
详细论文、程序源码和数据
请见代码仓库,过一阵子放
数据预处理
据说这个部分让很多队伍头痛,其实也不是很难,不用很多时间。主要是根据发票信息对每个公司进行统计,我们算出了一些指标,以便以后使用,由于时间原因,没有处理发票中的时间信息。如果时间足够的话,其实还可以算一下信用迁移矩阵。详细程序见下。
综合评价系统
我们用的是Topsis+熵权法,其实综合评价系统有很多种,应该针对不同的数据区别使用,但笔者没系统学过建模,也是现学现用。读者可以尝试使用其他评价系统,或者尝试一些现有信用风险模型,谷歌学术搜一搜就可。
分类系统
使用kmeans分类,我也只知道这个,太菜了╯﹏╰。论文里分了九类,是根据聚类效果评价算法得出来的最佳聚类簇个数,其实3个也就够了的。
程序
1.问题1
数据读取
#导入相关库
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from scipy.stats import zscore
from sklearn.decomposition import PCA
from sklearn.cluster import KMeans
from sklearn.metrics import silhouette_score
#读取数据
data = pd.read_excel('a0.xlsx')
data2 =pd.read_excel('a0.xlsx',sheet_name=1)
data3 =pd.read_excel('a0.xlsx',sheet_name=2)
#将企业代号前的E去掉,使其成为数值型变量,便于排序
data['企业代号']=data['企业代号'].apply(lambda x:int(x[1:]))
data2['企业代号']=data2['企业代号'].apply(lambda x:int(x[1:]))
data3['企业代号']=data3['企业代号'].apply(lambda x:int(x[1:]))
数据概览
data
| 企业代号 | 企业名称 | 信誉评级 | 是否违约 | |
|---|---|---|---|---|
| 0 | 1 | ***电器销售有限公司 | A | 否 |
| 1 | 2 | ***技术有限责任公司 | A | 否 |
| 2 | 3 | ***电子(中国)有限公司***分公司 | C | 否 |
| 3 | 4 | ***发展有限责任公司 | C | 否 |
| 4 | 5 | ***供应链管理有限公司 | B | 否 |
| ... | ... | ... | ... | ... |
| 118 | 119 | ***药房 | D | 是 |
| 119 | 120 | ***陈列广告有限公司 | D | 是 |
| 120 | 121 | ***药业连锁有限公司***药店 | D | 是 |
| 121 | 122 | ***商贸有限责任公司 | D | 是 |
| 122 | 123 | ***创科技有限责任公司 | D | 是 |
123 rows × 4 columns
data2
| 企业代号 | 发票号码 | 开票日期 | 销方单位代号 | 金额 | 税额 | 价税合计 | 发票状态 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 3390939 | 2017-07-18 | A00297 | -943.40 | -56.60 | -1000.00 | 有效发票 |
| 1 | 1 | 3390940 | 2017-07-18 | A00297 | -4780.24 | -286.81 | -5067.05 | 有效发票 |
| 2 | 1 | 3390941 | 2017-07-18 | A00297 | 943.40 | 56.60 | 1000.00 | 有效发票 |
| 3 | 1 | 3390942 | 2017-07-18 | A00297 | 4780.24 | 286.81 | 5067.05 | 有效发票 |
| 4 | 1 | 9902669 | 2017-08-07 | A05061 | 326.21 | 9.79 | 336.00 | 有效发票 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 210942 | 122 | 54706234 | 2019-04-17 | A08967 | 223.30 | 6.70 | 230.00 | 有效发票 |
| 210943 | 122 | 55721344 | 2020-01-10 | A09184 | 264.15 | 15.85 | 280.00 | 有效发票 |
| 210944 | 123 | 38493295 | 2017-12-15 | A03624 | 264.15 | 15.85 | 280.00 | 有效发票 |
| 210945 | 123 | 95472001 | 2018-12-29 | A03626 | 264.15 | 15.85 | 280.00 | 有效发票 |
| 210946 | 123 | 54469883 | 2019-12-18 | A03626 | 264.15 | 15.85 | 280.00 | 有效发票 |
210947 rows × 8 columns
data3
| 企业代号 | 发票号码 | 开票日期 | 购方单位代号 | 金额 | 税额 | 价税合计 | 发票状态 | |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | 11459356 | 2017-08-04 | B03711 | 9401.71 | 1598.29 | 11000.0 | 有效发票 |
| 1 | 1 | 5076239 | 2017-08-09 | B00844 | 8170.94 | 1389.06 | 9560.0 | 有效发票 |
| 2 | 1 | 5076240 | 2017-08-09 | B00844 | 8170.94 | 1389.06 | 9560.0 | 有效发票 |
| 3 | 1 | 5076241 | 2017-08-09 | B00844 | 4085.47 | 694.53 | 4780.0 | 有效发票 |
| 4 | 1 | 5076242 | 2017-08-09 | B00844 | 4085.47 | 694.53 | 4780.0 | 有效发票 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 162479 | 123 | 8887701 | 2019-12-17 | B10944 | 4827.67 | 144.83 | 4972.5 | 有效发票 |
| 162480 | 123 | 8887702 | 2019-12-17 | B10944 | 7412.62 | 222.38 | 7635.0 | 有效发票 |
| 162481 | 123 | 34173085 | 2019-12-17 | B13093 | 1917.47 | 57.53 | 1975.0 | 有效发票 |
| 162482 | 123 | 8887703 | 2019-12-25 | B13093 | 7252.42 | 217.58 | 7470.0 | 有效发票 |
| 162483 | 123 | 8887704 | 2019-12-25 | B13093 | 6660.19 | 199.81 | 6860.0 | 有效发票 |
162484 rows × 8 columns
数据预处理
#计算有效发票、负数发票和作废发票数量
def cnt(a,b,df):
tot=0
for i in range(a,b):
if df.iloc[i,6]<0 and df.iloc[i,7] == '有效发票':
tot+=1
if(len(df.iloc[a:b,:]['发票状态'].value_counts())==1):
return df.iloc[a:b,:]['发票状态'].value_counts()['有效发票'],0,tot
return df.iloc[a:b,:]['发票状态'].value_counts()['有效发票'],df.iloc[a:b,:]['发票状态'].value_counts()['作废发票'],tot
#计算有效金额,有效税额,作废额
def cnt2(a,b,df):
zf=0
yxj=0
yxs=0
for i in range(a,b):
if df.iloc[i,7] == '作废发票':
zf+=df.iloc[i,6]
else:
yxj+=df.iloc[i,4]
yxs+=df.iloc[i,5]
return yxj,yxs,zf
#对进项发票进行统计
checkin=pd.DataFrame(data2['企业代号'].value_counts())
checkin.columns=['进项发票数量']
checkin.sort_index(inplace=True)
last=0
temp1=[]
temp2=[]
temp3=[]
temp4=[]
temp5=[]
temp6=[]
temp7=[]
for i in range(len(checkin)):
a,b,c=cnt(last,last+int(checkin.iloc[i,0]),data2)
d,e,f=cnt2(last,last+int(checkin.iloc[i,0]),data2)
last=last+int(checkin.iloc[i,0])
temp1.append(a)
temp2.append(b)
temp3.append(c)
temp4.append(d)
temp5.append(e)
temp6.append(f)
temp7.append(d+e)
checkin['进项有效发票']=temp1
checkin['进项作废发票']=temp2
checkin['进项负数发票']=temp3
checkin['进项有效金额']=temp4
checkin['进项有效税额']=temp5
checkin['进项无效额']=temp6
checkin['进项有效价税']=temp7
#对销项发票进行统计
checkout=pd.DataFrame(data3['企业代号'].value_counts())
checkout.columns=['销项发票数量']
checkout.sort_index(inplace=True)
last=0
temp1=[]
temp2=[]
temp3=[]
temp4=[]
temp5=[]
temp6=[]
temp7=[]
for i in range(len(checkout)):
a,b,c=cnt(last,last+int(checkout.iloc[i,0]),data3)
d,e,f=cnt2(last,last+int(checkout.iloc[i,0]),data3)
last=last+int(checkout.iloc[i,0])
temp1.append(a)
temp2.append(b)
temp3.append(c)
temp4.append(d)
temp5.append(e)
temp6.append(f)
temp7.append(d+e)
checkout['销项有效发票']=temp1
checkout['销项作废发票']=temp2
checkout['销项负数发票']=temp3
checkout['销项有效金额']=temp4
checkout['销项有效税额']=temp5
checkout['销项无效额']=temp6
checkout['销项有效价税']=temp7
#保存中间结果
checkin.to_excel('value_counts_in.xls')
checkout.to_excel('value_counts_out.xls')
#合并进项和销项发票收据数据,为进行下一步计算做准备
checks=pd.concat([checkin,checkout],axis=1)
#对发票进行汇总统计
temp1=data['信誉评级']
temp2=data['是否违约']
temp1.index=range(1,124)
temp2.index=range(1,124)
checks=pd.concat([temp1,temp2,checks],axis=1)
checks['收入']=checks['销项有效价税']-checks['进项有效价税']
temp1=[]
temp2=[]
temp3=[]
temp4=[]
temp5=[]
last1=last2=0
a=b=0
for i in range(len(checks)):
next1=last1+checks.iloc[i,2]
next2=last2+checks.iloc[i,10]
temp3=data2.iloc[last1:next1,3].value_counts()
temp4=data3.iloc[last2:next2,3].value_counts()
if(len(temp3)<=3):
temp1.append(1)
temp2.append(1)
temp5.append(1)
else:
a=sum(temp3[:3])/sum(temp3)
b=sum(temp4[:3])/sum(temp4)
temp1.append(a)
temp2.append(b)
temp5.append(np.sqrt((a*a+b*b)/2))
last1=next1
last2=next2
checks['进稳定度指标']=temp1
checks['销稳定度指标']=temp2
checks['供求稳定度指标']=temp5
temp1=[]
temp2=[]
for i in range(len(checks)):
sum1=sum2=sum3=0
sum1=checks.iloc[i,2]+checks.iloc[i,10]
sum2=checks.iloc[i,4]+checks.iloc[i,12]
sum3=checks.iloc[i,5]+checks.iloc[i,13]
temp1.append(sum2/sum1)
temp2.append(sum3/sum1)
checks['作废发票率']=temp1
checks['负数发票率']=temp2
#保存中间结果
checks.to_excel('checks_1.xls')
第一问子问题一求解
pa0=checks[checks['信誉评级']!='D']
pa0
| 信誉评级 | 是否违约 | 进项发票数量 | 进项有效发票 | 进项作废发票 | 进项负数发票 | 进项有效金额 | 进项有效税额 | 进项无效额 | 进项有效价税 | ... | 销项有效金额 | 销项有效税额 | 销项无效额 | 销项有效价税 | 收入 | 进稳定度指标 | 销稳定度指标 | 供求稳定度指标 | 作废发票率 | 负数发票率 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 1 | A | 否 | 3441 | 3249 | 192 | 71 | 5.744706e+09 | 8.932358e+08 | 2.547518e+08 | 6.637942e+09 | ... | 4.065843e+09 | 6.327901e+08 | 1.001785e+08 | 4.698633e+09 | -1.939309e+09 | 0.515838 | 0.236252 | 0.401188 | 0.036014 | 0.025885 |
| 2 | A | 否 | 32156 | 31435 | 721 | 156 | 1.557623e+08 | 6.725653e+06 | 9.248509e+06 | 1.624880e+08 | ... | 5.908417e+08 | 3.545392e+07 | 6.841255e+07 | 6.262956e+08 | 4.638077e+08 | 0.268597 | 0.084520 | 0.199108 | 0.039297 | 0.011457 |
| 3 | C | 否 | 4561 | 4367 | 194 | 26 | 5.202698e+07 | 2.152374e+06 | 3.341486e+06 | 5.417935e+07 | ... | 5.701780e+08 | 9.089228e+07 | 2.166951e+07 | 6.610703e+08 | 6.068909e+08 | 0.168823 | 0.568936 | 0.419636 | 0.020221 | 0.154781 |
| 4 | C | 否 | 558 | 521 | 37 | 4 | 2.198771e+08 | 3.470711e+07 | 1.258232e+08 | 2.545842e+08 | ... | 1.839970e+09 | 3.065709e+08 | 1.990901e+08 | 2.146541e+09 | 1.891956e+09 | 0.261649 | 0.710892 | 0.535643 | 0.081391 | 0.004661 |
| 5 | B | 否 | 2169 | 2084 | 85 | 16 | 1.977850e+08 | 2.954699e+07 | 4.718235e+06 | 2.273320e+08 | ... | 2.026323e+08 | 3.065841e+07 | 9.497473e+06 | 2.332907e+08 | 5.958721e+06 | 0.393269 | 0.591509 | 0.502267 | 0.043357 | 0.008052 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 98 | B | 否 | 51 | 50 | 1 | 1 | 1.993190e+05 | 9.963970e+03 | 2.060000e+02 | 2.092830e+05 | ... | 1.403242e+06 | 4.186923e+04 | 3.697712e+05 | 1.445111e+06 | 1.235828e+06 | 0.392157 | 0.732026 | 0.587218 | 0.102941 | 0.034314 |
| 104 | C | 否 | 1 | 1 | 0 | 0 | 2.641500e+02 | 1.585000e+01 | 0.000000e+00 | 2.800000e+02 | ... | 2.626505e+05 | 7.879490e+03 | 2.000000e+04 | 2.705300e+05 | 2.702500e+05 | 1.000000 | 1.000000 | 1.000000 | 0.090909 | 0.045455 |
| 105 | C | 否 | 6 | 6 | 0 | 0 | 7.436920e+03 | 1.043080e+03 | 0.000000e+00 | 8.480000e+03 | ... | 9.248194e+05 | 2.774452e+04 | 1.039500e+04 | 9.525639e+05 | 9.440839e+05 | 0.833333 | 0.196721 | 0.605452 | 0.007812 | 0.031250 |
| 106 | B | 否 | 36 | 35 | 1 | 0 | 5.033527e+04 | 2.125830e+03 | 9.000000e+03 | 5.246110e+04 | ... | 5.860489e+05 | 1.762900e+04 | 5.552000e+04 | 6.036779e+05 | 5.512168e+05 | 0.361111 | 0.156863 | 0.278395 | 0.084656 | 0.021164 |
| 110 | C | 否 | 3 | 3 | 0 | 0 | 9.633900e+02 | 7.661000e+01 | 0.000000e+00 | 1.040000e+03 | ... | 1.969199e+05 | 5.907650e+03 | 7.257769e+04 | 2.028275e+05 | 2.017875e+05 | 1.000000 | 1.000000 | 1.000000 | 0.244186 | 0.000000 |
99 rows × 24 columns
pa0.iloc[:,0].value_counts()
B 38
C 34
A 27
Name: 信誉评级, dtype: int64
#替换指标值、删除多余项
pa1=pa0
pa1=pa1.replace('是',0)
pa1=pa1.replace('否',1)
pa1=pa1.replace('A',100)
pa1=pa1.replace('B',80)
pa1=pa1.replace('C',52.45)
pa1.drop(pa1.columns[range(2,18)],axis=1,inplace=True)
pa1.drop(pa1.columns[range(3,5)],axis=1,inplace=True)
pa1
| 信誉评级 | 是否违约 | 收入 | 供求稳定度指标 | 作废发票率 | 负数发票率 | |
|---|---|---|---|---|---|---|
| 1 | 100.00 | 1 | -1.939309e+09 | 0.401188 | 0.036014 | 0.025885 |
| 2 | 100.00 | 1 | 4.638077e+08 | 0.199108 | 0.039297 | 0.011457 |
| 3 | 52.45 | 1 | 6.068909e+08 | 0.419636 | 0.020221 | 0.154781 |
| 4 | 52.45 | 1 | 1.891956e+09 | 0.535643 | 0.081391 | 0.004661 |
| 5 | 80.00 | 1 | 5.958721e+06 | 0.502267 | 0.043357 | 0.008052 |
| ... | ... | ... | ... | ... | ... | ... |
| 98 | 80.00 | 1 | 1.235828e+06 | 0.587218 | 0.102941 | 0.034314 |
| 104 | 52.45 | 1 | 2.702500e+05 | 1.000000 | 0.090909 | 0.045455 |
| 105 | 52.45 | 1 | 9.440839e+05 | 0.605452 | 0.007812 | 0.031250 |
| 106 | 80.00 | 1 | 5.512168e+05 | 0.278395 | 0.084656 | 0.021164 |
| 110 | 52.45 | 1 | 2.017875e+05 | 1.000000 | 0.244186 | 0.000000 |
99 rows × 6 columns
#成本型指标转换,数据归一化
pa1['作废发票率']=(max(pa1['作废发票率'])-pa1['作废发票率'])/(max(pa1['作废发票率'])-min(pa1['作废发票率']))
pa1['负数发票率']=(max

最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



