基于Excel列的品牌、产品名称及重量的相似性匹配需求
跨异构超市数据集的产品匹配NLP方案
针对你提供的两个结构不同的超市产品Excel数据集,以下是一套实用的NLP文本相似度匹配方案,核心思路是先统一数据格式,再分层匹配过滤:
一、数据预处理:统一字段格式
这是匹配的基础,先把异构数据转换成可对比的结构:
- 品牌字段标准化:去除冗余后缀(如表格1的"Ferrero spa"去掉"spa"),统一大小写,把所有品牌转为小写或首字母大写格式。
- 规格信息拆分与标准化:表格2的名称字段混有规格(如"Nutella 250gr"),用正则表达式
\d+[a-zA-Z]+提取规格部分,再统一单位(如"gr"转"g"、"gml"转"ml");拆分后得到纯产品名称和独立的规格字段,和表格1的"名称1""重量1"对齐。 - 产品名称清洗:处理缩写(如"Pasta Ineg."还原为"Pasta Integrale"、"Zero Sug."还原为"Zero Sugar"),去掉规格、特殊符号等无关内容,得到干净的产品名称。
二、分层匹配逻辑
1. 品牌初筛:缩小匹配范围
- 精确匹配优先:先匹配标准化后的品牌完全一致的产品,减少后续计算量。
- 模糊匹配补漏:对精确匹配未命中的,用编辑距离(Levenshtein Distance)或模糊匹配工具计算品牌相似度,设定阈值(如80分),超过阈值则视为同一品牌。
2. 产品名称+规格精准匹配
这一步是核心,综合判断产品是否一致:
- 名称相似度计算:可以用两种方式:
- 轻量方案:用模糊匹配得分,或Jaccard相似度比较名称的词集合。
- 精准方案:用TF-IDF生成文本向量后计算余弦相似度,或用预训练词嵌入(如Word2Vec、BERT)计算句子级相似度,适合复杂名称。
- 规格严格匹配:标准化后的规格完全一致(如250g和250gr统一后均为250g)则得满分,不一致则得0分;若存在单位差异(如500ml和500gml),可提前做单位映射表处理。
- 综合得分判定:加权计算品牌匹配分、名称相似度分、规格匹配分(比如品牌40%、名称30%、规格30%),设定总得分阈值(如90分),超过阈值则判定为同一产品。
三、Python实现示例
以下是基于pandas和fuzzywuzzy的快速实现代码:
import pandas as pd import re from fuzzywuzzy import fuzz, process # 读取两个数据集 df1 = pd.read_excel("表格1.xlsx") df2 = pd.read_excel("表格2.xlsx") # 1. 品牌标准化 df1['品牌_clean'] = df1['品牌1'].str.replace(r'\sspa$', '', case=False) df2['品牌_clean'] = df2['品牌2'].str.strip() # 2. 表格2:拆分名称与规格并标准化 def clean_product_info(name): # 提取规格 spec_match = re.search(r'(\d+[a-zA-Z]+)', name) spec = spec_match.group(1).replace('gr', 'g').replace('gml', 'ml') if spec_match else '' # 清洗名称:移除规格、替换缩写 clean_name = re.sub(r'\d+[a-zA-Z]+', '', name).strip() clean_name = clean_name.replace('Ineg.', 'Integrale').replace('Sug.', 'Sugar') return clean_name, spec df2[['名称_clean', '重量_clean']] = df2['名称2'].apply(lambda x: pd.Series(clean_product_info(x))) # 3. 表格1:规格标准化 df1['重量_clean'] = df1['重量1'].str.replace('gr', 'g').replace('gml', 'ml') # 4. 产品匹配函数 def find_match(row): # 先筛选同品牌候选 brand_candidates = df2[df2['品牌_clean'] == row['品牌_clean']] # 品牌模糊匹配补漏 if brand_candidates.empty: best_brand, brand_score = process.extractOne(row['品牌_clean'], df2['品牌_clean'], scorer=fuzz.token_set_ratio) if brand_score >= 80: brand_candidates = df2[df2['品牌_clean'] == best_brand] else: return None # 计算名称与规格得分 brand_candidates['name_score'] = brand_candidates['名称_clean'].apply(lambda x: fuzz.token_set_ratio(x, row['名称1'])) brand_candidates['spec_score'] = brand_candidates.apply(lambda x: 100 if x['重量_clean'] == row['重量_clean'] else 0, axis=1) brand_candidates['total_score'] = brand_candidates['name_score']*0.3 + brand_candidates['spec_score']*0.3 + 100*0.4 # 取最高分匹配 best_match = brand_candidates[brand_candidates['total_score'] == brand_candidates['total_score'].max()] return best_match['名称2'].iloc[0] if best_match['total_score'].iloc[0] >= 90 else None # 执行匹配 df1['表格2匹配产品'] = df1.apply(find_match, axis=1) print(df1[['品牌1', '名称1', '重量1', '表格2匹配产品']])
四、优化建议
- 维护自定义同义词/缩写映射表:比如"Ineg."→"Integrale"、"Sug."→"Sugar",提前处理这类固定缩写,提升匹配准确率。
- 引入预训练语言模型:如果产品名称复杂,用BERT、Sentence-BERT计算句子相似度,比传统方法更精准。
- 加入规则引擎:比如品牌+规格完全一致时,直接判定匹配,跳过相似度计算,提升效率。
内容的提问来源于stack exchange,提问作者Take A few
相关产品推荐
相关产品推荐

