SequenceMathcer地址相似性计算

文摘   教育   2024-07-14 12:05   广东  
在反欺诈领域,如果存在相同或相近地址异常批量进件,则有可能出现了批量欺诈。

所以在风险防控中,可以通过计算地址相似程度设置相应规则来防范该情况。

基于不同地址相似性原理得出的地址相似程度,可能在值上有差异。

本文介绍基于SequenceMathcer计算地址相似性。

本文目录
  1. SequenceMathcer参数详解

  2. SequenceMathcer主要方法

  3. SequenceMathcer实例

  4. 先去掉停用词再计算相似性

  5. 批量计算地址相似性


一、SequenceMathcer参数详解

SequenceMatcher是Python标准库difflib中的一个类,用于比较两个序列(如字符串或列表)的相似性和差异。

SequenceMatcher(isjunk=None, a='', b='', autojunk=True)

参数详解:

isjunk:可选函数,指定哪些元素在比较时应该忽略。默认为None,即不忽略任何元素。

a='', b='':要比较的两个序列,可以是任何可迭代的对象,最常见的是字符串和列表。

autojunk:布尔值,指定是否自动将某些常见的垃圾元素视为不重要,默认值True。


二、SequenceMathcer主要方法

SequenceMathcer类提供了多个方法来分析和比较序列:

1.ration():计算所有匹配片段的长度之和T,然后计算2*T/(len(a)+len(b)),得到两个序列之间的相似度,范围在0到1之间,越接近1表示越相似。

2.quick_ratio():返回两个序列之间的快速估计相似度,比ratio方法更快但可能更不准确。

3.get_matching_blocks():返回一个列表,包含两个序列中最长匹配子序列的信息,每个元素是一个元组(i, j, n),表示第一个序列中从索引i开始长度为n的子序列与第二个序列中从索引j开始长度为n的子序列完全匹配。

4.get_opcodes():返回一个列表,包含了将第一个序列转换为第二个序列所需的操作,每个元素是一个元组(tag, i1, i2, j1, j2),表示对第一个序列中从索引i1到索引i2的子序列执行操作tag后,它将与第二个序列中从索引j1到索引j2(不包括)的子序列相等。操作有以下几种:

①'equal':表示两个子序列相等,无需修改,即a[i1:i2]和b[j1:j2]相同。

②'replace':表示需要将第一个子序列替换为第二个子序列,即a[i1:i2]能被b[j1:j2]替换。

③'delete':表示需要删除第一个子序列,即a[i1:i2]需被删除,此时j1==j2。

④'insert':表示需要在第一个子序列后插入第二个子序列。

⑤'noop':表示无操作。


三、SequenceMathcer实例

首先使用普通ratio方法计算两个真实地址的相似度,代码如下:

#使用文本相似度算法计算相似度from difflib import SequenceMatcher
address1 = '广东湛江霞山绿塘边坡村西路8号'address2 = '广东省湛江市霞山区霞山开发区绿华路28号'#计算相似度similarity_ratio = SequenceMatcher(None, address1, address2).ratio()print(similarity_ratio)
得到结果:
0.5714285714285714

接着使用quick_ratio方法计算相似度,代码如下:

SequenceMatcher(None, address1, address2).quick_ratio()

得到结果:

0.5714285714285714

可以发现该结果和ratio方法结果一致。

接着使用get_matching_blocks方法依次获取最长的相同段,代码如下:

SequenceMatcher(None, address1, address2).get_matching_blocks()

得到结果:

[Match(a=0, b=0, size=2), Match(a=2, b=3, size=2), Match(a=4, b=6, size=2), Match(a=6, b=14, size=1), Match(a=12, b=16, size=1), Match(a=13, b=18, size=2), Match(a=15, b=20, size=0)]

表示address1从位置0开始长度为2的字段和address2从位置0开始长度为2的字段相同,即广东这个词都在两个地址最开始的位置。其余的相同字段找寻方法类似。

从size中知,总计相同的字段量为10,直接运用公式计算两个字段的相似度,代码如下:

2*10/(len(address1) + len(address2))

得到结果:

0.5714285714285714

可以发现和ratio方法计算结果一致。

最后我们来看下get_opcodes方法,代码如下:

SequenceMatcher(None, address1, address2).get_opcodes()

得到结果:

[('equal', 0, 2, 0, 2), ('insert', 2, 2, 2, 3), ('equal', 2, 4, 3, 5), ('insert', 4, 4, 5, 6), ('equal', 4, 6, 6, 8), ('insert', 6, 6, 8, 14), ('equal', 6, 7, 14, 15), ('replace', 7, 12, 15, 16), ('equal', 12, 13, 16, 17), ('insert', 13, 13, 17, 18), ('equal', 13, 15, 18, 20)]

可以得到相同,需要替换等字段信息。


四、先去掉停用词再计算相似性

如果地址比较规范,都含有省、市、区类似的字段,则无需进行该模块的内容。

如果部分地址含了省、市、区类似字段,部分地址不含,则建议先去除停用词,再计算相似性。

首先去除地址中的停用词,代码如下:

import jieba 
address1 = '广东省湛江市霞山区绿塘边坡村西路8号'address2 = '广东省湛江市霞山区霞山开发区绿华路28号'def addr_rep(address): #定义去除的停用词,可根据需要添加 rep_wd = ['省', '市', '区', '县', '街道', ' ', '附近', '方向', '巷子', '号'] for i in rep_wd: address = address.replace(i, '') return address address1 = addr_rep(address1)address2 = addr_rep(address2)#去除地址中的停用词cut_address1 = "/".join(jieba.cut(address1, cut_all=False)) #用jieba分词器把地址字符分成一个一个的词cut_address2 = "/".join(jieba.cut(address2, cut_all=False)) #用jieba分词器把地址字符分成一个一个的词print(cut_address1)print(cut_address2)

得到结果:

广东/湛江/霞山/绿/塘边/坡村/西路/8广东/湛江/霞山/霞山/开发/绿华路/28
可以发现,去除了省、市、区等字段。接着计算去除停用词后的地址相似性,代码如下:
cut_address1 = cut_address1.replace('/', '')cut_address2 = cut_address2.replace('/', '')#计算相似度similarity_ratio = SequenceMatcher(None, cut_address1, cut_address2).ratio()print(similarity_ratio)

得到结果:

0.6206896551724138

可以发现一样的地址,去除停用词后地址相似性有了提高。


五、批量计算地址相似性

首先导入深交所上市公司的地址信息,代码如下:

import osimport pandas as pd  
os.chdir(r'F:\公众号\101_地址相似性')date = pd.read_excel('创业板.xlsx', sheet_name='创业板')date.head(2)

得到结果:

注:如需数据,可到“阿黎逸阳的代码”公众号中回复“创业板“获取

看下数据框的大小,即地址的个数,代码如下:

date.shape

得到结果:

(814, 20)

即有814个地址。

接着定义去除停用词后两个地址的相关性,代码如下:

#定义去除停用词的函数def simi_fun(address1, address2):    import jieba 
address1 = address1 address2 = address2 def addr_rep(address): #定义去除的停用词,可根据需要添加 rep_wd = ['省', '市', '区', '县', '街道', ' ', '附近', '方向', '巷子', '号'] for i in rep_wd: address = address.replace(i, '') return address address1 = addr_rep(address1) address2 = addr_rep(address2) #去除地址中的停用词 cut_address1 = "/".join(jieba.cut(address1, cut_all=False)) #用jieba分词器把地址字符分成一个一个的词 cut_address2 = "/".join(jieba.cut(address2, cut_all=False)) #用jieba分词器把地址字符分成一个一个的词 cut_address1 = cut_address1.replace('/', '') cut_address2 = cut_address2.replace('/', '') #计算相似度 similarity_ratio = SequenceMatcher(None, cut_address1, cut_address2).ratio() return similarity_ratio

然后写循环批量计算两两地址之间的相关性,代码如下:

name = []ratio = []for i in range(len(date)):    name.append(date['注册地址'][i])    #记录计算相关性变量的名称    sub_ratio = []    for j in range(len(date)):        simi_ratio = simi_fun(date['注册地址'][i], date['注册地址'][j])        sub_ratio.append(simi_ratio)    ratio.append(sub_ratio)

其中name用来记录计算相关性变量的名称,sub_ratio用来存储地址i和地址j的相关性,ratio用来存储全量地址的相关性。

接着把计算得到的结果处理成数据框,添加上对应地址信息,代码如下:

ratio_date = pd.DataFrame(ratio)ratio_date.columns = nameratio_date.index = nameratio_date.head(2)

得到结果:

最后,导出数据,代码如下:

ratio_date.to_csv('创业板_地址_ratio.csv', encoding='gbk')

得到结果:

至此,应用SequenceMathcer计算地址相关性已讲解完毕,对学习Python感兴趣的小伙伴欢迎加群讨论。
【部分群限时免费进分群讨论学习Python、玩转Python、风控建模【29.9元进】、人工智能、数据分析相关问题,还提供招聘推信息、优秀文章、学习视频、公众号文章答疑,也可交流工作中遇到的难题。如需添加微信号19967879837,加时备注想进的群,比如风控建模。
往期回顾:

一文囊括Python中的函数,持续更新。。。

一文囊括Python中的有趣案例,持续更新。。。

一文囊括Python中的数据分析与绘图,持续更新。。。

一文囊括风控模型搭建(原理+Python实现),持续更新。。。



限时免费加群

19967879837

添加微信号、手机号

阿黎逸阳的代码
阿黎逸阳,分享大数据和人工智能领域知识,提供风控建模干货经验。 博主履历:世界五百强公司、互联网上市公司、高校、外资银行,多年研究大数据分析、建模以及教学工作。
 最新文章