如何高效从Pandas DataFrame的Notes列提取存在干扰字符的9位数字ID?
如何从带干扰的Notes列中准确提取被拆分的9位数字ID
我完全懂你的困扰——那些被空格、横杠、百分比符号拆得七零八落的ID,还有到处乱入的小数字,确实会把简单的正则提取搞崩。咱们来解决这个问题,先分析下你的痛点:你之前的代码要么是手动替换符号太繁琐(根本覆盖不完所有情况),要么是找连续9位以上数字的思路不对,因为你的ID是被拆分的,不是连续的。
解决方案思路
你的每个例子里,目标ID都是一组连续出现的数字块,拼接后刚好是9位,而干扰项要么是和百分比绑定的数字,要么是零散的短数字块(组合起来长度也到不了9)。所以我们可以分三步处理:
- 先清理掉明确的干扰项:所有带百分比的数字(比如
2.5%、1.59%),这些肯定不属于ID。 - 提取剩下的所有数字块。
- 在这些数字块里,找到连续的一组,它们的长度加起来刚好是9——这就是你的目标ID,因为每个Notes里只有这么一组。
代码实现
import pandas as pd from itertools import accumulate def extract_9digit_id(notes): # 第一步:移除所有百分比相关的干扰内容 cleaned_notes = notes.replace(r'\d+\.?\d+%', '', regex=True) # 第二步:提取所有独立的数字块 num_blocks = cleaned_notes.findall(r'\d+') # 第三步:计算每个数字块的长度,找连续块长度和为9的组合 lengths = [len(block) for block in num_blocks] prefix_sums = [0] + list(accumulate(lengths)) # 前缀和数组,快速算区间长度和 for start_idx in range(len(num_blocks)): for end_idx in range(start_idx + 1, len(num_blocks) + 1): if prefix_sums[end_idx] - prefix_sums[start_idx] == 9: # 找到目标组合,拼接返回 return ''.join(num_blocks[start_idx:end_idx]) # 极端情况:没有找到连续组合(比如所有数字块分散但总长度>=9),取前9位 full_number = ''.join(num_blocks) return full_number[:9] if len(full_number) >= 9 else '' # 应用到你的DataFrame DF['Output'] = DF['Notes'].apply(extract_9digit_id)
代码解释
- 清理百分比干扰:用正则
\d+\.?\d+%匹配所有带百分比的数字(包括整数百分比比如126%和小数百分比比如2.5%),直接移除。 - 提取数字块:用
findall(r'\d+')把所有连续的数字串捞出来,不管它们之间被什么符号分隔。 - 寻找目标组合:通过前缀和数组快速计算任意连续数字块的总长度,找到总长度刚好为9的那一组,拼接起来就是ID。
- 兜底处理:如果遇到极端情况(比如所有数字块都零散,但总长度够9),就取所有数字拼接后的前9位,你可以根据实际需求调整这部分逻辑。
测试你的例子
把你给出的7个Notes例子代入,这个代码会精准输出你要的结果,完全匹配预期。
内容的提问来源于stack exchange,提问作者ross jim
相关产品推荐
相关产品推荐

