如何用Python NLP技术匹配两个DataFrame行并补全分类信息
解决品牌多分类场景下的优惠信息与产品分类匹配问题
核心思路:先缩范围再精准匹配
针对品牌存在多分类的情况,避免直接全表匹配,先通过BRAND字段缩小候选分类范围,再用提取的优惠关键词和分类文本做相似度匹配,既提升效率又减少错误匹配。
1. 预处理:构建品牌-分类映射字典
先把df1按品牌分组,将每个品牌对应的所有分类信息整理成字典,避免每次匹配都扫描全表:
import pandas as pd # 按BRAND分组,存储每个品牌的所有分类条目 brand_category_map = df1.groupby('BRAND').apply( lambda x: x[['PRODUCT_CATEGORY', 'PARENT_CATEGORY', 'CATEGORY_ID']].to_dict('records') ).to_dict()
2. 模糊匹配实现(适合中小数据量)
用fuzzywuzzy的分词集匹配(token_set_ratio),能忽略关键词和分类文本的顺序差异,提升匹配准确性:
from fuzzywuzzy import fuzz def match_best_category(row): brand = row['BRAND'] keywords = row['extracted_keywords'] # 假设已提取好的关键词列表 # 品牌无对应分类时返回空值 if brand not in brand_category_map: return pd.Series([None, None, None]) candidates = brand_category_map[brand] keyword_str = ' '.join(keywords).lower() best_score = 0 best_cat = None for cat in candidates: # 拼接分类文本并统一小写 cat_str = f"{cat['PRODUCT_CATEGORY']} {cat['PARENT_CATEGORY']}".lower() # 计算分词集匹配得分 score = fuzz.token_set_ratio(keyword_str, cat_str) if score > best_score: best_score = score best_cat = cat # 设置得分阈值,低于阈值返回空(可根据业务调整) if best_score >= 60 and best_cat: return pd.Series([best_cat['PRODUCT_CATEGORY'], best_cat['PARENT_CATEGORY'], best_cat['CATEGORY_ID']]) return pd.Series([None, None, None]) # 应用到df2 df2[['PRODUCT_CATEGORY', 'PARENT_CATEGORY', 'CATEGORY_ID']] = df2.apply(match_best_category, axis=1)
3. TF-IDF余弦相似度匹配(适合大数据量)
当数据量较大时,用TF-IDF结合余弦相似度的方法更高效,能更好处理多关键词的复杂匹配:
from sklearn.feature_extraction.text import TfidfVectorizer from sklearn.metrics.pairwise import cosine_similarity # 预处理df1:拼接分类文本,按品牌构建TF-IDF模型 brand_tfidf_dict = {} for brand, group in df1.groupby('BRAND'): group['cat_text'] = (group['PRODUCT_CATEGORY'] + ' ' + group['PARENT_CATEGORY']).str.lower() vectorizer = TfidfVectorizer(stop_words='english') # 若为中文场景需替换为中文停用词 tfidf_mat = vectorizer.fit_transform(group['cat_text']) brand_tfidf_dict[brand] = { 'vectorizer': vectorizer, 'tfidf_matrix': tfidf_mat, 'cat_info': group[['PRODUCT_CATEGORY', 'PARENT_CATEGORY', 'CATEGORY_ID']].to_dict('records') } def tfidf_match_category(row): brand = row['BRAND'] keywords = row['extracted_keywords'] if brand not in brand_tfidf_dict: return pd.Series([None, None, None]) data = brand_tfidf_dict[brand] keyword_str = ' '.join(keywords).lower() # 转换关键词为TF-IDF向量 keyword_vec = data['vectorizer'].transform([keyword_str]) # 计算余弦相似度 sim_scores = cosine_similarity(keyword_vec, data['tfidf_matrix'])[0] # 取相似度最高的分类 max_sim_idx = sim_scores.argmax() max_sim = sim_scores[max_sim_idx] # 设置相似度阈值(可根据业务调整) if max_sim >= 0.3: best_cat = data['cat_info'][max_sim_idx] return pd.Series([best_cat['PRODUCT_CATEGORY'], best_cat['PARENT_CATEGORY'], best_cat['CATEGORY_ID']]) return pd.Series([None, None, None]) # 应用到df2 df2[['PRODUCT_CATEGORY', 'PARENT_CATEGORY', 'CATEGORY_ID']] = df2.apply(tfidf_match_category, axis=1)
4. 优化多分类匹配的准确性
- 业务规则优先:如果已知品牌的主品类(比如苹果的主品类是数码产品),给df1添加
PRIORITY字段(数值越小优先级越高),匹配时先筛选高优先级的分类候选,再计算得分。 - 文本清洗对齐:把df1的
PRODUCT_CATEGORY和PARENT_CATEGORY也做和OFFER列一样的清洗(去掉非字母数字字符、统一大小写),减少文本差异带来的匹配误差。 - 批量加速:大数据量下用
swifter库替代原生apply,自动选择最优执行方式(向量化或并行):
import swifter df2[['PRODUCT_CATEGORY', 'PARENT_CATEGORY', 'CATEGORY_ID']] = df2.swifter.apply(match_best_category, axis=1)
内容的提问来源于stack exchange,提问作者rzan1
相关产品推荐
相关产品推荐

