正如题目中说的一样,这个程序的目的是实现公司名及公司地址的模糊匹配,也可以迁移到房产信息、电话号码之类的字段上。本来的应用场景是反团伙欺诈以及失联客户的修复,大概的意思就是说多个相同公司的同事都在我公司借贷的欺诈可能性要高于其他客户,以及造假的房产信息和电话号码可能不完全相同,但有一定的相似性,我们需要把这些客户找出来,但是又不能用精确匹配。因为存在问题的房产信息和电话可能只是相似,而不是完全相同;对于公司名和地址来说,就更糟糕一些,即使是真实的信息,但同一个公司的叫法可能会多种多样,如果麻烦一些,还要建一个同义词库。而我们做的工作还没有那么全面,只是提取出了公司名中的关键词。

而做评分卡模型也需要用到这个思想。因为评分卡的其中一个字段就是所在城市等级,这就需要从原始数据的地址中提取出城市信息,但地址的格式又不够标准,因为信息是客户人工填写的,举个例子,“山东省济南市”也有可能被写成“山东济南”,所以一个正则表达式就不足以解决这个字段提取的问题了。


总结一下,模糊匹配的两个应用场景:
1)构建反欺诈知识图谱
2)评分卡提取所需字段


地址处理的基本思路就是建立一个标准库,对地址逐个进行对比,再返回结果和置信度,所以词库的建立是地址处理的关键。


下面是解决问题的过程:


第一步,希望可以提取出公司名中的关键字。首先,要分析一下数据库中公司名的形式:“浙江杭州立多林贸易有限公司”,“汇川区万全兄弟购物中心”,“温州雪龙集团有限公司北京销售分公司”……
经过分析,可以看出,公司名大致分为3个部分:1、省市区名称;2、关键词+公司属性;3、分公司或分局等信息。

首先,需要使用python连接到数据库,取出公司名字段:
1、下载并安装psycopg2模块,下载链接如下:
http://www.stickpeople.com/projects/python/win-psycopg/
安装完毕后,输入下面语句,连接数据库:

import psycopg2
#录入数据
conn=psycopg2.connect(database="testdb", user="postgres", password="postgres", host="10.180.157.168", port="1975")
cur=conn.cursor()
needinfo=['brhs_unitname','dict_unit_province','dict_unit_city','dict_unit_arer','brhs_unit_address']
cur.execute("SELECT brhs_unitname,dict_unit_province,dict_unit_city,dict_unit_arer,brhs_unit_address FROM aaa_t_jk_dhzh_brhs limit 1000;")
selects=cur.fetchall()
enterprise_datas=pd.DataFrame(selects,columns=needinfo)

2、根据上面的分析,下一步就要先将省市区提取出来。提取省市区的常规做法是建立行政区划库,类似于jieba分词中的txt词典。在解决这个问题时,我和同事两个人的思路不尽相同。在使用jieba对公司名进行分词后,一种思路是建立一个最简词库,词库中的词都是行政区划的最简称,例如“宁夏”、“内蒙古”等,如果字典中的词在分词中,则取出该分词;另一种思路是,使用全称词库,例如“宁夏回族自治区”、“内蒙古自治区”等,如果分词后的词可以和其完全匹配,则取出该分词,否则,按照一定的规则,将字典中的词去掉“省”、“市”、“自治区”后,再和分词进行匹配。经过讨论,最后,行政区划库的形式如下图所示:

region_nosuffix region_suffix city_nosuffix city_suffix province_nosuffix province_suffix
东城 东城区 北京直辖区 北京直辖区 北京 北京市
西城 西城区 北京直辖区 北京直辖区 北京 北京市
朝阳 朝阳区 北京直辖区 北京直辖区 北京 北京市

3、使用python建立词典,分别建立以下几个词典:

#建立字典
district=pd.read_excel('~\district_new_nosuffix.xlsx',sheetname='slice').fillna('')
##建立pcr字典
district_dict_pcr=defaultdict(lambda:defaultdict(lambda:defaultdict(int)))
for num in range(len(district)):district_dict_pcr[district.ix[num,'province_nosuffix']][district.ix[num,'city_nosuffix']][district.ix[num,'region_nosuffix']]=district.ix[num,'region_code']
district_dict_pcr=dict(district_dict_pcr)
##建立rcp字典
district_dict_rcp=defaultdict(list)
for num in range(len(district)):district_dict_rcp[district.ix[num,'region_nosuffix']].extend([district.ix[num,'province_suffix'],district.ix[num,'city_suffix'],district.ix[num,'region_suffix']])
district_dict_rcp=dict(district_dict_rcp)
##建立cp字典
district_dict_cp=defaultdict(list)
for num in range(len(district)):if district_dict_cp[district.ix[num,'city_nosuffix']]==[]:district_dict_cp[district.ix[num,'city_nosuffix']].extend([district.ix[num,'province_suffix'],district.ix[num,'city_suffix']])
district_dict_cp=dict(district_dict_cp)
##建立pp字典
district_dict_pp=defaultdict(str)
for num in range(len(district)):district_dict_pp[district.ix[num,'province_nosuffix']]=district.ix[num,'province_suffix']
district_dict_pp=dict(district_dict_pp)

4、使用分词包对公司名进行分词,并标出词性
显然,需要提取出行政区,我们需要词性为ns的词,但分词后发现,Jieba自带的词典中,我们需要的省市区的词性并非全部为ns,而其他词,如“大望路”等我们不需要的词却可能为”ns”,于是,需要创建专用分词词典,并标注其词性为ns,替换默认的词典。

def word_flag(words):'''提取flag是u'ns'的word'''result=defaultdict(list)output=pseg.cut(words)for word,flag in output:result[flag].append(word)return result[u'ns']

5、提取出三级行政区划
前面已经提到过,由于书写的不规范,导致同一个行政区划,写法可能不同。例如,“山西省太原市小店区”,既有可能被写成“山西太原小店区”,也有可能被写成“太原市小店区”,还可能直接被写成“小店区”,所以,提取时,要分多种情况:

def geo_checker(word):'''验证word'''if len(word)>2:if (u'省' in word or u'自治区' in word):word=word.replace(u'省','').replace(u'自治区','')try:district_dict_pcr[word]return district_dict_pp[word]except KeyError:return u'未知省份'elif (u'地区' in word or u'自治州' in word or u'盟' in word):word=word.replace(u'地区','').replace(u'自治州','').replace(u'盟','')try:district_dict_cp[word]return district_dict_cp[word]except KeyError:return u'未知城市'                      elif (u'自治县' in word or u'矿区' in word or u'自治旗' in word):word=word.replace(u'自治县','').replace(u'矿区','').replace(u'自治旗','')try:district_dict_rcp[word]return district_dict_rcp[word]except KeyError:return u'未知区县' elif u'县' in word :word=word.replace(u'县','')try:district_dict_rcp[word]return district_dict_rcp[word]except KeyError:return u'未知区县'             elif u'市' in word:if (u'天津' in word or u'北京' in word or u'重庆' in word or u'上海' in word):word=word.replace(u'市','')try:district_dict_pcr[word]return district_dict_pp[word]except KeyError:return u'未知省份'if u'区' in word:word=word.replace(u'区','')try:district_dict_rcp[word]return district_dict_rcp[word]except KeyError:return u'未知区县'word=word.replace(u'市','')try:district_dict_cp[word]return district_dict_cp[word]except KeyError:try:district_dict_rcp[word]return district_dict_rcp[word]except KeyError:return u'未知城市或区县'elif u'区' in word:word=word.replace(u'区','')try:district_dict_cp[word]return district_dict_cp[word]except KeyError:try:district_dict_rcp[word]return district_dict_rcp[word]except KeyError:return u'未知城市或区县'else:try:district_dict_pcr[word]return district_dict_pp[word]except KeyError:try:district_dict_cp[word]return district_dict_cp[word]except KeyError:try:district_dict_rcp[word]return district_dict_rcp[word]except KeyError:return u'未知地理信息'else:if (u'市' in word or u'区' in word):word=word.replace(u'市','').replace(u'区','')try:district_dict_rcp[word]return district_dict_rcp[word]except KeyError:try:district_dict_cp[word]return district_dict_cp[word]except KeyError:return u'未知城市或区县'else:try:district_dict_pcr[word]return district_dict_pp[word]except KeyError:try:district_dict_cp[word]return district_dict_cp[word]except KeyError:try:district_dict_rcp[word]return district_dict_rcp[word]except KeyError:return u'未知地理信息'
def type_checker(x):if type(x)==list:return 1else:return 0def geo_standard(geo_list):for i in range(len(geo_list)):geo_list[i]=geo_checker(geo_list[i])geo_result=[x for x in geo_list if u'未知' not in x]geo_result_type=[type_checker(x) for x in geo_result]if sum(geo_result_type)>0:geo_result=geo_result[:geo_result_type.index(1)+1]return geo_resultdef geo_match(geo_result):for info in range(1,len(geo_result)):if not re.match(geo_result[info-1],geo_result[info]):return ''return 'Match'def geo_validate(geo_result):if geo_result==[]:return u'缺失地理信息'elif type(geo_result[-1])!=list:if len(geo_result)>1:for info in range(1,len(geo_result)):if not geo_match(geo_result):return u'无效地理信息'return geo_result[-1]else:if len(geo_result)==1:     return ','.join(geo_result[-1])else:for choice in range(len(geo_result[-1])):possible=geo_result[:-1]possible.append(geo_result[-1][choice])if not geo_match(possible):continuereturn possible[-1]return u'无效地理信息'def geo_guarder(geo_result):geo_result=geo_result.replace(u'北京直辖区','').replace(u'天津直辖区','').replace(u'上海直辖区','').replace(u'重庆直辖区','').replace(u'海南直辖区','').replace(u'湖北直辖区','')return geo_result#名称中的地理信息处理完毕
un_geo=unit_name.map(geo_substitute).map(word_flag).map(geo_standard).map(geo_validate).map(geo_guarder)

6、接下来,提取分公司信息

#划分名称中的组织架构
def branch(unit_name):'''检测分支机构信息'''pattern=[u'公司(.+?)(分公司)',u'局(.+?)(分局)',u'站(.+?)(分站)',u'社(.+?)(分社)',u'公司(.+?)(分行)',u'小学(.+?)(分校)',u'大学(.+?)(分校)',u'高中(.+?)(分校)']#unit_name=unit_name.decode('utf8')formation=defaultdict(str)for choice in range(len(pattern)):reg=re.search(pattern[choice],unit_name)try:formation['parent']=unit_name[:reg.start(1)]formation['branch']=unit_name[reg.start(1):reg.end(2)]formation['section']=unit_name[reg.end(2):]return formationexcept:continueformation['parent']=unit_namereturn formation

7、接下来,就是提取关键字信息
这也是所有步骤中比较困难的一点,主要的问题在于,需要新建行业词典。
下面是去掉行政区划以及分公司后,几个公司名的例子:
后英经贸有限公司
卫强餐饮有限公司
品展装潢有限公司
泰广兴空分设备配件有限公司
宇楠贸易有限公司
金路新力商贸有限公司
旭攀贸易有限公司
元东刀具厂
湛江霞山海明炉料商行
北铭钢铁有限公司
三达化学有限公司
友祚木业有限公司
雨竹广告有限公司
蒂暖实业有限公司
传银五金厂
盛师傅藤器厂
经过分析,公司名称大致可分为2种情况,1、后缀为“有限公司”、“责任有限个公司”、“有限责任公司”、“公司”;2、后缀名为“玩具厂”、“小卖部”、“化工厂”等。
所以,需要新建两个行业词典,其数据来源为公司购买的千万级法人库公司名称与地址,由于数据量较大,需要使用kattle将其导入数据库中进行操作。从所有公司名称中选出后缀为“有限公司”的名称,去掉这四个字的后缀后,分别截取倒数2个,3个,4个……字符,并按照其出现频率排序,然后,通过人工,按照字符串由多到少的顺序选取行业属性,其原因为,例如,假设“文化传播”在四个字符中出现的频率较高,有可能“化传播”在三个字符的时候,频率也较高,所以要先选出较长的字符串,然后手动删除掉较短字符串中,虽然频率较高,但并非一个词的字符串。得到的行业属性如下:
安全防范技术
安全防范技术服务
安装
安装工程
百货
办公设备
包装
包装制品
保洁
保洁服务
泵业
宾馆
玻璃
材料
材料销售
财务顾问
财务咨询
财务咨询服务
餐饮
餐饮服务
餐饮管理
仓储
测绘
策划
茶叶
产品
产品销售
同理,构造企业属性词库:
技术服务部
汽车修理站
配件经营部
营销服务部
机械配件厂
汽车运输队
建筑工程队
证券营业部
汽车维护厂
工会委员会
金属结构厂
金属加工厂
物资经销处
安装工程处
汽车维修站
技术开发部
这样我们就从企业名中剔除了属性,留下关键词,可以进行公司名称的模糊匹配了。
当然,对于部分公司,可能还存在别称,这就需要建立同义词库,这里暂时不讨论。

第二部分,是公司地址的模糊匹配。相对于公司名,地址的模糊匹配较简单。
斗篷山路317号灵智广场
马家工业园C幢4号
马家工业园C幢4号
鸳鸯路8号海阔天空二期1-5-3
高坪镇宏发路30号
之江路934号
滨湖路明湖花园1-4号
花荄五路口文苑路东段203号
渝南大道19号铠恩国际A馆1022B
小吕乡刘坡村
马坊乡钦桥村
珍溪镇滴水村六社
万象城一期A座底商A-1002
朱槿路11号柬埔寨园区5号楼2单元602号
之江路934号
生产物资市场11栋33号
东肖镇东肖南路15号
经过分析,得出公司地址的全称通常使用四级、五级、六级行政区划、某某路+数字+号+具体门牌号,故可以使用正则表达式进行提取:

unit_name=enterprise_datas['brhs_unit_address']
df = unit_name.str.extract('(.*[镇|乡|街道|街|道])?(.*[村|委员会|委会])?(.*[组])?(.*路)?(\d+号)?([\u4e00-\u9fa5]*)?(.*)?',expand=True)
df.columns = ['乡镇街道', '村','组', '道路', '门牌号', '地标名称', '其他']
writer = pd.ExcelWriter('pandas_simple.xlsx', engine='xlsxwriter')# Convert the dataframe to an XlsxWriter Excel object.
df.to_excel(writer, sheet_name='Sheet1')
writer.save()

使用Python完成公司名称和地址的模糊匹配相关推荐

  1. python 公司名称 相似度分析_使用Python完成公司名称和地址的模糊匹配

    正如题目中说的一样,这个程序的目的是实现公司名及公司地址的模糊匹配,也可以迁移到房产信息.电话号码之类的字段上.本来的应用场景是反团伙欺诈以及失联客户的修复,大概的意思就是说多个相同公司的同事都在我公 ...

  2. 菜鸟驿站是如何实现详细地址的省市区街道区分的?教你使用Python完成地址的模糊匹配

    摘要:正如题目中说的一样,这个程序的目的是地址的模糊匹配,也可以迁移到房产信息.电话号码之类的字段上.本来的应用场景是反团伙欺诈以及失联客户的修复,大概的意思就是说多个相同公司的同事都在我公司借贷的欺 ...

  3. 原 python实现模糊匹配_使用python中的fuzzywuzzy库进行模糊匹配实例

    fuzzywuzzy库是Python中的模糊匹配库,它依据 Levenshtein Distance 算法 计算两个序列之间的差异. Levenshtein Distance 算法,又叫 Edit D ...

  4. python数据模糊匹配,使用python中两个数据集的模糊匹配创建标志

    我尝试了两个df的模糊比较,就我的研究而言,没有快速的方法来做.使用4fuzz方法也会降低脚本的速度.一种方法是使用'工艺提取酮()`并创建一个函数:from fuzzywuzzy import pr ...

  5. python 模糊匹配_Case2:模糊匹配工具

    一.需求角度 1.使用情景 多组(大量,成百上千条)数据的情况下,给单个数据某一属性的非结构化录入值(尤其是文本信息,如地址等)以相应的关键词打上标签,便于后续的数据透视或相关处理. 2.使用人群 像 ...

  6. python字符串模糊匹配_NLP教程:用Fuzzywuzzy进行字符串模糊匹配

    在计算机科学中,字符串模糊匹配( fuzzy string matching)是一种近似地(而不是精确地)查找与模式匹配的字符串的技术.换句话说,字符串模糊匹配是一种搜索,即使用户拼错单词或只输入部分 ...

  7. 使用Python,OpenCV进行平滑和模糊

    使用Python,OpenCV进行平滑和模糊 1. 效果图 2. 原理 2.1 依赖库及安装 2.2 简单平均模糊 2.3 高斯模糊 2.4 中值模糊 2.5 双边滤波 3. 源代码 参考 这篇博客将 ...

  8. Python获取本地mac地址、主机名、IP地址

    1 在windows系统,命令行输入 ipconfig /all 此处获得mac地址. 2 在Python中获取mac地址 import uuid mac = uuid.UUID( int=uuid. ...

  9. Python:利用原生函数count或正则表达式compile、findall、finditer实现匹配统计(包括模糊匹配的贪婪匹配、懒惰匹配)

    Python:利用原生函数count或正则表达式compile.findall.finditer实现匹配统计(包括模糊匹配的贪婪匹配.懒惰匹配) 目录 利用原生函数count或正则表达式compile ...

最新文章

  1. python关闭读写的所有的文件-Python读写txt文本文件的操作方法全解析
  2. 算术运算符举例java_Java的算术运算符简介
  3. 计算机系职教周方案,琼软院软件〔2018〕14 号:关于印发《软件工程系2018年“职业教育 活动周”活动方案》的通知...
  4. 本地开发的 SAP UI5 应用,部署到 ABAP 服务器执行出错的问题分析
  5. [转载]android设置全屏和无标题
  6. 系统补丁自动批量安装
  7. Non-parseable POM C:\Users\admin\.m2\repository\org\springframework问题解决方案
  8. 松下plc编程软件_松下PLC编程软件Control FPWIN Pro7.3.2.0
  9. 众元教育H3CSE20200603班-云计算基础知识讲解
  10. springboot2 oauth2 jwt认证服务器和资源服务器
  11. Xcode打包ipa
  12. 网易云团队前端单元测试技术方案总结,测试人员必备知识
  13. 一个留学生眼中的匹兹堡(图)
  14. 5G千兆无线路由器,国产工业级稳定通信
  15. 时钟系统:时钟系统倍频分频配置--时钟系统分析案例
  16. 2018 10 12 校内模拟 字符串模拟+平面距离+线段树
  17. uni-app本地打包配置过程中出现的问题
  18. 十分钟掌握 “UML ” 的基本使用
  19. 中国ABS市场发展前景与投资策略建议报告2022-2028年
  20. 《rust死灵书》阅读笔记

热门文章

  1. 乐高小颗粒履带机器人_乐高履带机器人拼法 | 手游网游页游攻略大全
  2. 惠普HP Deskjet F4288 多功能一体机驱动
  3. 简单工厂模式实现加减乘除法
  4. 个人基因组测序将进入千美元费用时代
  5. 刺激战场体验服连接服务器无响应,刺激战场停服了吗 刺激战场体验服测试结束怎么回事...
  6. thinkpad机械硬盘换SSD固态硬盘的总结
  7. [跟进]_CDMA手机之母海蒂·拉玛
  8. 51单片机蓝牙遥控麦轮小车
  9. java基础及架构师面试问题
  10. Windows10桌面只有 回收站 没有我的电脑