我这次没有用深度学习的方式,直接手撕的,所以会有通用性差的弊端。如果有复现的好的模型,未来可以用来优化下。
性能评估:
1、召回率recall:269933条数据中数据中一共有13730条提及关键词,有13728条被识别出来了
regex_match.py召回率=99%
2、准确率precision:识别的关键词中有13694是对的
regex_match.py准确率=73% ,如果加入‘部分准确’的情况,准确率升为99%
1)完全准确 10038
content有N个关键词,model匹配到N个。
2)部分准确 3656
content有N个关键词,model匹配到N+M个(M为常数)。
3)部分不准确 0
content有N个关键词,model匹配到N-M个
3、算法对比
处理相同数据时,给定相同关键词库,flash_text只识别出7205条数据,召回率52.5%,大约为regex_match.py的一半。
4、结果分析
一般没有被准确识别主要原因是错别字和漏写,如果想进一步提高识别率,需要扩充关键词库。由于匹配时,findall()函数只有贪婪和非贪婪两种模式,这也是传统文本匹配模型的弊端,即对于一些特定的文本匹配任务需要根据其特点进行人工设计,导致不同的文本匹配任务之间不具有通用性。如果想提高准确率,可以用深度文本匹配。比如,
2022年有一篇Divide and Conquer: Text Semantic Matching with Disentangled Keywords and Intents提出了一种分治的办法,即将匹配问题分解为两个子问题:关键字匹配和意图匹配。其中的意图匹配可以在用户表达比较抽象时,将他的内容作为抽象意图处理,识别出最相似的关键词。https://arxiv.org/abs/2203.02898
代码:
import pandas as pd
import re
def read_excel(file, col_name1,col_name2):
data = pd.read_excel(file)
col1= data[col_name1]
col2 = data[col_name2]
return data, col1,col2
def save(data,path):
data.to_excel(path,index=False)
print("已经完成匹配并保存到文件:", path)
return data
# 处理空值或非字符串值 for model
def drop_nan(data):
return data.dropna().astype(str).str.lower()
def drop_nan_2(data):
new_data=[]
for i in data:
new_i=i.replace(' ','')
new_data.append(new_i)
return list(set(new_data))
def drop_url_nan(data):
url_pattern = r"(?:http|https)://[a-zA-Z0-9-\.]+(?:[a-zA-Z0-9/%&=?_#.-]+)?\b"
p = re.compile(url_pattern)
new_data = []
for i in data:
if p.match(i):
inew = p.sub("", i)
new_data.append(inew)
else:
inews = i.replace(' ', '').lower()
new_data.append(inews)
return new_data
# 将每一行的元素拆分成单个元素,综合成一个大列表 for model
def split_index_to_list(data):
lst1=[]
lst2=[]
for item in data:
if '、' in item:
lst1.append(item.split('、'))
else:
lst1.append(item)
for item in lst1:
if isinstance(item,list):
lst2.extend(item)
else:
lst2.append(item)
return lst2
'''
由于 型号 = 英文+数字(+中文),所以为了降低复杂度,
设定4种特殊情况:全英文/中文/数字,空字符
'''
def is_all_english(text):
return bool(re.match(r'^[a-zA-Z]+$', text))
def is_all_chinese(text):
return bool(re.match(r'^[\u4e00-\u9fa5]+$', text))
def is_all_digits(text):
return bool(re.match(r'^\d+$', text))
def is_empty(text):
return not text.strip()
# data-原数据,model-型号扩写关键词,model_standard-型号标准关键词,content-对话文本
def roll(data,model_before,model_after,model_sandard,content):
lst=[]
n=0
m=0
length=len(content)
# 遍历内容列中的每个内容
for content_item in content:
matched_keyword = []
mapped_models = []
# 异常检查
e=is_all_english(content_item)
c=is_all_chinese(content_item)
d=is_all_digits(content_item)
emp=is_empty(content_item)
if emp or e or c or d:
m+=1
else:
# 遍历型号列表中的每个正则表达式模式
for pattern in [re.compile(keyword, flags=re.IGNORECASE) for keyword in model_after]:
# 在当前内容中搜索匹配项(不同的数据类型有不同的搜索方式,list,set,‘’)
match=pattern.findall(content_item)
if match:
#print(match) # match是一个包含关键词的数组
n+=1
matched_keyword.extend(match)
# 将标准型号名称与之对应
mapping_dict = dict(zip(model_before, model_sandard))
for keyword in matched_keyword:
for key, value in mapping_dict.items():
if keyword in key :
mapped_models.append(value)
mapped_models=list(set(mapped_models))
break
# 将匹配的关键词添加到结果列表
lst.append(mapped_models)
print('提及产品型号的次数:',n)
print('不需要进行匹配的文本数:',m)
print('文本总数:',length)
data['model']=lst
return data
# 去重
def Remove_duplicates(data):
lst=[]
for i in data:
new_i = list(set(i))
lst.append(new_i)
return lst
# 关键词路径
model_file = ''
# 需要匹配的文本路径
content_file = ''
_, model_list, models = read_excel(model_file, col_name1='你要提取的列名', col_name2='列名2')
data, content, _ = read_excel(content_file, col_name1='列名1', col_name2='列名2')
model_list1 = drop_nan(model_list)
model_list2 = split_index_to_list(model_list1)
content = drop_url_nan(content)
data1 = roll(data, model_list1, model_list2, models, content)
data2=Remove_duplicates(data1)
new_file_path = ''
new_file = save(data2, new_file_path)