基与距离和字符串相似进行地址匹配,主要分为三部分。
数据:
业务源数据:df_s 包含业务地址、经纬度
待查找数据:df_find包含待查找地点地址、经纬度
1、计算业务源地址的经纬度与待查找地址经纬度的距离,进行初筛。
2、对df_s字符串和df_find字符串进行处理,为字符串相似做准备。
2.1.通过cpca库进行地址分词,去除省市信息仅保留最少地址信息。
2.2.通过正则去除字符串的特殊字符,仅保留字母、数字、汉字。
3、通过字符串相似算法,计算df_s和df_find的相似性。
一、计算距离
参考下面文章
https://blog.csdn.net/A41915460/article/details/128065351
二、字符串处理
地址分词主要使用cpca库,注意库有一个Bug,当地址里面省、市、区三级信息为空时会返回None而不是地址。
如:王家庄村25号使用cpca库解析地址会返回None,但是山西省王家庄村25号会返回王家庄村25号。并且当行政区重复时如山西山西省王家庄村25号也会返回王家庄村25号,利用这一特性我们再地址字符串前面统一加省份名称避免返回None(即原字符串没有行政区名称时通过我们人为增加的省份字段,库可以解析出地址;当原字符串有行政区名称时,通过我们人为增加的省份字段,虽然省份字段重复,但是库依然可以解析出地址)。
三、字符串相似度
通过编辑距离、莱文斯坦比 、jaro_winkler和包含关系计算字符串相似度。其中编辑距离和莱文斯坦比对相似的定义更严格但是容易漏检测,jaro_winkler相对宽松不容易漏检但是容易误检。因此设置门限时jaro_winkler要比莱文斯坦比高一点,利如莱文斯坦比门限时30%,可以设置jaro_winkler门限是50%。
具体判决规则为
if (
(r > r_threshold and d < d_threshold)
or (l != "无")
or j_r > j_threshold
or 源地址和查询地址距离<=50):
判断为True
##四、整体代码
# -*- coding : utf-8-*-
import pandas as pd
import numpy as np
import warnings
warnings.filterwarnings("ignore")
import time
from numba import njit
from numpy import radians, sin, cos, arcsin, sqrt
from rtree import index
from functools import lru_cache
import re
import Levenshtein
import cpca
from Levenshtein import jaro_winkler
############字符串相似度计算相关函数##############
def baoliuhanzhi(sr):
# 仅仅保留汉字
res_tr1 = '[^\u4e00-\u9fa5]+'
# 仅仅保留汉字、数字和字母,但是去除不掉^
re_str2 = "[^\u4e00-\u9fa5^a-z^A-Z^0-9]+"
sr1 = re.sub(res_tr1, '', sr)
sr2 = re.sub(re_str2, "", sr)
return sr2
# 计算编辑距离
def L_distance(str1, str2):
d = Levenshtein.distance(str1, str2)
return d
# 计算jaro_winkler相似度
def J_radio(str1, str2):
j = jaro_winkler(str1, str2)
return j
# 计算莱文斯坦比。计算公式 r = (sum – ldist) / sum, 其中sum是指str1 和 str2 字串的长度总和,ldist是类编辑距离。注意这里是类编辑距离,在类编辑距离中删除、插入依然+1,但是替换+2。
def L_ratio(str1, str2):
r = Levenshtein.ratio(str1, str2)
return r
def L_in(str1, str2):
st = "无"
n = len(str1) * len(str2)
if n > 0:
if str1 in str2:
st = "A in B"