DataFrame字符串精准匹配标准化及非指定列保留技术问询
DataFrame国家名称标准化匹配问题及原列保留需求
核心问题
- 现有正则匹配逻辑无法实现完整字符串精准匹配,会错误匹配包含目标子串的内容(比如把
Example1 and中的Example1误匹配) - 希望最终输出的DataFrame自动保留原数据中所有非指定列(如
year),无需手动指定列名
原实现代码
import re from functools import reduce import pandas as pd def match_country_codes(df, country_codes): # Create a regex pattern to match whole words pattern = '|'.join(rf'\b{re.escape(c)}\b' for c in country_codes[['country', 'alpha1', 'alpha2']].values.flatten()) # new column for matches between pattern and df['country'] items df['matched_country'] = df['country'].str.extract(f'({pattern})', flags=re.IGNORECASE) # Merge with 'country_codes' dataframe to get the full country names # merge over 3 frames for all columns df1 = df.merge(country_codes, left_on='matched_country', right_on='country', how='left') df2 = df.merge(country_codes, left_on='matched_country', right_on='alpha1', how='left') df3 = df.merge(country_codes, left_on='matched_country', right_on='alpha2', how='left') dataframes = [df1, df2, df3] # merge all dataframes together on '[['country_y']]' result = reduce(lambda x, y: x.merge(y, on=['country_y'], how='left'), dataframes) # Drop rows with None or NaN values in the 'country_y' column result = result.dropna(subset=['country_y']) # return result return result
示例数据
df = pd.DataFrame({'country': ['foobar', 'foo and bar', 'Example1 and', 'PQR'], 'year':[2018, 2019, 'NA',2017] }) country_codes = pd.DataFrame({'country': ['FooBar', 'Example1', 'foo and bar and foo', 'Example'], 'alpha1': ['foobar', 'Bosnia', 'ABC', 'DEF'], 'alpha2': ['GHI', 'JKL', 'MNO', 'PQR'] })
当前问题表现
运行match_country_codes(df, country_codes)会错误匹配到Example1,且原列保留逻辑混乱,出现大量冗余列。
期望输出
仅匹配完全一致的内容(忽略大小写),同时自动保留原所有列:
data = {'country': ['foobar', 'PQR'], 'year': [2018, 2017], 'standard_country': ['FooBar', 'Example'] } desired_output = pd.DataFrame(data, index=[0, 3])
解决方案
关键优化点
- 精准完全匹配:构建大小写不敏感的映射字典,将所有可能的匹配值(country、alpha1、alpha2)映射到标准国家名称,避免子串误匹配
- 自动保留原列:直接在原DataFrame基础上添加标准化列,避免多次合并导致的列冗余
修改后的代码
import pandas as pd def match_country_codes(df, country_codes): # 构建大小写不敏感的匹配映射:所有可能的输入值 -> 标准国家名 match_map = {} for _, row in country_codes.iterrows(): standard_name = row['country'] # 把country、alpha1、alpha2都加入映射,统一转小写作为键 for col in ['country', 'alpha1', 'alpha2']: match_key = str(row[col]).lower() match_map[match_key] = standard_name # 对原df的country列做匹配,生成标准化列 df['standard_country'] = df['country'].str.lower().map(match_map) # 过滤掉匹配失败的行,保留所有原列 result = df.dropna(subset=['standard_country']).copy() return result
测试验证
运行以下代码:
result = match_country_codes(df, country_codes) print(result)
输出结果:
country year standard_country 0 foobar 2018 FooBar 3 PQR 2017 Example
完全符合期望,自动保留了year列,且无错误匹配情况。
内容的提问来源于stack exchange,提问作者Benjamin Allen
相关产品推荐
相关产品推荐

