企业发票异常分析
1、数据组成
(1)增值税发票数据,文件名zzsfp
(2)发票对应货物明细数据,文件名zzsfp_hwmx
(3)企业信息,文件名nsrxx
2、数据字段说明
(1)zzsfp表字典
字段名称 |
字段含义 |
数据类型 |
备注 |
fp_nid |
发票id |
String |
发票唯一标识 |
xf_id |
销方识别号 |
String |
企业唯一身份标识 |
gf_id |
购方识别号 |
String |
企业唯一身份标识 |
je |
金额 |
Double |
|
se |
税额 |
Double |
|
jshj |
价税合计 |
Double |
|
kpyf |
开票月份 |
String |
|
kprq |
开票日期 |
String |
|
zfbz |
作废标志 |
String |
‘Y’代表作废 |
(2)zzsfp_hwmx表
字段名称 |
字段含义 |
数据类型 |
备注 |
fp_nid |
发票id |
String |
发票唯一标识 |
date_key |
开票月份 |
String |
|
hwmc |
货物名称 |
String |
|
ggxh |
规格型号 |
String |
|
dw |
单位 |
String |
|
sl |
数量 |
Double |
|
dj |
单价 |
Double |
|
je |
金额 |
Double |
|
se |
税额 |
Double |
|
spbm |
商品编码 |
String |
|
(3)nsrxx表
字段名称 |
字段含义 |
数据类型 |
备注 |
hydm |
行业代码 |
String |
|
nsr_id |
纳税人id |
String |
企业唯一身份标识 |
djzclx_dm |
登记注册类型代码 |
String |
网上可查阅相关代码含义 |
kydjrq |
开业登记日期 |
String |
|
xgrq |
修改日期 |
String |
给企业打标签的时间 |
label |
标签 |
String |
‘0’代表正常企业 ‘1’代表问题企业 |
3、关联数据的必要说明
(1)zzsfp表可通过fp_nid进行关联
(2)zzsfp表可通过xf_id或者gf_id与nsrxx中的nsr_id进行关联,分离出销项发票表和进项发票表
数据分析:
创建xj使用决策树。
首先创建了xf_data和gf_data表统计销方票数和进方票数
create table xf_data
(xf_id String, xf_count String)
ROW format delimited fields terminated by ',' STORED AS TEXTFILE;
create table gf_data
(gf_id String, gf_count String )
ROW format delimited fields terminated by ',' STORED AS TEXTFILE;
统计zzsfp中每个销方标识号和进方标识号各自的票数。
Insert into xf_data(xf_id,xf_count)
Select xf_id , count(xf_id) from zzsfp group by xf_id;
Insert into gf_data(gf_id,gf_count)
Select gf_id , count(gf_id) from zzsfp group by gf_id;
导出到mysql
创建xf_gf_cha表,统计销出和进入的差值:
Create table xf_gf_cha(nsr_id string,cha string)ROW format delimited fields terminated by ',' STORED AS TEXTFILE;
插入数据:
INSERT INTO xf_gf_cha (nsr_id, cha) SELECT nsr_id,ABS(xf_count - gf_count) FROM xj;
只进不出:11041
只出不进个数:4656
所以试着以差值作为标准:
暂定差值为600
第二个标准使用作废票数
创建 zfbz_data表
create table zfbz_data
(xf_id String , gf_id String , zfcs String)
ROW format delimited fields terminated by ',' STORED AS TEXTFILE
插入数据:
Insert into table zfbz_data(xf_id,gf_id,zfcs) (select xf_id, gf_id ,count(zfbz) from zzsfp where zfbz = 'Y' group by xf_id,gf_id);
导出到mysql:
使用报废票数作为标准,
报废数在24左右时接近318
总结上述种种标准决定合并这几个表使用决策树自动创建标准,并进行预测
连接xf_data,gf_data,zfbz_data表
创建xj表:
insert into xj(nsr_id,xf_count,gf_count,label) select hydm,xf_count,gf_count,label from nsrxx left join xf_data on nsrxx.hydm=xf_data.xf_id left join gf_data on nsrxx.hydm=gf_data.gf_id;
update xj set xf_count='0' where xf_count is null;
update xj set gf_count='0' where gf_count is null;
更新其中为空的值为0;
连接xj合成新的xj表去一部分数据作为决策树的训练集。
insert into xj(nsr_id,xf_count,gf_count,label,zfbz)select nsr_id,xf_count,gf_count,label,zfbz from xj left join zfbz_data on xj.nsr_id=zfbz_data.xf_id;
3.使用决策树
导出了xj.csv作为训练集和测试集。
使用每个公司的出票数、进票数、及报废票数作为特征值。通过决策树获取创建标准,目标值使用label,合格为0,异常为1。
import graphviz
import numpy as np
import pandas as pd
from sklearn.datasets import load_iris
from sklearn import datasets
from sklearn import naive_bayes
from sklearn import linear_model
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_auc_score;
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import LabelEncoder
data = pd.read_csv("xj.csv")
x=data[["nsr_id","xf_count","gf_count","zfbz"]]
y=data[["label"]]
data=np.array(data)
x_train, x_test, y_train, y_test = train_test_split(x,y, random_state=22)
es = DecisionTreeClassifier(criterion="entropy",max_depth=8)
es.fit(x_train, y_train)
y_predict = es.predict(x_test)
score = es.score(x_test, y_test)
print(y_predict)
temp = pd.DataFrame(y_predict)
temp.to_csv('E:\\xj\\result.csv')
print(score)
# 将得到的模型保存
with open("hwmx.dot", 'w') as f:
f = tree.export_graphviz(es, out_file=f,feature_names=['nsr_id','xf_count','gf_count',"zfbz"]);
# 将得到的模型生成pdf
dot_data = tree.export_graphviz(es, out_file=None,feature_names=['nsr_id','xf_count','gf_count',"zfbz"])
graph = graphviz.Source(dot_data)
graph.render("hwmx")
模型的准确率:
导出创建的模型,决策树可视化
对测试集测试:
因为没有设置公司的id,所以都是顺序输出每个公司和预测结果。
测试数据有8000多条,其中测试异常的含有一个,训练集中的含有317个,总计以这种标准出来318家异常公司。