所以在风险防控中,可以通过计算地址相似程度设置相应规则来防范该情况。
基于不同地址相似性原理得出的地址相似程度,可能在值上有差异。
本文介绍基于SequenceMathcer计算地址相似性。
SequenceMathcer参数详解
SequenceMathcer主要方法
SequenceMathcer实例
先去掉停用词再计算相似性
批量计算地址相似性
SequenceMatcher是Python标准库difflib中的一个类,用于比较两个序列(如字符串或列表)的相似性和差异。
SequenceMatcher(isjunk=None, a='', b='', autojunk=True)
参数详解:
isjunk:可选函数,指定哪些元素在比较时应该忽略。默认为None,即不忽略任何元素。
a='', b='':要比较的两个序列,可以是任何可迭代的对象,最常见的是字符串和列表。
autojunk:布尔值,指定是否自动将某些常见的垃圾元素视为不重要,默认值True。
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 os
import 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 = name
ratio_date.index = name
ratio_date.head(2)
得到结果:
最后,导出数据,代码如下:
ratio_date.to_csv('创业板_地址_ratio.csv', encoding='gbk')
得到结果:
至此,应用SequenceMathcer计算地址相关性已讲解完毕,对学习Python感兴趣的小伙伴欢迎加群讨论。
一文囊括风控模型搭建(原理+Python实现),持续更新。。。
限时免费加群
19967879837
添加微信号、手机号