如何用正则捕获重音字符,去除数据集列含复数、拼写错误的重复项
问题诊断与优化方案
你的代码没能达到预期去重效果,核心问题如下:
- 未处理重音字符:带重音和无重音的同一名称被判定为不同项,比如
maisonduesiècle和maisonduesiecle无法被识别为重复 - 单复数逻辑单向:仅检查当前名称加
s是否在列表中,若先出现单数、后出现复数,复数会被误判为新项(比如先有maison,后来的maisons会被错误加入) - 列表查询效率低:用列表
in操作判断存在性,数据量大时速度慢且逻辑易出错 - 拼写错误处理不全:仅移除了非字母字符,但未覆盖字母错位类错误
优化步骤与代码
1. 处理重音字符
通过Unicode标准化将带重音的字符转换为普通字母,这是解决重音导致重复的关键:
import unicodedata def remove_accents(text): return unicodedata.normalize('NFKD', text).encode('ascii', 'ignore').decode('utf-8')
2. 标准化文本格式
统一转小写、过滤非字母字符,确保不同格式的同一名称能被归一化:
import pandas as pd def normalize_name(text): if pd.isna(text): return '' # 移除重音 text_no_accents = remove_accents(text) # 仅保留字母并转小写 normalized = ''.join([c.lower() for c in text_no_accents if c.isalpha()]) return normalized
3. 完善单复数去重逻辑
改用集合存储已处理名称(查询效率O(1)),同时覆盖单数转复数、复数转单数的双向检查,还兼容法语部分特殊复数规则:
# 读取数据集 monuments = pd.read_csv("data/liste-des-immeubles-proteges-au-titre-des-monuments-historiques.csv", sep=";") # 生成标准化后的名称列 monuments['normalized_tico'] = monuments['tico'].apply(normalize_name) unique_names = set() sieve = [] for name in monuments['normalized_tico']: if not name: continue exists = False # 检查当前名称或其复数形式是否已存在 if name in unique_names or (name + 's') in unique_names: exists = True # 若当前是复数(结尾为s),检查对应单数是否已存在 elif name.endswith('s'): singular = name[:-1] if singular in unique_names: exists = True # 处理法语中以x结尾的复数(如château -> châteaux) elif name.endswith('x'): singular_candidate = name[:-1] if singular_candidate in unique_names or (singular_candidate + 's') in unique_names: exists = True if not exists: unique_names.add(name) sieve.append(name) print(len(sieve))
4. 额外处理拼写错误
如果要处理字母错位类错误(比如maison和maosn),可以用fuzzywuzzy库计算编辑距离判断名称相似度:
from fuzzywuzzy import fuzz def is_similar(name, unique_set, threshold=90): for existing in unique_set: if fuzz.ratio(name, existing) >= threshold: return True return False
将该函数加入循环的exists判断即可,注意这会增加运行时间,适合中等规模数据集。
内容的提问来源于stack exchange,提问作者Mustapha Unubi Momoh
相关产品推荐
相关产品推荐

