Selaa lähdekoodia

行业分类提取,产品预测返回调整

lsm 2 vuotta sitten
vanhempi
commit
86b2f7ff11

+ 5 - 2
BiddingKG/dl/interface/extract.py

@@ -206,7 +206,7 @@ def predict(doc_id,text,title="",page_time="",web_source_no='',original_docchann
 
     start_time = time.time() # 产品名称及废标原因提取  #依赖 docchannel结果
     fail = channel_dic['docchannel']['docchannel'] == "废标公告"
-    fail_reason = predictor.getPredictor("product").predict(list_sentences,list_entitys,list_articles, fail) #只返回失败原因,产品已加入到Entity类
+    fail_reason, product_list = predictor.getPredictor("product").predict(list_sentences,list_entitys,list_articles, fail) #只返回失败原因,产品已加入到Entity类 #2022/7/29补充返回产品,方便行业分类调用
     # predictor.getPredictor("product").predict(list_sentences, list_entitys)
     log("get product done of doc_id%s"%(doc_id))
     cost_time["product"] = round(time.time()-start_time,2)
@@ -216,10 +216,13 @@ def predict(doc_id,text,title="",page_time="",web_source_no='',original_docchann
     '''把产品要素提取结果在项目名称的添加到 采购需求,预算时间,采购时间 要素中'''
     predictor.getPredictor("product_attrs").add_product_attrs(channel_dic, product_attrs, list_sentences,list_entitys,codeName,prem,text,page_time)
 
+    '''行业分类提取,需要用标题、项目名称、产品、及prem 里面的角色'''
+    industry = predictor.getPredictor('industry').predict(title, project=codeName[0]['name'], product=','.join(product_list), prem=prem)
+
 
     # data_res = Preprocessing.union_result(Preprocessing.union_result(codeName, prem),list_punish_dic)[0]
     # data_res = Preprocessing.union_result(Preprocessing.union_result(Preprocessing.union_result(codeName, prem),list_punish_dic), list_channel_dic)[0]
-    data_res = dict(codeName[0], **prem[0], **channel_dic, **product_attrs[0], **product_attrs[1], **payment_way_dic, **fail_reason)
+    data_res = dict(codeName[0], **prem[0], **channel_dic, **product_attrs[0], **product_attrs[1], **payment_way_dic, **fail_reason, **industry)
     data_res["doctitle_refine"] = doctitle_refine
     data_res["nlp_enterprise"] = nlp_enterprise
     data_res["nlp_enterprise_attachment"] = nlp_enterprise_attachment

+ 2 - 2
BiddingKG/dl/interface/getAttributes.py

@@ -2900,7 +2900,7 @@ def getOtherAttributes(list_entity):
                 list_serviceTime.append(entity)
         elif entity.entity_type=="person" and entity.label ==4:
             dict_other["person_review"].append(entity.entity_text)
-        elif entity.entity_type=='product':
+        elif entity.entity_type=='product' and entity.entity_text not in dict_other["product"]: #顺序去重保留
             dict_other["product"].append(entity.entity_text)
         elif entity.entity_type=='money' and entity.notes=='总投资' and dict_other["total_tendereeMoney"]<float(entity.entity_text):
             dict_other["total_tendereeMoney"] = float(entity.entity_text)
@@ -2912,7 +2912,7 @@ def getOtherAttributes(list_entity):
         max_prob_serviceTime.sort(key=lambda x:(x.sentence_index,x.begin_index))
         dict_other["serviceTime"] = max_prob_serviceTime[0].entity_text
 
-    dict_other["product"] = list(set(dict_other["product"]))
+    # dict_other["product"] = list(set(dict_other["product"])) # 已在添加时 顺序去重保留
     return dict_other
 
 def getMoneyRange(RoleList):

+ 544 - 3
BiddingKG/dl/interface/predictor.py

@@ -25,6 +25,7 @@ from bs4 import BeautifulSoup
 import copy
 import calendar
 import datetime
+import fool
 
 from threading import RLock
 dict_predictor = {"codeName":{"predictor":None,"Lock":RLock()},
@@ -40,7 +41,8 @@ dict_predictor = {"codeName":{"predictor":None,"Lock":RLock()},
                 "product_attrs":{"predictor":None,"Lock":RLock()},
                   "channel": {"predictor": None, "Lock": RLock()},
                   "deposit_payment_way": {"predictor": None, "Lock": RLock()},
-                  "total_unit_money": {"predictor": None, "Lock": RLock()}
+                  "total_unit_money": {"predictor": None, "Lock": RLock()},
+                  "industry": {"predictor": None, "Lock": RLock()}
                   }
 
 
@@ -76,6 +78,8 @@ def getPredictor(_type):
                     dict_predictor[_type]["predictor"] = DepositPaymentWay()
                 if _type == 'total_unit_money':
                     dict_predictor[_type]["predictor"] = TotalUnitMoney()
+                if _type == 'industry':
+                    dict_predictor[_type]["predictor"] = IndustryPredictor()
             return dict_predictor[_type]["predictor"]
     raise NameError("no this type of predictor")
 
@@ -1818,6 +1822,7 @@ class ProductPredictor():
         with self.sess.as_default() as sess:
             with self.sess.graph.as_default():
                 result = []
+                product_list = []
                 if fail and list_articles!=[]:
                     text_list = [list_articles[0].content[:MAX_AREA]]
                     chars = [[self.word2index.get(it, self.word2index.get('<unk>')) for it in text] for text in text_list]
@@ -1835,6 +1840,7 @@ class ProductPredictor():
                         batch_paths = self.decode(scores, lengths, tran_)
                     for text, path, length in zip(text_list, batch_paths, lengths):
                         tags = ''.join([str(it) for it in path[:length]])
+                        # 提取产品
                         for it in re.finditer("12*3", tags):
                             start = it.start()
                             end = it.end()
@@ -1845,6 +1851,8 @@ class ProductPredictor():
                                              begin_index=0, end_index=0, wordOffset_begin=start,
                                              wordOffset_end=end)
                             list_entitys[0].append(_entity)
+                            product_list.append(text[start:end])
+                        # 提取失败原因
                         for it in re.finditer("45*6", tags):
                             start = it.start()
                             end = it.end()
@@ -1858,7 +1866,7 @@ class ProductPredictor():
                             reasons.append(it)
                         elif reasons == []:
                             reasons.append(it)
-                    return {'fail_reason':';'.join(reasons)}
+                    return {'fail_reason':';'.join(reasons)}, product_list
 
                 if list_entitys is None:
                     list_entitys = [[] for _ in range(len(list_sentences))]
@@ -1903,6 +1911,8 @@ class ProductPredictor():
                                                  wordOffset_end=end,in_attachment=sentence.in_attachment)
                                 list_entity.append(_entity)
                                 temp_list.append(sentence.sentence_text[start:end])
+                                product_list.append(sentence.sentence_text[start:end])
+
                         # item["product"] = list(set(temp_list))
                         # result.append(item)
                         if _begin_index+_LEN >= len(list_sentence):
@@ -1910,7 +1920,7 @@ class ProductPredictor():
                         _begin_index += _LEN
                     item["product"] = list(set(temp_list))
                     result.append(item) # 修正bug
-                return {'fail_reason': ""}
+                return {'fail_reason': ""},product_list
 
 
 # 产品数量单价品牌规格提取 #2021/11/10 添加表格中的项目、需求、预算、时间要素提取
@@ -3199,6 +3209,537 @@ class TotalUnitMoney:
                 # print("total_unit_money", _entity.entity_text,
                 #       _entity.is_total_money, _entity.is_unit_money)
 
+# 行业分类
+class IndustryPredictor():
+    def __init__(self,):
+        self.model_path = os.path.dirname(__file__)+ '/industry_model'
+        self.id2lb = {0: '专业施工', 1: '专用仪器仪表', 2: '专用设备修理', 3: '互联网信息服务', 4: '互联网安全服务', 5: '互联网平台', 6: '互联网接入及相关服务', 7: '人力资源服务',
+             8: '人造原油', 9: '仓储业', 10: '仪器仪表', 11: '仪器仪表修理', 12: '会计、审计及税务服务', 13: '会议、展览及相关服务', 14: '住宅、商业用房',
+             15: '体育场地设施管理', 16: '体育组织', 17: '体育设备', 18: '保险服务', 19: '信息处理和存储支持服务', 20: '信息技术咨询服务',
+             21: '信息系统集成和物联网技术服务', 22: '修缮工程', 23: '健康咨询', 24: '公路旅客运输', 25: '其他专业咨询与调查', 26: '其他专业技术服务',
+             27: '其他交通运输设备', 28: '其他公共设施管理', 29: '其他土木工程建筑', 30: '其他工程服务', 31: '其他建筑建材', 32: '其他运输业', 33: '农业和林业机械',
+             34: '农业服务', 35: '农产品', 36: '农副食品,动、植物油制品', 37: '出版业', 38: '办公消耗用品及类似物品', 39: '办公设备', 40: '化学原料及化学制品',
+             41: '化学纤维', 42: '化学药品和中药专用设备', 43: '医疗设备', 44: '医药品', 45: '卫星传输服务', 46: '卫生', 47: '印刷服务', 48: '图书和档案',
+             49: '图书档案设备', 50: '图书馆与档案馆', 51: '土地管理业', 52: '地质勘查', 53: '地震服务', 54: '场馆、站港用房', 55: '城市公共交通运输',
+             56: '塑料制品、半成品及辅料', 57: '天然石料', 58: '娱乐设备', 59: '婚姻服务', 60: '安全保护服务', 61: '安全生产设备', 62: '家具用具',
+             63: '家用电器修理', 64: '工业、生产用房', 65: '工业与专业设计及其他专业技术服务', 66: '工矿工程建筑', 67: '工程技术与设计服务', 68: '工程机械',
+             69: '工程监理服务', 70: '工程评价服务', 71: '工程造价服务', 72: '市场调查', 73: '广告业', 74: '广播', 75: '广播、电视、电影设备',
+             76: '广播电视传输服务', 77: '废弃资源综合利用业', 78: '建筑涂料', 79: '建筑物、构筑物附属结构', 80: '建筑物拆除和场地准备活动', 81: '建筑装饰和装修业',
+             82: '录音制作', 83: '影视节目制作', 84: '房地产中介服务', 85: '房地产开发经营', 86: '房地产租赁经营', 87: '房屋租赁', 88: '招标代理',
+             89: '探矿、采矿、选矿和造块设备', 90: '政法、检测专用设备', 91: '教育服务', 92: '教育设备', 93: '文物及非物质文化遗产保护', 94: '文物和陈列品',
+             95: '文艺创作与表演', 96: '文艺设备', 97: '新闻业', 98: '旅行社及相关服务', 99: '日杂用品', 100: '有色金属冶炼及压延产品', 101: '有色金属矿',
+             102: '木材、板材等', 103: '木材采集和加工设备', 104: '机械设备', 105: '机械设备经营租赁', 106: '林业产品', 107: '林业服务', 108: '架线和管道工程建筑',
+             109: '核工业专用设备', 110: '橡胶制品', 111: '殡葬服务', 112: '殡葬设备及用品', 113: '气象服务', 114: '水上交通运输设备', 115: '水上运输业',
+             116: '水利和水运工程建筑', 117: '水工机械', 118: '水文服务', 119: '水资源管理', 120: '污水处理及其再生利用', 121: '汽车、摩托车修理与维护',
+             122: '法律服务', 123: '洗染服务', 124: '测绘地理信息服务', 125: '海洋仪器设备', 126: '海洋工程建筑', 127: '海洋服务', 128: '消防设备',
+             129: '清洁服务', 130: '渔业产品', 131: '渔业服务', 132: '炼焦和金属冶炼轧制设备', 133: '烟草加工设备', 134: '热力生产和供应', 135: '焦炭及其副产品',
+             136: '煤炭采选产品', 137: '燃气生产和供应业', 138: '物业管理', 139: '特种用途动、植物', 140: '环保咨询', 141: '环境与生态监测检测服务',
+             142: '环境污染防治设备', 143: '环境治理业', 144: '玻璃及其制品', 145: '理发及美容服务', 146: '生态保护', 147: '电信',
+             148: '电力、城市燃气、蒸汽和热水、水', 149: '电力供应', 150: '电力工业专用设备', 151: '电力工程施工', 152: '电力生产', 153: '电子和通信测量仪器',
+             154: '电工、电子专用生产设备', 155: '电影放映', 156: '电气安装', 157: '电气设备', 158: '电气设备修理', 159: '畜牧业服务', 160: '监控设备',
+             161: '石油制品', 162: '石油和化学工业专用设备', 163: '石油和天然气开采产品', 164: '石油天然气开采专用设备', 165: '研究和试验发展', 166: '社会工作',
+             167: '社会经济咨询', 168: '科技推广和应用服务业', 169: '科研、医疗、教育用房', 170: '管道和设备安装', 171: '粮油作物和饲料加工设备', 172: '纸、纸制品及印刷品',
+             173: '纺织原料、毛皮、被服装具', 174: '纺织设备', 175: '绿化管理', 176: '缝纫、服饰、制革和毛皮加工设备', 177: '航空器及其配套设备', 178: '航空客货运输',
+             179: '航空航天工业专用设备', 180: '节能环保工程施工', 181: '装卸搬运', 182: '计算机和办公设备维修', 183: '计算机设备', 184: '计量标准器具及量具、衡器',
+             185: '货币处理专用设备', 186: '货币金融服务', 187: '质检技术服务', 188: '资本市场服务', 189: '车辆', 190: '边界勘界和联检专用设备', 191: '运行维护服务',
+             192: '通信设备', 193: '通用设备修理', 194: '道路货物运输', 195: '邮政专用设备', 196: '邮政业', 197: '采矿业和制造业服务',
+             198: '铁路、船舶、航空航天等运输设备修理', 199: '铁路、道路、隧道和桥梁工程建筑', 200: '铁路运输设备', 201: '防洪除涝设施管理', 202: '陶瓷制品',
+             203: '雷达、无线电和卫星导航设备', 204: '非金属矿', 205: '非金属矿物制品工业专用设备', 206: '非金属矿物材料', 207: '食品加工专用设备', 208: '食品及加工盐',
+             209: '餐饮业', 210: '饮料、酒精及精制茶', 211: '饮料加工设备', 212: '饲养动物及其产品', 213: '黑色金属冶炼及压延产品', 214: '黑色金属矿'}
+        self.industry_dic = {'专业施工': {'大类': '专业施工', '门类': '建筑业'},
+                             '专用仪器仪表': {'大类': '专用设备', '门类': '零售批发'},
+                             '专用设备修理': {'大类': '金属制品、机械和设备修理业', '门类': '金属制品、机械和设备修理业'},
+                             '互联网信息服务': {'大类': '互联网和相关服务', '门类': '信息传输、软件和信息技术服务业'},
+                             '互联网安全服务': {'大类': '互联网和相关服务', '门类': '信息传输、软件和信息技术服务业'},
+                             '互联网平台': {'大类': '互联网和相关服务', '门类': '信息传输、软件和信息技术服务业'},
+                             '互联网接入及相关服务': {'大类': '互联网和相关服务', '门类': '信息传输、软件和信息技术服务业'},
+                             '人力资源服务': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '人造原油': {'大类': '炼焦产品、炼油产品', '门类': '零售批发'},
+                             '仓储业': {'大类': '装卸搬运和运输代理业', '门类': '交通运输、仓储和邮政业'},
+                             '仪器仪表': {'大类': '通用设备', '门类': '零售批发'},
+                             '仪器仪表修理': {'大类': '金属制品、机械和设备修理业', '门类': '金属制品、机械和设备修理业'},
+                             '会计、审计及税务服务': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '会议、展览及相关服务': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '住宅、商业用房': {'大类': '房屋建筑业', '门类': '建筑业'},
+                             '体育场地设施管理': {'大类': '体育', '门类': '文化、体育和娱乐业'},
+                             '体育组织': {'大类': '体育', '门类': '文化、体育和娱乐业'},
+                             '体育设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '保险服务': {'大类': '保险业', '门类': '金融业'},
+                             '信息处理和存储支持服务': {'大类': '软件和信息技术服务业', '门类': '信息传输、软件和信息技术服务业'},
+                             '信息技术咨询服务': {'大类': '软件和信息技术服务业', '门类': '信息传输、软件和信息技术服务业'},
+                             '信息系统集成和物联网技术服务': {'大类': '软件和信息技术服务业', '门类': '信息传输、软件和信息技术服务业'},
+                             '修缮工程': {'大类': '修缮工程', '门类': '建筑业'},
+                             '健康咨询': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '公路旅客运输': {'大类': '道路运输业', '门类': '交通运输、仓储和邮政业'},
+                             '其他专业咨询与调查': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '其他专业技术服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '其他交通运输设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '其他公共设施管理': {'大类': '公共设施管理业', '门类': '水利、环境和公共设施管理业'},
+                             '其他土木工程建筑': {'大类': '土木工程建筑业', '门类': '建筑业'},
+                             '其他工程服务': {'大类': '工程服务', '门类': '科学研究和技术服务业'},
+                             '其他建筑建材': {'大类': '建筑建材', '门类': '零售批发'},
+                             '其他运输业': {'大类': '其他运输业', '门类': '交通运输、仓储和邮政业'},
+                             '农业和林业机械': {'大类': '专用设备', '门类': '零售批发'},
+                             '农业服务': {'大类': '农林牧副渔服务', '门类': '农林牧副渔服务'},
+                             '农产品': {'大类': '农林牧渔业产品', '门类': '零售批发'},
+                             '农副食品,动、植物油制品': {'大类': '食品、饮料和烟草原料', '门类': '零售批发'},
+                             '出版业': {'大类': '新闻和出版业', '门类': '文化、体育和娱乐业'},
+                             '办公消耗用品及类似物品': {'大类': '办公消耗用品及类似物品', '门类': '零售批发'},
+                             '办公设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '化学原料及化学制品': {'大类': '基础化学品及相关产品', '门类': '零售批发'},
+                             '化学纤维': {'大类': '基础化学品及相关产品', '门类': '零售批发'},
+                             '化学药品和中药专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '医疗设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '医药品': {'大类': '医药品', '门类': '零售批发'},
+                             '卫星传输服务': {'大类': '电信、广播电视和卫星传输服务', '门类': '信息传输、软件和信息技术服务业'},
+                             '卫生': {'大类': '卫生', '门类': '卫生和社会工作'},
+                             '印刷服务': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '图书和档案': {'大类': '图书和档案', '门类': '零售批发'},
+                             '图书档案设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '图书馆与档案馆': {'大类': '文化艺术业', '门类': '文化、体育和娱乐业'},
+                             '土地管理业': {'大类': '土地管理业', '门类': '水利、环境和公共设施管理业'},
+                             '地质勘查': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '地震服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '场馆、站港用房': {'大类': '房屋建筑业', '门类': '建筑业'},
+                             '城市公共交通运输': {'大类': '道路运输业', '门类': '交通运输、仓储和邮政业'},
+                             '塑料制品、半成品及辅料': {'大类': '橡胶、塑料、玻璃和陶瓷制品', '门类': '零售批发'},
+                             '天然石料': {'大类': '建筑建材', '门类': '零售批发'},
+                             '娱乐设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '婚姻服务': {'大类': '居民服务业', '门类': '居民服务、修理和其他服务业'},
+                             '安全保护服务': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '安全生产设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '家具用具': {'大类': '家具用具', '门类': '零售批发'},
+                             '家用电器修理': {'大类': '机动车、电子产品和日用产品修理业', '门类': '居民服务、修理和其他服务业'},
+                             '工业、生产用房': {'大类': '房屋建筑业', '门类': '建筑业'},
+                             '工业与专业设计及其他专业技术服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '工矿工程建筑': {'大类': '土木工程建筑业', '门类': '建筑业'},
+                             '工程技术与设计服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '工程机械': {'大类': '专用设备', '门类': '零售批发'},
+                             '工程监理服务': {'大类': '工程服务', '门类': '科学研究和技术服务业'},
+                             '工程评价服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '工程造价服务': {'大类': '工程服务', '门类': '科学研究和技术服务业'},
+                             '市场调查': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '广告业': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '广播': {'大类': '广播、电视、电影和影视录音制作业', '门类': '文化、体育和娱乐业'},
+                             '广播、电视、电影设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '广播电视传输服务': {'大类': '电信、广播电视和卫星传输服务', '门类': '信息传输、软件和信息技术服务业'},
+                             '废弃资源综合利用业': {'大类': '废弃资源综合利用业', '门类': '废弃资源综合利用业'},
+                             '建筑涂料': {'大类': '建筑建材', '门类': '零售批发'},
+                             '建筑物、构筑物附属结构': {'大类': '建筑建材', '门类': '零售批发'},
+                             '建筑物拆除和场地准备活动': {'大类': '建筑装饰和其他建筑业', '门类': '建筑业'},
+                             '建筑装饰和装修业': {'大类': '建筑装饰和其他建筑业', '门类': '建筑业'},
+                             '录音制作': {'大类': '广播、电视、电影和影视录音制作业', '门类': '文化、体育和娱乐业'},
+                             '影视节目制作': {'大类': '广播、电视、电影和影视录音制作业', '门类': '文化、体育和娱乐业'},
+                             '房地产中介服务': {'大类': '房地产业', '门类': '房地产业'},
+                             '房地产开发经营': {'大类': '房地产业', '门类': '房地产业'},
+                             '房地产租赁经营': {'大类': '房地产业', '门类': '房地产业'},
+                             '房屋租赁': {'大类': '租赁业', '门类': '租赁和商务服务业'},
+                             '招标代理': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '探矿、采矿、选矿和造块设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '政法、检测专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '教育服务': {'大类': '教育服务', '门类': '教育'},
+                             '教育设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '文体设备和用品出租': {'大类': '租赁业', '门类': '租赁和商务服务业'},
+                             '文物及非物质文化遗产保护': {'大类': '文化艺术业', '门类': '文化、体育和娱乐业'},
+                             '文物和陈列品': {'大类': '文物和陈列品', '门类': '零售批发'},
+                             '文艺创作与表演': {'大类': '文化艺术业', '门类': '文化、体育和娱乐业'},
+                             '文艺设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '新闻业': {'大类': '新闻和出版业', '门类': '文化、体育和娱乐业'},
+                             '旅行社及相关服务': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '日杂用品': {'大类': '日杂用品', '门类': '零售批发'},
+                             '有色金属冶炼及压延产品': {'大类': '建筑建材', '门类': '零售批发'},
+                             '有色金属矿': {'大类': '矿与矿物', '门类': '零售批发'},
+                             '木材、板材等': {'大类': '建筑建材', '门类': '零售批发'},
+                             '木材采集和加工设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '机械设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '机械设备经营租赁': {'大类': '租赁业', '门类': '租赁和商务服务业'},
+                             '林业产品': {'大类': '农林牧渔业产品', '门类': '零售批发'},
+                             '林业服务': {'大类': '农林牧副渔服务', '门类': '农林牧副渔服务'},
+                             '架线和管道工程建筑': {'大类': '土木工程建筑业', '门类': '建筑业'},
+                             '核工业专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '橡胶制品': {'大类': '橡胶、塑料、玻璃和陶瓷制品', '门类': '零售批发'},
+                             '殡葬服务': {'大类': '居民服务业', '门类': '居民服务、修理和其他服务业'},
+                             '殡葬设备及用品': {'大类': '专用设备', '门类': '零售批发'},
+                             '气象服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '水上交通运输设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '水上运输业': {'大类': '水上运输业', '门类': '交通运输、仓储和邮政业'},
+                             '水利和水运工程建筑': {'大类': '土木工程建筑业', '门类': '建筑业'},
+                             '水工机械': {'大类': '专用设备', '门类': '零售批发'},
+                             '水文服务': {'大类': '水利管理业', '门类': '水利、环境和公共设施管理业'},
+                             '水资源管理': {'大类': '水利管理业', '门类': '水利、环境和公共设施管理业'},
+                             '污水处理及其再生利用': {'大类': '水的生产和供应业', '门类': '电力、热力、燃气及水生产和供应业'},
+                             '汽车、摩托车修理与维护': {'大类': '机动车、电子产品和日用产品修理业', '门类': '居民服务、修理和其他服务业'},
+                             '法律服务': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '洗染服务': {'大类': '居民服务业', '门类': '居民服务、修理和其他服务业'},
+                             '测绘地理信息服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '海洋仪器设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '海洋工程建筑': {'大类': '土木工程建筑业', '门类': '建筑业'},
+                             '海洋服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '消防设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '清洁服务': {'大类': '其他服务业', '门类': '居民服务、修理和其他服务业'},
+                             '渔业产品': {'大类': '农林牧渔业产品', '门类': '零售批发'},
+                             '渔业服务': {'大类': '农林牧副渔服务', '门类': '农林牧副渔服务'},
+                             '炼焦和金属冶炼轧制设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '烟草加工设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '热力生产和供应': {'大类': '电力、热力生产和供应业', '门类': '电力、热力、燃气及水生产和供应业'},
+                             '焦炭及其副产品': {'大类': '炼焦产品、炼油产品', '门类': '零售批发'},
+                             '煤炭采选产品': {'大类': '矿与矿物', '门类': '零售批发'},
+                             '燃气生产和供应业': {'大类': '燃气生产和供应业', '门类': '电力、热力、燃气及水生产和供应业'},
+                             '物业管理': {'大类': '房地产业', '门类': '房地产业'},
+                             '特种用途动、植物': {'大类': '农林牧渔业产品', '门类': '零售批发'},
+                             '环保咨询': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '环境与生态监测检测服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '环境污染防治设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '环境治理业': {'大类': '生态保护和环境治理业', '门类': '水利、环境和公共设施管理业'},
+                             '玻璃及其制品': {'大类': '橡胶、塑料、玻璃和陶瓷制品', '门类': '零售批发'},
+                             '理发及美容服务': {'大类': '居民服务业', '门类': '居民服务、修理和其他服务业'},
+                             '生态保护': {'大类': '生态保护和环境治理业', '门类': '水利、环境和公共设施管理业'},
+                             '电信': {'大类': '电信、广播电视和卫星传输服务', '门类': '信息传输、软件和信息技术服务业'},
+                             '电力、城市燃气、蒸汽和热水、水': {'大类': '电力、城市燃气、蒸汽和热水、水', '门类': '零售批发'},
+                             '电力供应': {'大类': '电力、热力生产和供应业', '门类': '电力、热力、燃气及水生产和供应业'},
+                             '电力工业专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '电力工程施工': {'大类': '土木工程建筑业', '门类': '建筑业'},
+                             '电力生产': {'大类': '电力、热力生产和供应业', '门类': '电力、热力、燃气及水生产和供应业'},
+                             '电子和通信测量仪器': {'大类': '通用设备', '门类': '零售批发'},
+                             '电工、电子专用生产设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '电影放映': {'大类': '广播、电视、电影和影视录音制作业', '门类': '文化、体育和娱乐业'},
+                             '电气安装': {'大类': '建筑安装业', '门类': '建筑业'},
+                             '电气设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '电气设备修理': {'大类': '金属制品、机械和设备修理业', '门类': '金属制品、机械和设备修理业'},
+                             '畜牧业服务': {'大类': '农林牧副渔服务', '门类': '农林牧副渔服务'},
+                             '监控设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '石油制品': {'大类': '炼焦产品、炼油产品', '门类': '零售批发'},
+                             '石油和化学工业专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '石油和天然气开采产品': {'大类': '矿与矿物', '门类': '零售批发'},
+                             '石油天然气开采专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '研究和试验发展': {'大类': '研究和试验发展', '门类': '科学研究和技术服务业'},
+                             '社会工作': {'大类': '社会工作', '门类': '卫生和社会工作'},
+                             '社会经济咨询': {'大类': '商务服务业', '门类': '租赁和商务服务业'},
+                             '科技推广和应用服务业': {'大类': '科技推广和应用服务业', '门类': '科学研究和技术服务业'},
+                             '科研、医疗、教育用房': {'大类': '房屋建筑业', '门类': '建筑业'},
+                             '管道和设备安装': {'大类': '建筑安装业', '门类': '建筑业'},
+                             '粮油作物和饲料加工设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '纸、纸制品及印刷品': {'大类': '纸、纸制品及印刷品', '门类': '零售批发'},
+                             '纺织原料、毛皮、被服装具': {'大类': '纺织原料、毛皮、被服装具', '门类': '零售批发'},
+                             '纺织设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '绿化管理': {'大类': '公共设施管理业', '门类': '水利、环境和公共设施管理业'},
+                             '缝纫、服饰、制革和毛皮加工设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '航空器及其配套设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '航空客货运输': {'大类': '航空运输业', '门类': '交通运输、仓储和邮政业'},
+                             '航空航天工业专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '节能环保工程施工': {'大类': '土木工程建筑业', '门类': '建筑业'},
+                             '装卸搬运': {'大类': '装卸搬运和运输代理业', '门类': '交通运输、仓储和邮政业'},
+                             '计算机和办公设备维修': {'大类': '机动车、电子产品和日用产品修理业', '门类': '居民服务、修理和其他服务业'},
+                             '计算机设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '计量标准器具及量具、衡器': {'大类': '通用设备', '门类': '零售批发'},
+                             '货币处理专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '货币金融服务': {'大类': '货币金融服务', '门类': '金融业'},
+                             '质检技术服务': {'大类': '专业技术服务业', '门类': '科学研究和技术服务业'},
+                             '资本市场服务': {'大类': '资本市场服务', '门类': '金融业'},
+                             '车辆': {'大类': '通用设备', '门类': '零售批发'},
+                             '边界勘界和联检专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '运行维护服务': {'大类': '软件和信息技术服务业', '门类': '信息传输、软件和信息技术服务业'},
+                             '通信设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '通用设备修理': {'大类': '金属制品、机械和设备修理业', '门类': '金属制品、机械和设备修理业'},
+                             '道路货物运输': {'大类': '道路运输业', '门类': '交通运输、仓储和邮政业'},
+                             '邮政专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '邮政业': {'大类': '邮政业', '门类': '交通运输、仓储和邮政业'},
+                             '采矿业和制造业服务': {'大类': '采矿业和制造业服务', '门类': '农林牧副渔服务'},
+                             '铁路、船舶、航空航天等运输设备修理': {'大类': '金属制品、机械和设备修理业', '门类': '金属制品、机械和设备修理业'},
+                             '铁路、道路、隧道和桥梁工程建筑': {'大类': '土木工程建筑业', '门类': '建筑业'},
+                             '铁路运输设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '防洪除涝设施管理': {'大类': '水利管理业', '门类': '水利、环境和公共设施管理业'},
+                             '陶瓷制品': {'大类': '橡胶、塑料、玻璃和陶瓷制品', '门类': '零售批发'},
+                             '雷达、无线电和卫星导航设备': {'大类': '通用设备', '门类': '零售批发'},
+                             '非金属矿': {'大类': '矿与矿物', '门类': '零售批发'},
+                             '非金属矿物制品工业专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '非金属矿物材料': {'大类': '建筑建材', '门类': '零售批发'},
+                             '食品加工专用设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '食品及加工盐': {'大类': '食品、饮料和烟草原料', '门类': '零售批发'},
+                             '餐饮业': {'大类': '餐饮业', '门类': '住宿和餐饮业'},
+                             '饮料、酒精及精制茶': {'大类': '食品、饮料和烟草原料', '门类': '零售批发'},
+                             '饮料加工设备': {'大类': '专用设备', '门类': '零售批发'},
+                             '饲养动物及其产品': {'大类': '农林牧渔业产品', '门类': '零售批发'},
+                             '黑色金属冶炼及压延产品': {'大类': '建筑建材', '门类': '零售批发'},
+                             '黑色金属矿': {'大类': '矿与矿物', '门类': '零售批发'}}
+        self.sess = tf.Session(graph=tf.Graph())
+        self.get_model()
+
+        with open(os.path.dirname(__file__)+'/industry_rule_kw_json/tw_industry_keyword_org/tw_industry_keyword_org.json', 'r',
+                  encoding='utf-8') as fp1:
+            self.json_data_industry = json.load(fp1)
+        with open(os.path.dirname(__file__)+'/industry_rule_kw_json/tw_company_classification_keyword/tw_company_classification_keyword.json', 'r',
+                  encoding='utf-8') as fp2:
+            self.json_data_company = json.load(fp2)
+        with open(os.path.dirname(__file__)+'/industry_rule_kw_json/tw_custom_keyword/tw_custom_keyword.json', 'r', encoding='utf-8') as fp3:
+            self.json_data_custom = json.load(fp3)
+
+
+    def get_model(self):
+        with self.sess.as_default() as sess:
+            with self.sess.graph.as_default():
+                meta_graph_def = tf.saved_model.loader.load(sess,
+                                                            tags=['serve'],
+                                                            export_dir=os.path.dirname(__file__)+'/industry_model')
+                signature_key = tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY
+                signature_def = meta_graph_def.signature_def
+
+                self.title = sess.graph.get_tensor_by_name(signature_def[signature_key].inputs['title'].name)
+                self.project = sess.graph.get_tensor_by_name(signature_def[signature_key].inputs['project'].name)
+                self.product = sess.graph.get_tensor_by_name(signature_def[signature_key].inputs['product'].name)
+                self.outputs = sess.graph.get_tensor_by_name(signature_def[signature_key].outputs['outputs'].name)
+
+    def text2array(self, text, tenderee='', maxSententLen=20):
+        tenderee = tenderee.replace('(', '(').replace(')', ')')
+        text = text.replace('(', '(').replace(')', ')')
+        text = re.sub(
+            '(废标|终止|综?合?评审|评标|开标|资审|履约|验收|成交|中标人?|中选人?|单一来源|合同|候选人|结果|变更|更正|答疑|澄清|意向|需求|采购|招标|询比?价|磋商|谈判|比选|比价|竞价|议价)的?(公告|预告|公示)?|关于为?|选取|定点|直接|邀请函?|通知书?|备案|公开|公示|公告|记录|竞争性',
+            '', text)
+        text = text.replace(tenderee, '')
+        text = ' ' if text=="" else text
+        words_docs_list = fool.cut(text)
+        words_docs_list = [[it for it in l if re.search('^[\u4e00-\u9fa5]+$', it)][-maxSententLen:] for l in words_docs_list]
+        array = embedding(words_docs_list, shape=(len(words_docs_list), maxSententLen, 128))
+        return array
+
+    def process(self, title, project, product, tenderee):
+        return self.text2array(title, tenderee), self.text2array(project, tenderee), self.text2array(product)
+
+    def predict_model(self, title, project, product, tenderee=''):
+        title_array, project_array, product_array = self.process(title, project, product, tenderee)
+        rs = self.sess.run(self.outputs,
+                           feed_dict={
+                               self.title:title_array,
+                               self.project:project_array,
+                               self.product:product_array
+                            }
+                           )
+        pred = np.argmax(rs[0])
+        return self.id2lb[pred], rs[0][pred]
+        # # 返回top2 结果
+        # pred_list = np.argsort(-rs[0])
+        # return self.id2lb[pred_list[0]], self.id2lb[pred_list[1]], rs[0][pred_list[0]], rs[0][pred_list[1]]
+
+    def predict_rule(self, doctitle, tenderee, win_tenderer, project_name, product):
+        doctitle = doctitle if doctitle else ''
+        tenderee = tenderee if tenderee else ''
+        win_tenderer = win_tenderer if win_tenderer else ''
+        project_name = project_name if project_name else ''
+        product = product if product else ''
+
+        text_ind = (doctitle + project_name + product).replace(tenderee, '')
+        text_com = win_tenderer
+
+        length_ind_text = len(text_ind) + 1
+        length_com_text = len(text_com) + 1
+        # print(text)
+
+        dic_res = {}  # 行业分类字典
+        score_lst = []  # 得分列表
+        word_lst = []  # 关键词列表
+
+        # 主要内容关键词
+        if text_ind:
+            # logging.info("data_ind%s"%str(_json_data_industry[0]))
+            for data_industry in self.json_data_industry:
+                industry = data_industry['xiaolei']
+                key_word = data_industry['key_word']
+                key_word_2 = data_industry['key_word2']
+                power = float(data_industry['power']) if data_industry['power'] else 0
+                this_score = power * (text_ind.count(key_word) * len(key_word) / length_ind_text)
+
+                if key_word_2:
+                    # key_word_compose = key_word + "+" + key_word_2
+                    if text_ind.count(key_word_2) == 0:
+                        this_score = 0
+
+                if this_score > 0:
+                    # print(industry,key_word,this_score)
+                    if industry in dic_res.keys():
+                        dic_res[industry] += this_score
+                    else:
+                        dic_res[industry] = this_score
+
+                    if key_word not in word_lst:
+                        word_lst.append(key_word)
+
+        # 供应商关键词
+        if text_com:
+
+            for data_company in self.json_data_company:
+                industry = data_company['industry_type']
+                key_word = data_company['company_word']
+                power = float(data_company['industry_rate']) if data_company['industry_rate'] else 0
+                this_score = power * (text_com.count(key_word) * len(key_word) / length_com_text)
+
+                if this_score > 0:
+                    # print(industry,key_word,this_score)
+                    if industry in dic_res.keys():
+                        dic_res[industry] += this_score
+                    else:
+                        dic_res[industry] = this_score
+
+                    if key_word not in word_lst:
+                        word_lst.append(key_word)
+
+        # 自定义关键词
+        if text_ind:
+
+            custom_ind = [
+                ['tenderee', '医院|疾病预防', ['设备', '系统', '器'], '医疗设备'],
+                ['tenderee', '学校|大学|小学|中学|学院|幼儿园', ['设备', '器'], '教育设备'],
+                ['tenderee', '学校|大学|小学|中学|学院|幼儿园|医院', ['工程'], '科研、医疗、教育用房'],
+                ['tenderee', '供电局|电网|国网|电力|电厂|粤电', ['设备', '器', '物资'], '电力工业专用设备'],
+                ['tenderee', '公安|法院|检察院', ['设备', '器'], '政法、检测专用设备'],
+                ['tenderee', '^中铁|^中交|^中建|中国建筑', ['材料'], '其他建筑建材'],
+                ['doctextcon', '信息技术服务|系统开发|信息化|信息系统', ['监理'], '信息技术咨询服务'],
+                ['doctextcon', '工程', ['消防'], '专业施工'],
+                ['doctextcon', '铁路|航空|船舶|航天|广铁', ['维修'], '铁路、船舶、航空航天等运输设备修理'],
+                ['doctextcon', '设备|仪|器', ['租赁'], '机械设备经营租赁'],
+                ['doctextcon', '交通|铁路|公路|道路|桥梁', ['工程'], '铁路、道路、隧道和桥梁工程建筑'],
+                ['win_tenderer', '电力', ['设备', '器'], '电力工业专用设备'],
+                ['win_tenderer', '信息|网络科技', ['系统'], '信息系统集成和物联网技术服务'],
+                ['tenderee,doctextcon', '铁路|广铁|铁道', ['设备', '器', '物资', '材料', '铁路'], '铁路运输设备'],
+            ]
+
+            for data_custom in self.json_data_custom:
+                industry_custom = data_custom['industry']
+                key_word = data_custom['company_word']
+                power = float(data_custom['industry_rate'])
+                for k in range(len(custom_ind)):
+                    subject = ''
+                    if 'tenderee' in custom_ind[k][0]:
+                        subject += tenderee
+                    if 'win_tenderer' in custom_ind[k][0]:
+                        subject += win_tenderer
+                    if 'doctextcon' in custom_ind[k][0]:
+                        subject += text_ind
+
+                    ptn = custom_ind[k][1]
+                    # print('ptn',ptn)
+                    if re.search(ptn, subject) and industry_custom in custom_ind[k][2]:
+                        industry = custom_ind[k][3]
+                    else:
+                        continue
+
+                    this_score = power * (text_ind.count(key_word) * len(key_word) / len(subject))
+
+                    if this_score > 0:
+                        # print(industry,key_word,this_score)
+                        if industry in dic_res.keys():
+                            dic_res[industry] += this_score
+                        else:
+                            dic_res[industry] = this_score
+
+                        if key_word not in word_lst:
+                            word_lst.append(key_word)
+        sort_res = sorted(dic_res.items(), key=lambda x: x[1], reverse=True)
+        lst_res = [s[0] for s in sort_res]
+        score_lst = [str(round(float(s[1]), 2)) for s in sort_res]
+        if len(lst_res) > 0:
+            return lst_res, score_lst, word_lst
+        else:
+            return [""], [], []
+
+    def predict_merge(self, pinmu_type, industry_lst):
+        '''
+        通过一系列规则最终决定使用模型还是规则的结果
+        :param pinmu_type: 模型预测类别
+        :param industry_lst: 规则预测类别列表
+        :return:
+        '''
+        industry_type = industry_lst[0]
+        if industry_type == "":
+            return pinmu_type
+        if industry_type == '专用设备修理' and re.search('修理|维修|装修|修缮', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '其他土木工程建筑' and re.search('工程|建筑|用房|施工|安装|质检|其他专业咨询与调查', pinmu_type):
+            final_type = pinmu_type
+        elif pinmu_type == '专用设备修理' and re.search('工程|修理', industry_type):
+            final_type = industry_type
+        elif pinmu_type == '信息系统集成和物联网技术服务' and re.search('卫星传输|信息处理和存储支持服务|信息技术咨询服务|运行维护服务|其他专业技术服务|医疗设备|医药品',
+                                                          industry_type):
+            final_type = industry_type
+        elif industry_type == '仪器仪表' and re.search('仪器|器具|医疗设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '医药品' and re.search('医疗设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '医药品' and re.search('医疗设备', pinmu_type):
+            final_type = pinmu_type
+        elif re.search('设备', industry_type) and re.search('修理|维修', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '社会工作' and re.search('工程', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '信息系统集成和物联网技术服务' and re.search('信息处理|设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '研究和试验发展' and re.search('其他专业咨询与调查|质检技术服务|信息系统集成|其他工程服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '其他专业咨询与调查' and re.search('工程造价服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '广告业' and re.search('印刷服务|影视节目制作|信息系统', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '清洁服务' and re.search('工程|环境污染防治设备|修理', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '其他公共设施管理' and re.search('信息系统', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '其他专业技术服务' and re.search('工程技术与设计服务|质检技术服务|环境与生态监测检测服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '机械设备经营租赁' and re.search('电信', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '货币金融服务' and re.search('信息系统集成和物联网技术服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '体育场地设施管理' and re.search('体育设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '安全保护服务' and re.search('信息系统|监控设备|互联网安全服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '互联网接入及相关服务' and re.search('通信设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '卫生' and re.search('医疗设备|信息系统', pinmu_type):
+            final_type = pinmu_type
+        elif pinmu_type == '研究和试验发展' and re.search('其他工程服务', industry_type):
+            final_type = industry_type
+        elif pinmu_type == '办公设备' and re.search('教育设备', industry_type):
+            final_type = industry_type
+        elif re.search('车辆|机械设备经营租赁', pinmu_type) and re.search('公路旅客运输', industry_type):
+            final_type = industry_type
+        elif len(industry_lst) > 1 and pinmu_type == industry_lst[1] and re.search('会计|法律|物业|家具|印刷|互联网安全',
+                                                                                   industry_type) == None \
+                and re.search('其他|人力资源服务', pinmu_type) == None:
+            final_type = pinmu_type
+        elif industry_type != "":
+            final_type = industry_type
+        else:
+            final_type = pinmu_type
+        return final_type
+
+    def predict(self, title, project, product, prem):
+        def get_ree_win(prem):
+            tenderee = ""
+            win_tenderer = ""
+            try:
+                for v in prem[0]['prem'].values():
+                    for link in v['roleList']:
+                        if link['role_name'] == 'tenderee' and tenderee == "":
+                            tenderee = link['role_text']
+                        elif link['role_name'] == 'win_tenderer' and win_tenderer == "":
+                            win_tenderer = link['role_text']
+            except Exception as e:
+                print('解析prem 获取招标人、中标人出错')
+            return tenderee, win_tenderer
+        tenderee, win_tenderer = get_ree_win(prem)
+        result_model, prob = self.predict_model(title, project, product, tenderee)
+        industry_lst, score_lst, word_lst = self.predict_rule(title, tenderee, win_tenderer, project, product)
+        final_type = self.predict_merge(result_model, industry_lst)
+        # print('模型:%s;规则:%s;最终:%s'%(result_model, industry_lst[0], final_type))
+        # return {'industry': final_type}
+        return {'industry': {
+                            'class_name': final_type,
+                            'subclass': self.industry_dic[final_type]['大类'],
+                            'class': self.industry_dic[final_type]['门类']
+                            }
+                }
+
+
 
 def getSavedModel():
     #predictor = FormPredictor()

+ 300 - 0
BiddingKG/dl_dev/industry/data_process.py

@@ -0,0 +1,300 @@
+from collections import Counter
+import pandas as pd
+import fool
+import pickle
+import json
+import random
+import time
+import re
+import numpy as np
+import gensim
+
+w2v = r"D:\bidi\BIDI_ML_INFO_EXTRACTION\BiddingKG\dl\wiki_128_word_embedding_new.vector"
+# w2v = "/data/python/lishimin/BiddingKG/dl/wiki_128_word_embedding_new.vector"
+model_w2v = gensim.models.KeyedVectors.load_word2vec_format(w2v, binary=True)
+
+def cut_words(text_list):
+    return fool.cut(text_list)
+
+def words_docs_list2array(words_docs_list, maxSententLen=20):
+    array = np.zeros((len(words_docs_list), maxSententLen, 128))
+    for i in range(len(words_docs_list)):
+        words = words_docs_list[i][-maxSententLen:]
+        for j in range(len(words)):
+            if words[j] in model_w2v:
+                array[i][j] = model_w2v[words[j]]
+            else:
+                print('word not in w2v: ', words[j])
+    return array
+
+def dump_segwords():
+    # df = pd.read_excel('data/新标准所有规则标注数据帅选数据.xlsx')[:]
+    # df = pd.read_excel('data/215类数据太少类别补充数据.xlsx')[:]
+    df = pd.read_excel('data/新标准所有规则标注数据去除产品长度大于100帅选并补充后165595条215类.xlsx')[:]
+    df.dropna(subset=['industry_type'], inplace=True)
+    print(df.head(5))
+    df.fillna(' ', inplace=True)
+    print('len_df', len(df))
+    df = df[df['industry_type']!=' ']
+    print('len_df', len(df))
+
+    from collections import Counter
+    c = Counter(df['industry_type'])
+    print('类别数:', len(c))
+
+    def del_words(tenderee, text):
+        tenderee = tenderee.replace('(', '(').replace(')', ')')
+        text = text.replace('(', '(').replace(')', ')')
+        text = re.sub(
+            '(废标|终止|综?合?评审|评标|开标|资审|履约|验收|成交|中标人?|中选人?|单一来源|合同|候选人|结果|变更|更正|答疑|澄清|意向|需求|采购|招标|询比?价|磋商|谈判|比选|比价|竞价|议价)的?(公告|预告|公示)?|关于为?|选取|定点|直接|邀请函?|通知书?|备案|公开|公示|公告|记录|竞争性',
+            '', text)
+        text = text.replace(tenderee, '')
+        text = ' ' if text=="" else text
+        return text
+
+    def get_winer(sub_docs_json, winner):
+        # winner = ' '
+        if winner == ' ' and 'win_tenderer' in sub_docs_json:
+            l = json.loads(sub_docs_json)
+            for d in l:
+                if d.get('win_tenderer', '')!="":
+                    winner = d.get('win_tenderer', '')
+                    return winner
+        return winner
+    df['doctitle'] = df.apply(lambda x:del_words(x['tenderee'], x['doctitle']), axis=1)
+    df['project_name'] = df.apply(lambda x:del_words(x['tenderee'], x['project_name']), axis=1)
+    # df['win_tenderer'] = df['sub_docs_json'].apply(lambda x:get_winer(x))
+    df['win_tenderer'] = df.apply(lambda x:get_winer(x['sub_docs_json'], x['win_tenderer']), axis=1)
+    labels = sorted(set(df['industry_type']))
+    lb2id = {k:v for v, k in enumerate(labels)}
+    print(df.head(5))
+    print(labels, len(labels))
+    print(lb2id[labels[0]], labels[0])
+
+    t1 = time.time()
+
+    f = open('data/all_segwords.txt', 'w', encoding='utf-8')
+    # f = open('data/all_segwords.txt', 'a', encoding='utf-8')
+    n = 0
+    for docid, title, project, product, win_tenderer, lb in \
+     zip(df['docid'], df['doctitle'], df['project_name'], df['product'], df['win_tenderer'], df['industry_type']):
+        try:
+            title_, project_, product_, win_tenderer_  = cut_words([title, project, product, win_tenderer])
+            segwords = ' '.join(title_)+'#split#'+' '.join(project_)+'#split#'+' '.join(product_)+'#split#'+' '.join(win_tenderer_)
+            f.write('%s\t%s\t%s\n'%(lb, segwords, docid))
+            n += 1
+            if n %1000==0:
+                print('已完成%d篇'%n)
+        except Exception as e:
+            print('error : ', e)
+
+    f.close()
+
+        # all_data = []
+    # all_data = [(docid,cut_words([title, project, product, win_tenderer]), lb) for docid,title,project,product,win_tenderer,lb in zip(df['docid'],df['doctitle'],df['project_name'],df['product'],df['win_tenderer'],df['industry_type'])]
+    # print('all_data_len:', len(all_data))
+    # with open('data/all_data.pkl', 'wb') as f:
+    #     pickle.dump(all_data, f)
+    # with open('data/lb2id.pkl', 'wb') as f:
+    #     pickle.dump(lb2id, f)
+    t2 = time.time()
+    print('总耗时:', t2-t1)
+
+# dump_segwords()
+
+def get_array_data():
+    with open('E:/行业分类/all_data.pkl', 'rb') as f:
+        all_data = pickle.load(f)
+    with open('E:/行业分类/lb2id.pkl', 'rb') as f:
+        lb2id = pickle.load( f)
+    print('all_data_len', len(all_data))
+    print(lb2id)
+    title = [it[0][0] for it in all_data]
+    project = [it[0][1] for it in all_data]
+    product = [it[0][2] for it in all_data]
+    labels_type = [it[1] for it in all_data]
+
+    title_array = words_docs_list2array(title)
+    project_array = words_docs_list2array(project)
+    product_array = words_docs_list2array(product)
+    label_ids = [lb2id[it] for it in labels_type]
+    label_array = np.zeros(shape=((len(label_ids), len(lb2id))))
+    for i in range(len(label_ids)):
+        label_array[i][label_ids[i]] = 1
+    print(title_array.shape, label_array.shape)
+    return title_array, project_array, product_array, label_array, all_data, lb2id
+
+def split_train_test():
+    # with open('E:/行业分类/all_data.pkl', 'rb') as f:
+    #     all_data = pickle.load(f)
+    # df = pd.DataFrame(all_data, columns=['segword_list', 'label'])
+    # df['segword_list'] = df['segword_list'].apply(lambda x: json.dumps(x, ensure_ascii=False))
+    # df.drop_duplicates(subset=['segword_list', 'label'], inplace=True)
+    # df.drop_duplicates(subset=['segword_list'], inplace=True)
+
+    with open('data/all_segwords.txt', 'r', encoding='utf-8') as f:
+        lines = f.read().split('\n')
+    lines = [it.strip().split('\t') for it in lines if '#split#' in it]
+    print(lines[:3])
+    df = pd.DataFrame(lines, columns=['label', 'segwords', 'docid'])
+    print(len(df), df.head(3))
+    df.drop_duplicates(subset=['segwords'], inplace=True)
+    print(len(df))
+
+    c = Counter(df['label'])
+    less_10 = []
+    for k, v in c.items():
+        if v < 10:
+            less_10.append(k)
+    df = df[~df['label'].isin(less_10)]
+    df_test = pd.DataFrame()
+    for lb in set(df['label']):
+        df_tmp = df[df['label']==lb]
+        n = int(len(df_tmp)*0.2)
+        df_test = df_test.append(df_tmp.sample(n=n), ignore_index=True)
+        df_test = df_test.sample(frac=1)
+    # df_train = df[~df['segword_list'].isin(df_test['segword_list'])]
+    df_train = df[~df['segwords'].isin(df_test['segwords'])]
+    df_train = df_train.sample(frac=1)
+    print(len(df), len(df_train), len(df_test))
+    df_train.to_excel('data/新标准215类train.xlsx')
+    df_test.to_excel('data/新标准215类test.xlsx')
+    return df_train, df_test
+
+def df_to_array(df, seq_len=20):
+    # df['segword_list'] = df['segword_list'].apply(lambda x:json.loads(x))
+    # with open('E:/行业分类/lb2id.pkl', 'rb') as f:
+    #     lb2id = pickle.load( f)
+    labels = sorted(set(df['label']))
+    lb2id = {k:v for v, k in enumerate(labels)}
+    # all_data = list(df['segword_list'])
+    all_data = df['segwords'].apply(lambda x:x.split('#split#'))
+    for l in all_data:
+        assert len(l) == 4
+    print('all_data_len', len(all_data))
+    print(lb2id)
+    title = [it[0].split() for it in all_data]
+    project = [it[1].split() for it in all_data]
+    product = [it[2].split() for it in all_data]
+    labels_type = [it for it in df['label']]
+
+    title = [[it for it in l if re.search('^[\u4e00-\u9fa5]+$', it)] for l in title]
+    project = [[it for it in l if re.search('^[\u4e00-\u9fa5]+$', it)] for l in project]
+    product = [[it for it in l if re.search('^[\u4e00-\u9fa5]+$', it)] for l in product]
+
+    title_array = words_docs_list2array(title,seq_len)
+    project_array = words_docs_list2array(project,seq_len)
+    product_array = words_docs_list2array(product,seq_len)
+    label_ids = [lb2id[it] for it in labels_type]
+    label_array = np.zeros(shape=((len(label_ids), len(lb2id))))
+    for i in range(len(label_ids)):
+        label_array[i][label_ids[i]] = 1
+    print(title_array.shape, label_array.shape)
+    return title_array, project_array, product_array, label_array, all_data, lb2id
+
+def getVocabAndMatrix(model):
+    '''
+    加载词向量或字向量,返回词、字列表及向量矩阵,过滤掉非纯中文词、字
+    :param model: 加载的词或字向量模型  gensim.models.keyedvectors.KeyedVectors
+    :return:
+    '''
+    vocab = ['<pad>'] + [it for it in model.index2word if re.search('^[\u4e00-\u9fa5]+$', it)]
+    word2index = {k:v for k,v in enumerate(vocab)}
+    Embedding_size = model[model.index2word[0]].shape[0]
+    embedding_matrix = np.zeros((len(vocab), Embedding_size))
+    for i in range(1, len(vocab)):
+        embedding_matrix[i] = model[vocab[i]]
+    return vocab, embedding_matrix, word2index
+
+def df_to_ids(df, word2index):
+    def words2ids(words_docs_list, maxSententLen=20):
+        array = np.zeros((len(words_docs_list), maxSententLen))
+        for i in range(len(words_docs_list)):
+            words = words_docs_list[i][-maxSententLen:]
+            for j in range(len(words)):
+                if words[j] in word2index:
+                    array[i][j] = word2index[words[j]]
+        return array
+    df['segword_list'] = df['segword_list'].apply(lambda x:json.loads(x))
+    # with open('E:/行业分类/lb2id.pkl', 'rb') as f:
+    #     lb2id = pickle.load( f)
+    labels = sorted(set(df['label']))
+    lb2id = {k:v for v, k in enumerate(labels)}
+    all_data = list(df['segword_list'])
+    print('all_data_len', len(all_data))
+    print(lb2id)
+    title = [it[0] for it in all_data]
+    project = [it[1] for it in all_data]
+    product = [it[2] for it in all_data]
+    labels_type = [it for it in df['label']]
+
+    title_ids = words2ids(title)
+    project_ids = words2ids(project)
+    product_ids = words2ids(product)
+    label_ids = [lb2id[it] for it in labels_type]
+    label_array = np.zeros(shape=((len(label_ids), len(lb2id))))
+    for i in range(len(label_ids)):
+        label_array[i][label_ids[i]] = 1
+    return title_ids, project_ids, product_ids, label_array, all_data, lb2id
+if __name__ == "__main__":
+    # dump_segwords()
+    # split_train_test()
+    # df = pd.read_excel('E:/行业分类/新标准所有规则标注数据过滤掉标题、项目、产品三要素重复的剩余498976条215类.xlsx')[:]
+    # df.fillna(' ', inplace=True)
+    # c = Counter(df['industry_type'])
+    import copy
+    # df_fill = pd.DataFrame()
+    # for k, v in c.items():
+    #     if v > 1000:
+    #         print(k, v)
+    #         df2 = copy.deepcopy(df[df['industry_type']==k])
+    #         print(len(df2))
+    #         if len(df2)>1000:
+    #             df2.drop_duplicates(subset=['doctitle'], inplace=True)
+    #             print(len(df2))
+    #             if len(df2) > 1000:
+    #                 df2.drop_duplicates(subset=['project_name'], inplace=True)
+    #                 print(len(df2))
+    #                 if len(df2) > 1000:
+    #                     df2.drop_duplicates(subset=['product'], inplace=True)
+    #                     print(len(df2))
+    #                     if len(df2) > 1000:
+    #                         df2.drop_duplicates(subset=['tenderee'], inplace=True)
+    #                         print(len(df2))
+    #
+    #         df_fill = df_fill.append(df2, ignore_index=True)
+    #     else:
+    #         df2 = copy.deepcopy(df[df['industry_type'] == k])
+    #         df_fill = df_fill.append(df2, ignore_index=True)
+    # print('len_df_fill', len(df_fill))
+    # df_fill = df_fill.sample(frac=1)
+    # df_fill.to_excel('E:/行业分类/新标准所有规则标注数据帅选数据.xlsx')
+    # import re
+    # df = pd.read_excel('E:/行业分类/新标准所有规则标注数据帅选数据.xlsx')
+    # c = Counter(df['industry_type'])
+    # print(c.most_common())
+    # l = []
+    # pos = neg = 0
+    # for i in df.index:
+    #     title = df.loc[i, 'doctitle']
+    #     name = df.loc[i, 'project_name']
+    #     ree = df.loc[i, 'tenderee']
+    #     name = re.sub(
+    #         '(废标|终止|综?合?评审|评标|开标|资审|履约|验收|成交|中标人?|中选人?|单一来源|合同|候选人|结果|变更|更正|答疑|澄清|意向|需求|采购|招标|询比?价|磋商|谈判|比选|比价|竞价|议价)的?(公告|预告|公示)?|关于为?|选取|定点|直接|邀请函?|通知书?|备案|公开|公示|公告|记录|竞争性',
+    #         '', name)
+    #     if name in title:
+    #         pos += 1
+    #     else:
+    #         neg += 1
+    #         print(name,   title)
+        # text = title.replace(name, '##').replace(ree, '')
+        # text_l = text.split('##')
+        # for w in text_l:
+        #     l.append(w)
+
+    # c = Counter(l)
+    # print(c.most_common(100))
+    # print('pos:%d, neg:%d'%(pos,neg))
+    # with open('E:/行业分类/过滤词.txt', 'w', encoding='utf-8') as f:
+    #     for it in c.most_common(200):
+    #         f.write(it[0]+'\n')

BIN
BiddingKG/dl_dev/industry/industry_model/saved_model.pb


BIN
BiddingKG/dl_dev/industry/industry_model/variables/variables.data-00000-of-00001


BIN
BiddingKG/dl_dev/industry/industry_model/variables/variables.index


+ 259 - 0
BiddingKG/dl_dev/industry/model.py

@@ -0,0 +1,259 @@
+import tensorflow as tf
+import tensorflow.keras.backend as K
+import numpy as np
+import pandas as pd
+import pickle
+
+from BiddingKG.dl_dev.industry.data_process import get_array_data, df_to_array
+
+id2lb = {0: '专业施工', 1: '专用仪器仪表', 2: '专用设备修理', 3: '互联网信息服务', 4: '互联网安全服务', 5: '互联网平台', 6: '互联网接入及相关服务', 7: '人力资源服务',
+         8: '人造原油', 9: '仓储业', 10: '仪器仪表', 11: '仪器仪表修理', 12: '会计、审计及税务服务', 13: '会议、展览及相关服务', 14: '住宅、商业用房',
+         15: '体育场地设施管理', 16: '体育组织', 17: '体育设备', 18: '保险服务', 19: '信息处理和存储支持服务', 20: '信息技术咨询服务', 21: '信息系统集成和物联网技术服务',
+         22: '修缮工程', 23: '健康咨询', 24: '公路旅客运输', 25: '其他专业咨询与调查', 26: '其他专业技术服务', 27: '其他交通运输设备', 28: '其他公共设施管理',
+         29: '其他土木工程建筑', 30: '其他工程服务', 31: '其他建筑建材', 32: '其他运输业', 33: '农业和林业机械', 34: '农业服务', 35: '农产品',
+         36: '农副食品,动、植物油制品', 37: '出版业', 38: '办公消耗用品及类似物品', 39: '办公设备', 40: '化学原料及化学制品', 41: '化学纤维', 42: '化学药品和中药专用设备',
+         43: '医疗设备', 44: '医药品', 45: '卫星传输服务', 46: '卫生', 47: '印刷服务', 48: '图书和档案', 49: '图书档案设备', 50: '图书馆与档案馆',
+         51: '土地管理业', 52: '地质勘查', 53: '地震服务', 54: '场馆、站港用房', 55: '城市公共交通运输', 56: '塑料制品、半成品及辅料', 57: '天然石料', 58: '娱乐设备',
+         59: '婚姻服务', 60: '安全保护服务', 61: '安全生产设备', 62: '家具用具', 63: '家用电器修理', 64: '工业、生产用房', 65: '工业与专业设计及其他专业技术服务',
+         66: '工矿工程建筑', 67: '工程技术与设计服务', 68: '工程机械', 69: '工程监理服务', 70: '工程评价服务', 71: '工程造价服务', 72: '市场调查', 73: '广告业',
+         74: '广播', 75: '广播、电视、电影设备', 76: '广播电视传输服务', 77: '废弃资源综合利用业', 78: '建筑涂料', 79: '建筑物、构筑物附属结构', 80: '建筑物拆除和场地准备活动',
+         81: '建筑装饰和装修业', 82: '录音制作', 83: '影视节目制作', 84: '房地产中介服务', 85: '房地产开发经营', 86: '房地产租赁经营', 87: '房屋租赁', 88: '招标代理',
+         89: '探矿、采矿、选矿和造块设备', 90: '政法、检测专用设备', 91: '教育服务', 92: '教育设备', 93: '文物及非物质文化遗产保护', 94: '文物和陈列品', 95: '文艺创作与表演',
+         96: '文艺设备', 97: '新闻业', 98: '旅行社及相关服务', 99: '日杂用品', 100: '有色金属冶炼及压延产品', 101: '有色金属矿', 102: '木材、板材等',
+         103: '木材采集和加工设备', 104: '机械设备', 105: '机械设备经营租赁', 106: '林业产品', 107: '林业服务', 108: '架线和管道工程建筑', 109: '核工业专用设备',
+         110: '橡胶制品', 111: '殡葬服务', 112: '殡葬设备及用品', 113: '气象服务', 114: '水上交通运输设备', 115: '水上运输业', 116: '水利和水运工程建筑',
+         117: '水工机械', 118: '水文服务', 119: '水资源管理', 120: '污水处理及其再生利用', 121: '汽车、摩托车修理与维护', 122: '法律服务', 123: '洗染服务',
+         124: '测绘地理信息服务', 125: '海洋仪器设备', 126: '海洋工程建筑', 127: '海洋服务', 128: '消防设备', 129: '清洁服务', 130: '渔业产品', 131: '渔业服务',
+         132: '炼焦和金属冶炼轧制设备', 133: '烟草加工设备', 134: '热力生产和供应', 135: '焦炭及其副产品', 136: '煤炭采选产品', 137: '燃气生产和供应业', 138: '物业管理',
+         139: '特种用途动、植物', 140: '环保咨询', 141: '环境与生态监测检测服务', 142: '环境污染防治设备', 143: '环境治理业', 144: '玻璃及其制品', 145: '理发及美容服务',
+         146: '生态保护', 147: '电信', 148: '电力、城市燃气、蒸汽和热水、水', 149: '电力供应', 150: '电力工业专用设备', 151: '电力工程施工', 152: '电力生产',
+         153: '电子和通信测量仪器', 154: '电工、电子专用生产设备', 155: '电影放映', 156: '电气安装', 157: '电气设备', 158: '电气设备修理', 159: '畜牧业服务',
+         160: '监控设备', 161: '石油制品', 162: '石油和化学工业专用设备', 163: '石油和天然气开采产品', 164: '石油天然气开采专用设备', 165: '研究和试验发展',
+         166: '社会工作', 167: '社会经济咨询', 168: '科技推广和应用服务业', 169: '科研、医疗、教育用房', 170: '管道和设备安装', 171: '粮油作物和饲料加工设备',
+         172: '纸、纸制品及印刷品', 173: '纺织原料、毛皮、被服装具', 174: '纺织设备', 175: '绿化管理', 176: '缝纫、服饰、制革和毛皮加工设备', 177: '航空器及其配套设备',
+         178: '航空客货运输', 179: '航空航天工业专用设备', 180: '节能环保工程施工', 181: '装卸搬运', 182: '计算机和办公设备维修', 183: '计算机设备',
+         184: '计量标准器具及量具、衡器', 185: '货币处理专用设备', 186: '货币金融服务', 187: '质检技术服务', 188: '资本市场服务', 189: '车辆',
+         190: '边界勘界和联检专用设备', 191: '运行维护服务', 192: '通信设备', 193: '通用设备修理', 194: '道路货物运输', 195: '邮政专用设备', 196: '邮政业',
+         197: '采矿业和制造业服务', 198: '铁路、船舶、航空航天等运输设备修理', 199: '铁路、道路、隧道和桥梁工程建筑', 200: '铁路运输设备', 201: '防洪除涝设施管理',
+         202: '陶瓷制品', 203: '雷达、无线电和卫星导航设备', 204: '非金属矿', 205: '非金属矿物制品工业专用设备', 206: '非金属矿物材料', 207: '食品加工专用设备',
+         208: '食品及加工盐', 209: '餐饮业', 210: '饮料、酒精及精制茶', 211: '饮料加工设备', 212: '饲养动物及其产品', 213: '黑色金属冶炼及压延产品', 214: '黑色金属矿'}
+lb2id = {k: v for v, k in id2lb.items()}
+
+seq_len=20
+
+def recall(y_true, y_pred):
+    '''
+    计算召回率
+    @Argus:
+        y_true: 正确的标签
+        y_pred: 模型预测的标签
+
+    @Return
+        召回率
+    '''
+    c1 = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
+    c3 = K.sum(K.round(K.clip(y_true, 0, 1)))
+    if c3 == 0:
+        return 0
+    recall = c1 / c3
+    return recall
+
+
+def f1_score(y_true, y_pred):
+    '''
+    计算F1
+
+    @Argus:
+        y_true: 正确的标签
+        y_pred: 模型预测的标签
+
+    @Return
+        F1值
+    '''
+
+    c1 = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
+    c2 = K.sum(K.round(K.clip(y_pred, 0, 1)))
+    c3 = K.sum(K.round(K.clip(y_true, 0, 1)))
+    precision = c1 / c2
+    if c3 == 0:
+        recall = 0
+    else:
+        recall = c1 / c3
+    f1_score = 2 * (precision * recall) / (precision + recall)
+    return f1_score
+
+
+def precision(y_true, y_pred):
+    '''
+    计算精确率
+
+    @Argus:
+        y_true: 正确的标签
+        y_pred: 模型预测的标签
+
+    @Return
+        精确率
+    '''
+    c1 = K.sum(K.round(K.clip(y_true * y_pred, 0, 1)))
+    c2 = K.sum(K.round(K.clip(y_pred, 0, 1)))
+    precision = c1 / c2
+    return precision
+
+# SELU 必须与 lecun_normal 初始化一起使用,且将 AlphaDropout 作为 dropout
+def rnn_model(seq_len=seq_len, rnn_unit=128): #64
+    input1 = tf.keras.Input(shape=(seq_len, 128), name='title') #20
+    input2 = tf.keras.Input(shape=(seq_len, 128), name='project')
+    input3 = tf.keras.Input(shape=(seq_len, 128), name='product')
+
+    lstm1 = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(units=rnn_unit, recurrent_dropout=0.5))(input1) #64
+    lstm2 = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(units=rnn_unit, recurrent_dropout=0.5))(input2)  #rnn_unit*4
+    lstm3 = tf.keras.layers.Bidirectional(tf.keras.layers.LSTM(units=rnn_unit, recurrent_dropout=0.5))(input3)  #rnn_unit*2
+    concat = tf.keras.layers.Concatenate()([lstm1, lstm2, lstm3])
+    drop = tf.keras.layers.Dropout(rate=0.5)(concat)
+    out = tf.keras.layers.Dense(units=215, activation='softmax')(drop) #183
+    model = tf.keras.Model(inputs=(input1, input2, input3), outputs=out)
+    model.compile(optimizer=tf.keras.optimizers.Adam(lr=0.001), loss=tf.keras.losses.categorical_crossentropy,
+                  metrics=[recall, precision, f1_score, tf.keras.metrics.categorical_accuracy])  #recall, precision, f1_score
+    print(model.summary())
+    return model
+
+def predict():
+    import copy
+    # model = tf.keras.models.load_model('model.18-1.3477-0.7020.h5', #准确率:0.6912, 总样本:32735
+    #                                    custom_objects={'recall':recall, 'f1_score':f1_score, 'precision':precision})  #准确率:0.8383, 总样本:32735
+    df_test = pd.read_excel('data/新标准215类test.xlsx')
+    # df_test = pd.read_excel('E:\行业分类/标记数据.xlsx')
+    # df_test = pd.read_excel('data/新标准215类train.xlsx')
+    # df_test = pd.read_excel('data/新标准215类test_predict.xlsx')
+    # df_test = pd.read_excel('data/新标准215类筛选数据test_predict.xlsx')
+    # df_test = pd.read_excel('data/新标准所有标准规则标注数据_relabel.xlsx')
+    # df_test = pd.read_excel('data/新标准所有标准规则标注数据_relabel_predict_标注与模型不一致数据50592条.xlsx')
+    # df_test = pd.read_excel('data/新标准所有标准规则标注数据_relabel_predict_标注与模型不一致数据50592条预测结果_2为最新预测.xlsx')
+
+    df_test.reset_index(drop=True, inplace=True)
+    pred_list = []
+    prob_list = []
+    x1, x2, x3, y, all_data, _= df_to_array(df_test, seq_len)
+    # assert len(lb2id) == 215
+    # id2lb = {k:v for v,k in lb2id.items()}
+    n = 0
+    # model.load_weights('model.50-1.5302-0.5805-0.7621-0.6589.h5')  #准确率:0.6515, 总样本:32735
+    # model.load_weights('model.97-1.3751-0.6604-0.7787-0.7147.h5')  #准确率:0.6515, 总样本:32735
+    # model.load_weights('model.25-1.4056-0.6231-0.7799-0.6926.h5')  #
+    # model.load_weights('model.19-1.3846-0.6070-0.7887-0.6859.h5')  # 测试集做训练
+    # model.load_weights('model.28-0.4495-0.8564-0.8921-0.8739.h5')  # 帅选数据重新训练
+    model.load_weights('model.19-0.9958-0.7568.h5')  # 帅选数据重新训练
+    # model.load_weights('model.21-0.9929-0.7576.h5')
+
+    # model.load_weights('newmodel_rnn_50_256.h5') #准确率:0.8290, 总样本:32735
+
+    pred = model.predict(x=[x1[n:], x2[n:], x3[n:]])
+    label = copy.deepcopy(y[n:])
+    data = all_data[n:]
+    for i in range(len(pred)):
+        pred_list.append(id2lb[np.argmax(pred[i])])
+        prob_list.append(pred[i][np.argmax(pred[i])])
+        # # print(pred[i])
+        # # print(label[i])
+        # if np.argmax(pred[i]) != np.argmax(label[i]):
+        #     print(data[i])
+        #     print(id2lb[np.argmax(pred[i])] , id2lb[np.argmax(y[n:][i])])
+        # else:
+        #     print('equal')
+    assert len(pred_list) == len(df_test)
+    df_test['预测结果2'] = pd.Series(pred_list)
+    df_test['预测概率2'] = pd.Series(prob_list)
+    df_test['pred=label2'] = df_test.apply(lambda x:1 if x['预测结果2']==x['label'] else 0, axis=1)
+    # df_test['pred=old_label'] = df_test.apply(lambda x:1 if x['预测结果']==x['old_label'] else 0, axis=1)
+    print('准确率:%.4f, 总样本:%d'%(sum(df_test['pred=label2'])/len(df_test), len(df_test)))
+    # print('准确率:%.4f, 总样本:%d'%(sum(df_test['pred=old_label'])/len(df_test), len(df_test)))
+    # df_test[['doctitle', 'project_name', 'product', 'win_tenderer']] = df_test["segwords"].str.split('#split#',
+    #                                                                                                  expand=True).loc[:, :]
+    # df_test.to_excel('data/新标准215类筛选数据test_predict.xlsx', index=False)
+    df_test.to_excel('data/新标准215类test_predict.xlsx', index=False)
+    # df_test.to_excel('E:\行业分类/标记数据.xlsx', index=False)
+    # df_test.to_excel('data/新标准所有标准规则标注数据_relabel_predict_标注与模型不一致数据50592条预测结果_3为最新预测.xlsx', index=False)
+    # df_test.to_excel('data/新标准所有标准规则标注数据_relabel_predict.xlsx', index=False)
+
+    # df_test.to_excel('data/新标准215类train_predict.xlsx')
+
+def data_enhance(df, n=1500):
+    l = []
+    for lb in set(df['label']):
+        df_lb = df[df['label']==lb]
+        num = len(df_lb)
+        if num < n:
+            l.append(df_lb.sample(n=n-num, replace=True))
+    df = df.append(l, ignore_index=True)
+    return df.sample(frac=1)
+
+def train():
+    import pandas as pd
+    # from new_model.data_process import get_array_data, df_to_array
+
+    df_train = pd.read_excel('data/新标准215类train.xlsx')    #E:\行业分类/新标准183类train.xlsx
+    df_test = pd.read_excel('data/新标准215类test.xlsx')
+
+    df_train = data_enhance(df_train, n=50)
+
+    # df_test = pd.read_excel('data/新标准215类train.xlsx')
+    # df_train = pd.read_excel('data/新标准215类test.xlsx')
+
+    df_train = df_train.sample(frac=1)
+    df_test = df_test.sample(frac=1)
+
+    x1, x2, x3, y, all_data, lb2id = df_to_array(df_train, seq_len)
+    x1_t, x2_t, x3_t, y_t, all_data_t, lb2id_t = df_to_array(df_test, seq_len)
+    # model.load_weights(filepath='model.50-1.4338-0.6360-0.7683-0.6959.h5')
+    model.fit(x=[x1,x2,x3], y=y, batch_size=512, epochs=100, verbose=1,
+                    # callbacks=[tf.keras.callbacks.ModelCheckpoint(filepath= 'model.{epoch:02d}-{val_loss:.4f}-{val_recall:.4f}-{val_precision:.4f}-{val_f1_score:.4f}.h5',#'newmodel_rnn_50_256.h5',
+                    callbacks=[tf.keras.callbacks.ModelCheckpoint(filepath= 'model.{epoch:02d}-{val_loss:.4f}-{val_categorical_accuracy:.4f}.h5',#'newmodel_rnn_50_256.h5',
+                                                                  monitor='val_loss',
+                                                                  save_best_only=True,
+                                                                  save_weights_only=False)],
+                    validation_data=([x1_t, x2_t, x3_t], y_t), shuffle=True)
+
+    tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir='logs/',
+                                                          histogram_freq=1,write_images=True, write_grads=True)
+    # model.fit(x=[x1,x2,x3], y=y, batch_size=512, epochs=50, verbose=1,
+    #                 callbacks=[tf.keras.callbacks.ModelCheckpoint(filepath='newmodel_rnn.h5',
+    #                                                               monitor='val_loss',
+    #                                                               save_best_only=True,
+    #                                                               save_weights_only=False),
+    #                            tensorboard_callback],
+    #                 validation_split=0.2, shuffle=False)
+
+
+def save_model():
+    filepath = 'model.21-0.9929-0.7576.h5'
+    # filepath = 'newmodel.h5'
+    with tf.Graph().as_default():
+        with tf.Session() as sess:
+            model = tf.keras.models.load_model(filepath, custom_objects={'precision': precision, 'recall': recall,
+                                                                         'f1_score': f1_score})
+            print(model.summary())
+            print(model.weights)
+            tf.saved_model.simple_save(sess,
+                                       'industry_model/',
+                                       inputs={
+                                           "title": model.input[0],
+                                           "project": model.input[1],
+                                           "product": model.input[2],
+                                       },
+                                       outputs={"outputs": model.output})
+
+
+
+if __name__ == "__main__":
+    # rnn 加batchnormal及dropout loss: 0.5266 - recall: 0.8121 - precision: 0.9099 - f1_score: 0.8582 - val_loss: 0.8428 - val_recall: 0.7788 - val_precision: 0.8683 - val_f1_score: 0.8211
+    # loss: 0.6649 - recall: 0.7623 - precision: 0.8891 - f1_score: 0.8208 - val_loss: 0.9595 - val_recall: 0.7373 - val_precision: 0.8468 - val_f1_score: 0.7878
+    model = rnn_model() # loss: 0.5595 - categorical_crossentropy: 0.5595 - recall: 0.7968 - precision: 0.9241 - f1_score: 0.8557 - val_loss: 0.9927 - val_categorical_crossentropy: 0.9927 - val_recall: 0.7195 - val_precision: 0.8498 - val_f1_score: 0.7791
+    # model = cnn_model()  # epoch 15 - loss: 1.1907 - recall: 0.6311 - precision: 0.8064 - f1_score: 0.7080 - val_loss: 1.4360 - val_recall: 0.6322 - val_precision: 0.7886 - val_f1_score: 0.7017
+
+    # from new_model.data_process import get_array_data, df_to_array
+    # x1, x2, x3, y, all_data, lb2id = get_array_data()
+    train()
+    # predict()
+    # save_model()
+
+

+ 322 - 0
BiddingKG/dl_dev/industry/predict.py

@@ -0,0 +1,322 @@
+#encoding=utf-8
+import os
+import re
+import tensorflow as tf
+import numpy as np
+import gensim
+from BiddingKG.dl.common.Utils import embedding
+import json
+import fool
+
+
+class IndustryPredictor():
+    def __init__(self,):
+        model_path = 'model.21-0.9929-0.7576.h5'
+        self.model_path = 'industry_model'
+        self.id2lb = {0: '专业施工', 1: '专用仪器仪表', 2: '专用设备修理', 3: '互联网信息服务', 4: '互联网安全服务', 5: '互联网平台', 6: '互联网接入及相关服务', 7: '人力资源服务',
+             8: '人造原油', 9: '仓储业', 10: '仪器仪表', 11: '仪器仪表修理', 12: '会计、审计及税务服务', 13: '会议、展览及相关服务', 14: '住宅、商业用房',
+             15: '体育场地设施管理', 16: '体育组织', 17: '体育设备', 18: '保险服务', 19: '信息处理和存储支持服务', 20: '信息技术咨询服务',
+             21: '信息系统集成和物联网技术服务', 22: '修缮工程', 23: '健康咨询', 24: '公路旅客运输', 25: '其他专业咨询与调查', 26: '其他专业技术服务',
+             27: '其他交通运输设备', 28: '其他公共设施管理', 29: '其他土木工程建筑', 30: '其他工程服务', 31: '其他建筑建材', 32: '其他运输业', 33: '农业和林业机械',
+             34: '农业服务', 35: '农产品', 36: '农副食品,动、植物油制品', 37: '出版业', 38: '办公消耗用品及类似物品', 39: '办公设备', 40: '化学原料及化学制品',
+             41: '化学纤维', 42: '化学药品和中药专用设备', 43: '医疗设备', 44: '医药品', 45: '卫星传输服务', 46: '卫生', 47: '印刷服务', 48: '图书和档案',
+             49: '图书档案设备', 50: '图书馆与档案馆', 51: '土地管理业', 52: '地质勘查', 53: '地震服务', 54: '场馆、站港用房', 55: '城市公共交通运输',
+             56: '塑料制品、半成品及辅料', 57: '天然石料', 58: '娱乐设备', 59: '婚姻服务', 60: '安全保护服务', 61: '安全生产设备', 62: '家具用具',
+             63: '家用电器修理', 64: '工业、生产用房', 65: '工业与专业设计及其他专业技术服务', 66: '工矿工程建筑', 67: '工程技术与设计服务', 68: '工程机械',
+             69: '工程监理服务', 70: '工程评价服务', 71: '工程造价服务', 72: '市场调查', 73: '广告业', 74: '广播', 75: '广播、电视、电影设备',
+             76: '广播电视传输服务', 77: '废弃资源综合利用业', 78: '建筑涂料', 79: '建筑物、构筑物附属结构', 80: '建筑物拆除和场地准备活动', 81: '建筑装饰和装修业',
+             82: '录音制作', 83: '影视节目制作', 84: '房地产中介服务', 85: '房地产开发经营', 86: '房地产租赁经营', 87: '房屋租赁', 88: '招标代理',
+             89: '探矿、采矿、选矿和造块设备', 90: '政法、检测专用设备', 91: '教育服务', 92: '教育设备', 93: '文物及非物质文化遗产保护', 94: '文物和陈列品',
+             95: '文艺创作与表演', 96: '文艺设备', 97: '新闻业', 98: '旅行社及相关服务', 99: '日杂用品', 100: '有色金属冶炼及压延产品', 101: '有色金属矿',
+             102: '木材、板材等', 103: '木材采集和加工设备', 104: '机械设备', 105: '机械设备经营租赁', 106: '林业产品', 107: '林业服务', 108: '架线和管道工程建筑',
+             109: '核工业专用设备', 110: '橡胶制品', 111: '殡葬服务', 112: '殡葬设备及用品', 113: '气象服务', 114: '水上交通运输设备', 115: '水上运输业',
+             116: '水利和水运工程建筑', 117: '水工机械', 118: '水文服务', 119: '水资源管理', 120: '污水处理及其再生利用', 121: '汽车、摩托车修理与维护',
+             122: '法律服务', 123: '洗染服务', 124: '测绘地理信息服务', 125: '海洋仪器设备', 126: '海洋工程建筑', 127: '海洋服务', 128: '消防设备',
+             129: '清洁服务', 130: '渔业产品', 131: '渔业服务', 132: '炼焦和金属冶炼轧制设备', 133: '烟草加工设备', 134: '热力生产和供应', 135: '焦炭及其副产品',
+             136: '煤炭采选产品', 137: '燃气生产和供应业', 138: '物业管理', 139: '特种用途动、植物', 140: '环保咨询', 141: '环境与生态监测检测服务',
+             142: '环境污染防治设备', 143: '环境治理业', 144: '玻璃及其制品', 145: '理发及美容服务', 146: '生态保护', 147: '电信',
+             148: '电力、城市燃气、蒸汽和热水、水', 149: '电力供应', 150: '电力工业专用设备', 151: '电力工程施工', 152: '电力生产', 153: '电子和通信测量仪器',
+             154: '电工、电子专用生产设备', 155: '电影放映', 156: '电气安装', 157: '电气设备', 158: '电气设备修理', 159: '畜牧业服务', 160: '监控设备',
+             161: '石油制品', 162: '石油和化学工业专用设备', 163: '石油和天然气开采产品', 164: '石油天然气开采专用设备', 165: '研究和试验发展', 166: '社会工作',
+             167: '社会经济咨询', 168: '科技推广和应用服务业', 169: '科研、医疗、教育用房', 170: '管道和设备安装', 171: '粮油作物和饲料加工设备', 172: '纸、纸制品及印刷品',
+             173: '纺织原料、毛皮、被服装具', 174: '纺织设备', 175: '绿化管理', 176: '缝纫、服饰、制革和毛皮加工设备', 177: '航空器及其配套设备', 178: '航空客货运输',
+             179: '航空航天工业专用设备', 180: '节能环保工程施工', 181: '装卸搬运', 182: '计算机和办公设备维修', 183: '计算机设备', 184: '计量标准器具及量具、衡器',
+             185: '货币处理专用设备', 186: '货币金融服务', 187: '质检技术服务', 188: '资本市场服务', 189: '车辆', 190: '边界勘界和联检专用设备', 191: '运行维护服务',
+             192: '通信设备', 193: '通用设备修理', 194: '道路货物运输', 195: '邮政专用设备', 196: '邮政业', 197: '采矿业和制造业服务',
+             198: '铁路、船舶、航空航天等运输设备修理', 199: '铁路、道路、隧道和桥梁工程建筑', 200: '铁路运输设备', 201: '防洪除涝设施管理', 202: '陶瓷制品',
+             203: '雷达、无线电和卫星导航设备', 204: '非金属矿', 205: '非金属矿物制品工业专用设备', 206: '非金属矿物材料', 207: '食品加工专用设备', 208: '食品及加工盐',
+             209: '餐饮业', 210: '饮料、酒精及精制茶', 211: '饮料加工设备', 212: '饲养动物及其产品', 213: '黑色金属冶炼及压延产品', 214: '黑色金属矿'}
+        self.sess = tf.Session(graph=tf.Graph())
+        self.get_model()
+
+        with open('rule_kw_json/tw_industry_keyword_org/tw_industry_keyword_org.json', 'r',
+                  encoding='utf-8') as fp1:
+            self.json_data_industry = json.load(fp1)
+        with open('rule_kw_json/tw_company_classification_keyword/tw_company_classification_keyword.json', 'r',
+                  encoding='utf-8') as fp2:
+            self.json_data_company = json.load(fp2)
+        with open('rule_kw_json/tw_custom_keyword/tw_custom_keyword.json', 'r', encoding='utf-8') as fp3:
+            self.json_data_custom = json.load(fp3)
+
+
+    def get_model(self):
+        with self.sess.as_default() as sess:
+            with self.sess.graph.as_default():
+                meta_graph_def = tf.saved_model.loader.load(sess,
+                                                            tags=['serve'],
+                                                            export_dir=os.path.dirname(__file__)+'/industry_model')
+                signature_key = tf.saved_model.signature_constants.DEFAULT_SERVING_SIGNATURE_DEF_KEY
+                signature_def = meta_graph_def.signature_def
+
+                self.title = sess.graph.get_tensor_by_name(signature_def[signature_key].inputs['title'].name)
+                self.project = sess.graph.get_tensor_by_name(signature_def[signature_key].inputs['project'].name)
+                self.product = sess.graph.get_tensor_by_name(signature_def[signature_key].inputs['product'].name)
+                self.outputs = sess.graph.get_tensor_by_name(signature_def[signature_key].outputs['outputs'].name)
+
+    def text2array(self, text, tenderee='', maxSententLen=20):
+        tenderee = tenderee.replace('(', '(').replace(')', ')')
+        text = text.replace('(', '(').replace(')', ')')
+        text = re.sub(
+            '(废标|终止|综?合?评审|评标|开标|资审|履约|验收|成交|中标人?|中选人?|单一来源|合同|候选人|结果|变更|更正|答疑|澄清|意向|需求|采购|招标|询比?价|磋商|谈判|比选|比价|竞价|议价)的?(公告|预告|公示)?|关于为?|选取|定点|直接|邀请函?|通知书?|备案|公开|公示|公告|记录|竞争性',
+            '', text)
+        text = text.replace(tenderee, '')
+        text = ' ' if text=="" else text
+        words_docs_list = fool.cut(text)
+        words_docs_list = [[it for it in l if re.search('^[\u4e00-\u9fa5]+$', it)][-maxSententLen:] for l in words_docs_list]
+        array = embedding(words_docs_list, shape=(len(words_docs_list), maxSententLen, 128))
+        return array
+
+    def process(self, title, project, product, tenderee):
+        return self.text2array(title, tenderee), self.text2array(project, tenderee), self.text2array(product)
+
+    def predict_model(self, title, project, product, tenderee=''):
+        title_array, project_array, product_array = self.process(title, project, product, tenderee)
+        rs = self.sess.run(self.outputs,
+                           feed_dict={
+                               self.title:title_array,
+                               self.project:project_array,
+                               self.product:product_array
+                            }
+                           )
+        pred = np.argmax(rs[0])
+        return self.id2lb[pred], rs[0][pred]
+        # # 返回top2 结果
+        # pred_list = np.argsort(-rs[0])
+        # return self.id2lb[pred_list[0]], self.id2lb[pred_list[1]], rs[0][pred_list[0]], rs[0][pred_list[1]]
+
+    def predict_rule(self, doctitle, tenderee, win_tenderer, project_name, product):
+        doctitle = doctitle if doctitle else ''
+        tenderee = tenderee if tenderee else ''
+        win_tenderer = win_tenderer if win_tenderer else ''
+        project_name = project_name if project_name else ''
+        product = product if product else ''
+
+        text_ind = (doctitle + project_name + product).replace(tenderee, '')
+        text_com = win_tenderer
+
+        length_ind_text = len(text_ind) + 1
+        length_com_text = len(text_com) + 1
+        # print(text)
+
+        dic_res = {}  # 行业分类字典
+        score_lst = []  # 得分列表
+        word_lst = []  # 关键词列表
+
+        # 主要内容关键词
+        if text_ind:
+            # logging.info("data_ind%s"%str(_json_data_industry[0]))
+            for data_industry in self.json_data_industry:
+                industry = data_industry['xiaolei']
+                key_word = data_industry['key_word']
+                key_word_2 = data_industry['key_word2']
+                power = float(data_industry['power']) if data_industry['power'] else 0
+                this_score = power * (text_ind.count(key_word) * len(key_word) / length_ind_text)
+
+                if key_word_2:
+                    # key_word_compose = key_word + "+" + key_word_2
+                    if text_ind.count(key_word_2) == 0:
+                        this_score = 0
+
+                if this_score > 0:
+                    # print(industry,key_word,this_score)
+                    if industry in dic_res.keys():
+                        dic_res[industry] += this_score
+                    else:
+                        dic_res[industry] = this_score
+
+                    if key_word not in word_lst:
+                        word_lst.append(key_word)
+
+        # 供应商关键词
+        if text_com:
+
+            for data_company in self.json_data_company:
+                industry = data_company['industry_type']
+                key_word = data_company['company_word']
+                power = float(data_company['industry_rate']) if data_company['industry_rate'] else 0
+                this_score = power * (text_com.count(key_word) * len(key_word) / length_com_text)
+
+                if this_score > 0:
+                    # print(industry,key_word,this_score)
+                    if industry in dic_res.keys():
+                        dic_res[industry] += this_score
+                    else:
+                        dic_res[industry] = this_score
+
+                    if key_word not in word_lst:
+                        word_lst.append(key_word)
+
+        # 自定义关键词
+        if text_ind:
+
+            custom_ind = [
+                ['tenderee', '医院|疾病预防', ['设备', '系统', '器'], '医疗设备'],
+                ['tenderee', '学校|大学|小学|中学|学院|幼儿园', ['设备', '器'], '教育设备'],
+                ['tenderee', '学校|大学|小学|中学|学院|幼儿园|医院', ['工程'], '科研、医疗、教育用房'],
+                ['tenderee', '供电局|电网|国网|电力|电厂|粤电', ['设备', '器', '物资'], '电力工业专用设备'],
+                ['tenderee', '公安|法院|检察院', ['设备', '器'], '政法、检测专用设备'],
+                ['tenderee', '^中铁|^中交|^中建|中国建筑', ['材料'], '其他建筑建材'],
+                ['doctextcon', '信息技术服务|系统开发|信息化|信息系统', ['监理'], '信息技术咨询服务'],
+                ['doctextcon', '工程', ['消防'], '专业施工'],
+                ['doctextcon', '铁路|航空|船舶|航天|广铁', ['维修'], '铁路、船舶、航空航天等运输设备修理'],
+                ['doctextcon', '设备|仪|器', ['租赁'], '机械设备经营租赁'],
+                ['doctextcon', '交通|铁路|公路|道路|桥梁', ['工程'], '铁路、道路、隧道和桥梁工程建筑'],
+                ['win_tenderer', '电力', ['设备', '器'], '电力工业专用设备'],
+                ['win_tenderer', '信息|网络科技', ['系统'], '信息系统集成和物联网技术服务'],
+                ['tenderee,doctextcon', '铁路|广铁|铁道', ['设备', '器', '物资', '材料', '铁路'], '铁路运输设备'],
+            ]
+
+            for data_custom in self.json_data_custom:
+                industry_custom = data_custom['industry']
+                key_word = data_custom['company_word']
+                power = float(data_custom['industry_rate'])
+                for k in range(len(custom_ind)):
+                    subject = ''
+                    if 'tenderee' in custom_ind[k][0]:
+                        subject += tenderee
+                    if 'win_tenderer' in custom_ind[k][0]:
+                        subject += win_tenderer
+                    if 'doctextcon' in custom_ind[k][0]:
+                        subject += text_ind
+
+                    ptn = custom_ind[k][1]
+                    # print('ptn',ptn)
+                    if re.search(ptn, subject) and industry_custom in custom_ind[k][2]:
+                        industry = custom_ind[k][3]
+                    else:
+                        continue
+
+                    this_score = power * (text_ind.count(key_word) * len(key_word) / len(subject))
+
+                    if this_score > 0:
+                        # print(industry,key_word,this_score)
+                        if industry in dic_res.keys():
+                            dic_res[industry] += this_score
+                        else:
+                            dic_res[industry] = this_score
+
+                        if key_word not in word_lst:
+                            word_lst.append(key_word)
+        sort_res = sorted(dic_res.items(), key=lambda x: x[1], reverse=True)
+        lst_res = [s[0] for s in sort_res]
+        score_lst = [str(round(float(s[1]), 2)) for s in sort_res]
+        if len(lst_res) > 0:
+            return lst_res, score_lst, word_lst
+        else:
+            return [""], [], []
+
+    def predict_merge(self, pinmu_type, industry_lst):
+        '''
+        通过一系列规则最终决定使用模型还是规则的结果
+        :param pinmu_type: 模型预测类别
+        :param industry_lst: 规则预测类别列表
+        :return:
+        '''
+        industry_type = industry_lst[0]
+        if industry_type == "":
+            return pinmu_type
+        if industry_type == '专用设备修理' and re.search('修理|维修|装修|修缮', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '其他土木工程建筑' and re.search('工程|建筑|用房|施工|安装|质检|其他专业咨询与调查', pinmu_type):
+            final_type = pinmu_type
+        elif pinmu_type == '专用设备修理' and re.search('工程|修理', industry_type):
+            final_type = industry_type
+        elif pinmu_type == '信息系统集成和物联网技术服务' and re.search('卫星传输|信息处理和存储支持服务|信息技术咨询服务|运行维护服务|其他专业技术服务|医疗设备|医药品',
+                                                          industry_type):
+            final_type = industry_type
+        elif industry_type == '仪器仪表' and re.search('仪器|器具|医疗设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '医药品' and re.search('医疗设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '医药品' and re.search('医疗设备', pinmu_type):
+            final_type = pinmu_type
+        elif re.search('设备', industry_type) and re.search('修理|维修', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '社会工作' and re.search('工程', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '信息系统集成和物联网技术服务' and re.search('信息处理|设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '研究和试验发展' and re.search('其他专业咨询与调查|质检技术服务|信息系统集成|其他工程服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '其他专业咨询与调查' and re.search('工程造价服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '广告业' and re.search('印刷服务|影视节目制作|信息系统', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '清洁服务' and re.search('工程|环境污染防治设备|修理', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '其他公共设施管理' and re.search('信息系统', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '其他专业技术服务' and re.search('工程技术与设计服务|质检技术服务|环境与生态监测检测服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '机械设备经营租赁' and re.search('电信', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '货币金融服务' and re.search('信息系统集成和物联网技术服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '体育场地设施管理' and re.search('体育设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '安全保护服务' and re.search('信息系统|监控设备|互联网安全服务', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '互联网接入及相关服务' and re.search('通信设备', pinmu_type):
+            final_type = pinmu_type
+        elif industry_type == '卫生' and re.search('医疗设备|信息系统', pinmu_type):
+            final_type = pinmu_type
+        elif pinmu_type == '研究和试验发展' and re.search('其他工程服务', industry_type):
+            final_type = industry_type
+        elif pinmu_type == '办公设备' and re.search('教育设备', industry_type):
+            final_type = industry_type
+        elif re.search('车辆|机械设备经营租赁', pinmu_type) and re.search('公路旅客运输', industry_type):
+            final_type = industry_type
+        elif len(industry_lst) > 1 and pinmu_type == industry_lst[1] and re.search('会计|法律|物业|家具|印刷|互联网安全',
+                                                                                   industry_type) == None \
+                and re.search('其他|人力资源服务', pinmu_type) == None:
+            final_type = pinmu_type
+        elif industry_type != "":
+            final_type = industry_type
+        else:
+            final_type = pinmu_type
+        return final_type
+
+    def predict(self, title, project, product, tenderee="", win_tenderer=""):
+        result_model, prob = self.predict_model(title, project, product, tenderee)
+        industry_lst, score_lst, word_lst = self.predict_rule(title, tenderee, win_tenderer, project, product)
+        final_type = self.predict_merge(result_model, industry_lst)
+        print('模型:%s;规则:%s;最终:%s'%(result_model, industry_lst[0], final_type))
+        return final_type
+
+if __name__ == "__main__":
+    model_predictor = IndustryPredictor()
+
+    s = '自用 ( )#split#自用#split#小便池 下水 弯管 , 捷星 角磨机 钢刷 , 宽 胶带 , 玻璃胶 , 空气 清新剂 , 窄 胶带 , 柠檬 超洁 洗洁精 , 窗帘环 , 舌 锁 , 晶华 胶带 , 电池 纽扣 电池 , 免钉 胶#split#盂县 禄鑫 商贸 有限公司'
+    # s = '无锡 浩源 招投标 咨询 服务 有限公司 社会保险 相关 业务 文书 送达 服务 的#split#社会保险 相关 业务 文书 送达 服务#split#社会保险 相关 业务 文书 送达 服务 , 文书 送达 服务 , 业务 文书 送达 服务#split#中国 邮政 速递 物流 股份 有限公司 无锡市 分公司'
+    # s = '小轿车#split#小轿车#split#小轿车#split# '
+    # s = '2021年 12月 至 2022年 01月 政府#split#陆路 与 航空 口岸 疫情 防控 工作 专班 B13 栋 集中 居住 点 委托 运营 服务 项目#split#集中 居住 点 委托 运营 服务#split# '
+    # s = '广州市 越秀区 云泉路 20 号 配电 柜 更换 项目#split#广州市 越秀区 云泉路 20 号 配电 柜 更换 项目#split#配电 柜 更换#split# '
+    title, project, product, win_tenderer = s.replace(' ', '').split('#split#')
+
+    print(model_predictor.predict(title, project, product, tenderee="", win_tenderer=win_tenderer))
+    print()
+
+
+
+
+

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
BiddingKG/dl_dev/industry/rule_kw_json/tw_company_classification_keyword/tw_company_classification_keyword.json


+ 1 - 0
BiddingKG/dl_dev/industry/rule_kw_json/tw_custom_keyword/tw_custom_keyword.json

@@ -0,0 +1 @@
+[{"id": 1, "industry": "\u7cfb\u7edf", "industry_rate": "0.1", "company_word": "\u7cfb\u7edf"}, {"id": 2, "industry": "\u8bbe\u5907", "industry_rate": "0.1", "company_word": "\u8bbe\u5907"}, {"id": 3, "industry": "\u8bbe\u5907", "industry_rate": "0.1", "company_word": "\u88c5\u5907"}, {"id": 4, "industry": "\u8bbe\u5907", "industry_rate": "0.1", "company_word": "\u88c5\u7f6e"}, {"id": 5, "industry": "\u5668", "industry_rate": "0.2", "company_word": "\u5668"}, {"id": 6, "industry": "\u5668", "industry_rate": "0.2", "company_word": "\u4eea"}, {"id": 7, "industry": "\u5668", "industry_rate": "0.2", "company_word": "\u673a"}, {"id": 8, "industry": "\u7269\u8d44", "industry_rate": "0.2", "company_word": "\u7269\u8d44"}, {"id": 9, "industry": "\u7269\u8d44", "industry_rate": "0.2", "company_word": "\u8f85\u6750"}, {"id": 10, "industry": "\u6d88\u9632", "industry_rate": "5.0", "company_word": "\u6d88\u9632"}, {"id": 11, "industry": "\u5de5\u7a0b", "industry_rate": "0.1", "company_word": "\u5de5\u7a0b"}, {"id": 12, "industry": "\u5de5\u7a0b", "industry_rate": "0.1", "company_word": "\u65bd\u5de5"}, {"id": 13, "industry": "\u5de5\u7a0b", "industry_rate": "0.5", "company_word": "\u7528\u623f"}, {"id": 14, "industry": "\u5de5\u7a0b", "industry_rate": "0.1", "company_word": "\u5927\u697c"}, {"id": 15, "industry": "\u5de5\u7a0b", "industry_rate": "1.0", "company_word": "\u65b0\u5efa"}, {"id": 16, "industry": "\u76d1\u7406", "industry_rate": "5.0", "company_word": "\u76d1\u7406"}, {"id": 17, "industry": "\u79df\u8d41", "industry_rate": "5.0", "company_word": "\u79df\u8d41"}, {"id": 18, "industry": "\u6750\u6599", "industry_rate": "5.0", "company_word": "\u6750\u6599"}, {"id": 19, "industry": "\u7ef4\u4fee", "industry_rate": "5.0", "company_word": "\u7ef4\u4fee"}, {"id": 20, "industry": "\u94c1\u8def", "industry_rate": "5.0", "company_word": "\u94c1\u8def"}, {"id": 21, "industry": "\u7ef4\u4fee", "industry_rate": "6.0", "company_word": "\u4fee\u7406"}]

Tiedoston diff-näkymää rajattu, sillä se on liian suuri
+ 0 - 0
BiddingKG/dl_dev/industry/rule_kw_json/tw_industry_keyword_org/tw_industry_keyword_org.json


Kaikkia tiedostoja ei voida näyttää, sillä liian monta tiedostoa muuttui tässä diffissä