版权声明:本文为博主原创文章,欢迎病毒式泛滥! https://blog.csdn.net/qiaokelinaicha/article/details/85317989
-
项目目标:
已有本地登记数据local-data.xlsx,需从网页填报数据web-data.xls中筛查出未填报的本地数据 -
数据特征:
- web-data.xls包含目标列“尾矿库名称”和“企业名称”,local-data.xlsx包含目标列“尾矿库名称”、“所属企业”、“尾矿库\n运行情况”
- web-data.xls数据基本格式如下:
尾矿库名称(str) | 企业名称(str) |
---|---|
(str) | (str) |
local-data.xlsx数据基本格式如下:
尾矿库名称(str) | 企业名称(str) | 尾矿库\n运行情况(str) |
---|---|---|
(str) | (str) | 在用/停用/…(str) |
- web-data.xls的“企业名称”列是“尾矿库名称”列的上级列,即某企业包含某尾矿库,local-data.xlsx的目标列“所属企业”和“尾矿库名称”存在相同关系
- 一家企业可包含多个尾矿库,企业名称不允许同名,尾矿库名称不允许同名
- web-data.xls应和local-data.xlsx中能匹配的对应条目描述基本一致,即web-data.xls的“尾矿库名称”与local-data.xlsx的“尾矿库名称”对应字符串完全相同或相似,web-data.xls的“企业名称”与local-data.xlsx的“所属企业”对应字符同上
- 在网页测试过程中手工填报了一部分条目,未及时删除,与网页发布后填报的数据重复,使web-data.xls中存在同名尾矿库或同名企业,与上文第3点数据特征相违背,此类数据应首先进行筛查处理
- local-data.xlsx中“尾矿库\n运行情况”列区分“在用”“停用”等状态,需要从中筛选出状态为“在用”的数据条目
-
思路原则:
优先匹配尾矿库名称,利用企业名称进行配合比较 -
解决方案:
- 筛查处理web-data.xls中存在同名尾矿库或同名企业
- 筛选出local-data.xlsx中“尾矿库\n运行情况”为“在用”的数据条目
- 处理干净后的web-data.xls和local-data.xlsx的条目进行逐条对比,
- 逐条对比中,先删除“尾矿库名称”字符串完全匹配条目,得到第一次对比剩余的web-data和local-data
- 第一次对比剩余的web-data和local-data中,删除“企业名称”字符串完全匹配条目,得到第二次对比剩余的web-data和local-data;此时的数据已全部去除完全同名尾矿库名称和完全同名企业名称,仅包含名称相似数据(需进一步筛除)和目标数据(即未填报的本地数据)
- 第二次对比剩余的web-data和local-data中,采用循环,对每行数据进行“尾矿库名称+企业名称”字符串最长匹配,具体如下:
- 当前行web-data 匹配目标字符串 = str(尾矿库名称) + str(企业名称)
- 当前行local-data 匹配目标字符串 = str(尾矿库名称) + str(所属企业)
- 对当前行web-data 匹配目标字符串和当前行local-data 匹配目标字符串进行len()比较,令 str_long = len()较长字符串,str_short = len()较短字符串
- 将str_short的每个字符character以“滑动窗口形式”向str_long逐个字符进行循环比较,当str_long有str_short当前character时,计数n = n + 1,且从str_long中删除该字符,滑动str_short字符窗口进行下一个循环;最后取当前web-data对当前local-data的最长匹配字符n,并计算n = float( n / len(str_short) );此处,因str_short实际为字符串列表list,所以循环当前str_short的包含字符character时为依次循环,表现为“滑动窗口形式”,且字符匹配时无需删除,而str_long虽同为字符串列表,但因其为被比较对象,若在字符匹配时不删除当前匹配字符,则进入当前str_short的下一个character循环时会重新计数,导致计数错误,所以每匹配一次character均删除当前str_long中的匹配character
- 对于每行web-data,可得到多个local-data的匹配值,取最大n值和对应local-data作为当前行web-data的匹配信息,登记入匹配字典match_dic;对于最大n值相等的情况,此处采取先出现先匹配的原则,取第一个出现的最大n值作为匹配值
- 除去第二次对比剩余的web-data和local-data中在match_dic中出现的记录,得到第三次对比剩余的web-data和local-data
- 当web-data的记录条目不为0时,进行第四次对比,参考解决方案5的思路对每行数据进行“企业名称”字符串最长匹配,得到第四次对比剩余的web-data和local-data
- web-data的记录条目为0,匹配全部完成
- 解决步骤:
- 读取数据
- 筛除完全同名“尾矿库名称”数据
- 筛除完全同名“企业名称”数据
- “尾矿库名称+企业名称”数据匹配筛除
- “企业名称”数据匹配筛除
- 输出结果
- 核心代码:
- 筛查web-data.xls中的重复数据
def getRepeatData(data_dic, tail_data, already_exist_data, i):
for (k, v) in list(data_dic.items()):
# dictionary changed size during iteration => 字典转换为集合或列表
if '-repeat' in k:
k = str(k).split('-')[0]
if tail_data == k:
already_exist_data.append([tail_data, i])
break
- 除去同名尾矿库
for (k_web,v_web) in list(data_dic_web.items()):
if k_web in data_dic_local.keys():
del data_dic_local[k_web]
del data_dic_web[k_web]
- 除去同名尾矿库后,在web剩余中先对比local查找同企业名称尾矿库
for (k_web,v_web) in list(data_dic_web.items()):
for(k_local,v_local) in list(data_dic_local.items()):
if v_web == v_local:
# 避免一个企业多个尾矿库、增加字典报错的情况 分别做try
try:
temp_dic_local[k_local] = v_local
except:
pass
try:
temp_dic_web[k_web] = v_web
except:
pass
- 通过差集获得不同名且企业名称不同的尾矿库
for (k_web,v_web) in list(data_dic_web.items()):
if k_web in temp_dic_web.keys():
del data_dic_web[k_web]
for (k_local,v_local) in list(data_dic_local.items()):
if k_local in temp_dic_local.keys():
del data_dic_local[k_local]
- 对剩余部分,用web数据依次遍历local数据,按最大匹配(最多相同字符)推荐对应匹配项目
# 获取匹配字典,比较尾矿库+企业名称
match_dic = advancedCompare('all',data_dic_web, data_dic_local)
# 获取剩余数据
(data_dic_web, data_dic_local) = getLeftData(match_dic, data_dic_web, data_dic_local)
# 加一层循环,比较企业名称
if len(data_dic_web) > 0:
match_dic = advancedCompare('value_only',data_dic_web, data_dic_local)
(data_dic_web,data_dic_local) = getLeftData(match_dic,data_dic_web,data_dic_local)
# 深入的语义比较
def advancedCompare(pattern,data_dic_web,data_dic_local):
match_dic = {}
for item_web in data_dic_web.items():
temp_match_max_n = 0
temp_match_max_item = ''
for item_local in data_dic_local.items():
n = 0
# web 和 local 双向比较,短str向长str比较,获得最长匹配 n ,取 n = n / len(较短str)
str_web = ''
str_local = ''
if pattern == 'all': # 尾矿库名称 + 企业名称
str_web = str(item_web[0]) + str(item_web[1])
str_local = str(item_local[0]) + str(item_local[1])
if pattern == 'value_only': # 仅企业名称
str_web = str(item_web[1])
str_local = str(item_local[1])
str_long = ''
str_short = ''
if len(str_web) >= len(str_local):
str_long = str_web
str_short = str_local
else:
str_long = str_local
str_short = str_web
for character in str_short: # item 为 tuple
if character in str_long:
n = n + 1
# 删除匹配character的第一个字符,避免重复比较
str_long = str_long.replace(character, '', 1)
n = float(n/len(str_short))
if n > temp_match_max_n:
temp_match_max_n = n
temp_match_max_item = item_local
# local出现重复记录的,即temp_match_max_item,且 n 不相等的,取 n 最大值匹配
if match_dic == {}:
match_dic[item_web[0]] = ([item_web, temp_match_max_item, temp_match_max_n])
else:
add_flag = True
for v in list(match_dic.values()):
# 遍历到最后,扫描一遍
# 若在字典中有重复匹配的情况
if temp_match_max_item == v[1]:
# 扫描一遍发现相同项,则不执行最后的add
add_flag = False
# 若 n 值较大,则删除已登记的较小匹配条目,新增较大条目
if temp_match_max_n > v[2]:
# print("get greater n = {0}, temp_match_max_item = {1}".format(temp_match_max_n,
# temp_match_max_item))
del match_dic[v[0][0]]
match_dic[item_web[0]] = ([item_web, temp_match_max_item, temp_match_max_n])
# 若 n 值相等或变小,则跳过,不添加入字典(相等情况应进一步讨论)
else:
# print("get lesser {0} {1}".format(temp_match_max_item,temp_match_max_n))
pass
# 扫描一遍,若不在字典中则直接添加
if add_flag:
match_dic[item_web[0]] = ([item_web, temp_match_max_item, temp_match_max_n])
return match_dic
**代码下载地址 **:
https://github.com/793298337/str_longest_compare