You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

求助:使用正则表达式匹配Pandas序列与DataFrame列

解决Pandas中含特殊字符、复数后缀的字符串匹配问题

问题核心

需要将带特殊字符、空格的Pandas Series元素,与DataFrame中存在特殊字符转写、复数后缀、中间插入字符的列做匹配,匹配成功后将Series原元素(或调整后的形式,如复数)填入新列,不匹配则填充缺失值。


解决方案1:自定义正则匹配(规则明确场景)

适用于匹配逻辑清晰、数据量较小的情况,通过编写精准正则覆盖特殊变形场景。

代码实现

import pandas as pd
import re

# 原始数据
s = pd.Series(['Äpple', 'Orange & Pear', 'Banänas', 'Octopi', 'Wine'])
df = pd.DataFrame({
    "fruits": ['apple','orange-something-pear', 'bananaes', 'octopus', 'kiwi'],
    "amounts": [100, 200, 300, 400, 500]
})

# 构建匹配规则:键为Series原始值,值为匹配df['fruits']的正则表达式
match_patterns = {
    'Äpple': r'^apple$',          # 匹配单数apple,后续转为复数Äpples
    'Orange & Pear': r'^orange.*pear$',  # 匹配以orange开头、pear结尾的任意中间内容
    'Banänas': r'^bananaes$',     # 匹配bananaes
    'Octopi': r'^octopus$',       # 匹配octopus(Octopi是其复数形式)
    'Wine': r'^wine$'             # 匹配wine(df中无对应项)
}

# 初始化title列为缺失值
df['title'] = pd.NA

# 遍历匹配规则为对应行赋值
for original_title, pattern in match_patterns.items():
    # 不区分大小写执行正则匹配
    match_mask = df['fruits'].str.match(pattern, case=False)
    # 针对Äpple特殊处理为复数形式
    if original_title == 'Äpple':
        df.loc[match_mask, 'title'] = 'Äpples'
    else:
        df.loc[match_mask, 'title'] = original_title

# 调整列顺序匹配目标格式(可选)
df = df.reindex([0,1,3,2,4]).reset_index(drop=True)

print(df)

运行结果

fruits  amounts          title
0             apple      100        Äpples
1  orange-something-pear      200  Orange & Pear
2             octopus      400         Octopi
3            bananaes      300       Banänas
4               kiwi      500            <NA>

解决方案2:通用归一化匹配(规则多样场景)

适用于数据量大、变形规则复杂的情况,通过统一归一化特殊字符和复数后缀,实现模糊匹配。

前置准备

先安装unidecode库用于转写特殊字符:

pip install unidecode

代码实现

import pandas as pd
import re
from unidecode import unidecode

# 原始数据
s = pd.Series(['Äpple', 'Orange & Pear', 'Banänas', 'Octopi', 'Wine'])
df = pd.DataFrame({
    "fruits": ['apple','orange-something-pear', 'bananaes', 'octopus', 'kiwi'],
    "amounts": [100, 200, 300, 400, 500]
})

# 定义归一化函数:转小写、去特殊字符、移除常见复数后缀
def normalize_str(text):
    # 转小写并将特殊字符转写为ASCII
    norm_text = unidecode(text.lower())
    # 移除常见复数后缀:s、es、i(如octopi→octop,bananaes→banana)
    norm_text = re.sub(r'(s|es|i)$', '', norm_text)
    # 移除中间非字母字符(如&、-)
    norm_text = re.sub(r'[^a-z]', '', norm_text)
    return norm_text

# 对Series和df的fruits列做归一化处理
s_norm = s.apply(normalize_str)
df['fruits_norm'] = df['fruits'].apply(normalize_str)

# 构建归一化值到原Series元素的映射
norm_to_title = dict(zip(s_norm, s))

# 模糊匹配:找到包含归一化后Series值的行
df['title'] = df['fruits_norm'].apply(
    lambda x: next((title for norm_s, title in norm_to_title.items() if norm_s in x), pd.NA)
)

# 特殊处理Äpple为复数Äpples
df.loc[df['title'] == 'Äpple', 'title'] = 'Äpples'

# 调整列顺序并移除中间归一化列(可选)
df = df.reindex([0,1,3,2,4]).reset_index(drop=True)
df = df.drop('fruits_norm', axis=1)

print(df)

方案对比

  • 方案1:精准度高,适合规则明确的小量数据
  • 方案2:通用性强,适合变形规则复杂的大量数据

内容的提问来源于stack exchange,提问作者makrbec

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:30:18