企业非法集资风险预测 竞赛 - DataFountainwww.datafountain.cn代码地址github.com
欢迎大家开源关注我的github仓库以及该知乎专栏,该仓库用于记录和定期提供各大数据科学竞赛的赛事消息和原创baseline,思路分享以及博主的一些竞赛心得和学习资料等. 主要涵盖:kaggle, 阿里天池,华为云大赛校园赛,百度aistudio,和鲸社区,datafountain等。目前已经总结了多个比赛的获奖方案和baseline
赛题描述:
背景:非法集资严重干扰了正常的经济、金融秩序,使参与者遭受经济损失,甚至生活陷入困境,极易引发社会不稳定和大量社会治安问题,甚至引发局部地区的社会动荡。如何根据大量的企业信息建立预测模型并判断企业是否存在非法集资风险,对监管部门、企业合作伙伴、投资者都具有一定的价值。任务:利用机器学习、深度学习等方法训练一个预测模型,该模型可学习企业的相关信息,以预测企业是否存在非法集资风险。赛题的难点在于数据集包括大量的企业相关信息,如何从中提取有效的特征并进行风险预测成为本赛题的关键问题
解决思路:
目前只提交了9次,后续有时间会继续做,所以还会继续更新效果更好的代码!目前的特征基本没有怎么做,所以改进空间还有很大。目测好好做数据和特征筛选会取得很好的成绩,但是最稳的还是有一个稳定的线下验证,如果有一个和线上同升/降的验证集,比赛基本拿下一半了
- 缺失值填补(一半缺失的列删除,对于类别特征:NaN当作单独一个类别进行数值编码)
- object类型数值编码
- 交叉特征和分桶特征,对于几个重要的特征(企业类别,细分类这种做交叉特征是很有意义的)
- merge每一个表格的数据(基本信息表,纳税表,年度报表,变动表,舆论表,其余)
- 选出category特征给catboost单独指定
- 暴力搜索参数
- 随机森林单模五折交叉验证:线下:832,线上:829
- catboost单模五折交叉验证:线下:841,线上:828
- 随机森林+catboost融合(取前20重要的特征:线上834)
- 特征筛选十分重要,避免过度拟合到线下的验证数据
- 缺失值填补(一半缺失的列删除,对于类别特征:NaN当作单独一个类别进行数值编码)
- object类型数值编码
- 交叉特征和分桶特征,对于几个重要的特征(企业类别,细分类这种做交叉特征是很有意义的)
- merge每一个表格的数据(基本信息表,纳税表,年度报表,变动表,舆论表,其余)
- 选出category特征给catboost单独指定
- 暴力搜索参数
- 随机森林单模五折交叉验证:线下:832,线上:829
- catboost单模五折交叉验证:线下:841,线上:828
- 随机森林+catboost融合(取前20重要的特征:线上834)
- 特征筛选十分重要,避免过度拟合到线下的验证数据
数据分析:
本赛题数据缺失值较多,除了企业的基本信息较为齐全外,其余各表信息均有缺失。很多企业id空缺 训练集总共14865条样本,其中正例:13884,负例981.约为14:1.
下面是对数据的初步分析:
base_info=pd.read_csv('train/base_info.csv')#企业的基本信息
annual_report_info=pd.read_csv('train/annual_report_info.csv')#企业的年报基本信息
tax_info=pd.read_csv('train/tax_info.csv')#企业的纳税信息
change_info=pd.read_csv('train/tax_info.csv')#变更信息
news_info=pd.read_csv('train/news_info.csv')#舆情信息
other_info=pd.read_csv('train/other_info.csv')#其它信息
entprise_info=pd.read_csv('train/entprise_info.csv')#企业标注信息{0: 13884, 1: 981}
entprise_evaluate=pd.read_csv('entprise_evaluate.csv')#未标注信息print('base_info shape:',base_info.shape,'id unique:',len(base_info['id'].unique()))
print('annual_report_info shape:',annual_report_info.shape,'id unique:',len(annual_report_info['id'].unique()))
print('tax_info shape:',tax_info.shape,'id unique:',len(tax_info['id'].unique()))
print('change_info shape:',change_info.shape,'id unique:',len(change_info['id'].unique()))
print('news_info shape:',news_info.shape,'id unique:',len(news_info['id'].unique()))
print('other_info shape:',other_info.shape,'id unique:',len(other_info['id'].unique()))
print('entprise_info shape:',entprise_info.shape,'id unique:',len(entprise_info['id'].unique()))
print('entprise_evaluate shape:',entprise_evaluate.shape,'id unique:',len(entprise_evaluate['id'].unique()))
处理base_info数据:主要是对数据object列进行数值编码
# #处理base_info数据
base_info_clean=base_info.drop(['opscope','opfrom','opto'],axis=1)#............................对object类型进行编码...............................
base_info_clean['industryphy']=base_info_clean['industryphy'].fillna("无")
base_info_clean['dom']=base_info_clean['dom'].fillna("无")
base_info_clean['opform']=base_info_clean['opform'].fillna("无")
base_info_clean['oploc']=base_info_clean['oploc'].fillna("无")
#
dic={}
cate=base_info_clean.industryphy.unique()
for i in range(len(cate)):dic[cate[i]]=ibuf = pd.DataFrame()
buf_group = base_info_clean.groupby('industryphy',sort=False)
for name,group in buf_group:group['industryphy'] = dic[name]buf = pd.concat([buf,group],ignore_index=True)
print('finished 1....')
#
dic={}
cate=buf.dom.unique()
for i in range(len(cate)):dic[cate[i]]=ibuf_group = buf.groupby('dom',sort=False)
buf = pd.DataFrame()
for name,group in buf_group:group['dom'] = dic[name]buf = pd.concat([buf,group],ignore_index=True)
print('finished 2....')
#
dic={}
cate=buf.opform.unique()
for i in range(len(cate)):dic[cate[i]]=ibuf_group = buf.groupby('opform',sort=False)
buf = pd.DataFrame()
for name,group in buf_group:group['opform'] = dic[name]buf = pd.concat([buf,group],ignore_index=True)
print('finished 3....')
#
dic={}
cate=buf.oploc.unique()
for i in range(len(cate)):dic[cate[i]]=ibuf_group = buf.groupby('oploc',sort=False)
buf = pd.DataFrame()
for name,group in buf_group:group['oploc'] = dic[name]buf = pd.concat([buf,group],ignore_index=True)
print('finished 4....')
#
buf=buf.fillna(-1)
#
buf_group = buf.groupby('id',sort=False).agg('mean')
base_info_clean=pd.DataFrame(buf_group).reset_index()
#
print('编码完毕.................')
对一些重要的特征进行交叉组合和分桶构造新特征
#........................分桶.................................
def bucket(name,bucket_len):gap_list=[base_info_clean[name].quantile(i/bucket_len) for i in range(bucket_len+1)]len_data=len(base_info_clean[name])new_col=[]for i in base_info_clean[name].values:for j in range(len(gap_list)):if gap_list[j]>=i:encode=jbreaknew_col.append(encode)return new_col
#注册资本_实缴资本
base_info_clean['regcap_reccap']=base_info_clean['regcap']-base_info_clean['reccap']
#注册资本分桶
base_info_clean['regcap']=base_info_clean['regcap'].fillna(base_info_clean['regcap'].median())
base_info_clean['bucket_regcap']=bucket('regcap',5)
#实缴资本分桶
base_info_clean['reccap']=base_info_clean['reccap'].fillna(base_info_clean['reccap'].median())
base_info_clean['bucket_reccap']=bucket('reccap',5)
#注册资本_实缴资本分桶
base_info_clean['regcap_reccap']=base_info_clean['regcap_reccap'].fillna(base_info_clean['regcap_reccap'].median())
base_info_clean['bucket_regcap_reccap']=bucket('regcap_reccap',5)
print('分桶完毕.................')
#.............................交叉.........................
#作两个特征的交叉
def cross_two(name_1,name_2):new_col=[]encode=0dic={}val_1=base_info[name_1]val_2=base_info[name_2]for i in tqdm(range(len(val_1))):tmp=str(val_1[i])+'_'+str(val_2[i])if tmp in dic:new_col.append(dic[tmp])else:dic[tmp]=encodenew_col.append(encode)encode+=1return new_col
#作企业类型-小类的交叉特征
base_info_clean['enttypegb']=base_info_clean['enttypegb'].fillna("无")
base_info_clean['enttypeitem']=base_info_clean['enttypeitem'].fillna("无")
new_col=cross_two('enttypegb','enttypeitem')#作企业类型-小类的交叉特征
base_info_clean['enttypegb_enttypeitem']=new_col
#
#行业类别-细类的交叉特征
base_info_clean['industryphy']=base_info_clean['industryphy'].fillna("无")
base_info_clean['industryco']=base_info_clean['industryco'].fillna("无")
new_col=cross_two('industryphy','industryco')#作企业类型-小类的交叉特征
base_info_clean['industryphy_industryco']=new_col
print('交叉特征完毕.................')
处理其它几个表格的方式相同,完整代码见文章开头的github地址!
目前没有几个手工特征,之前试过一个特征不做,就用原始数据也能到82.5+的成绩。所以模型的改进空间还有很大,预祝大家取得好成绩!