如何在Pandas中使用含通配符的查找表实现数据分类?
问题:基于含通配符的多维度查找表实现数据分类
我已经找了好几天的解决方案,在其他论坛都没找到类似的案例。现在我需要通过一个带通配符的查找表来给输入数据做分类,分类维度包括大洲(Continent)、国家(Country)和城市(City),有些分类只需要用到部分维度。这里的通配符规则是:
- 单星号
*:匹配该维度下的所有值(比如法国所有城市都归类为"France") - 双星号
**:匹配该维度下排除已精确指定后的剩余值(比如美国除纽约、旧金山外的所有城市归类为"USA - Other")
查找表示例代码
import pandas as pd lookup_df = pd.DataFrame({ 'Continent': ['Europe', 'Europe', 'Asia', 'America', 'America', 'America', 'America', 'Africa'], 'Country': ['France', 'Italy', 'Japan', 'USA', 'USA', 'USA', 'Argentina', '*'], 'City': ['*', '*', '*', 'New York', 'San Francisco', '**', '*', '*'], 'Classification': ['France', 'Italy', 'Japan', 'USA - NY', 'USA - SF', 'USA - Other', 'Argentina', 'Africa'] })
待分类数据示例代码
df = pd.DataFrame({ 'Continent': ['Europe', 'Europe', 'Asia', 'America ', 'America', 'America', 'Africa'], 'Country': ['France', 'Italy', 'Japan', 'USA', 'USA', 'USA', 'Egypt'], 'City': ['Paris', 'Rome', 'Tokyo', 'San Francisco', 'Houston', 'DC', 'Cairo'] })
我希望能得到对应的分类结果,但没法生成全球全量城市表,而且这个查找表还要兼容其他流程,想问问有没有Python风格的实现方式?我试过用pd.merge但没找到合适的示例。
解决方案:自定义匹配逻辑结合pandas迭代处理
我之前也碰到过类似的多维度通配符匹配需求,直接用pd.merge确实不太好使,因为它主要是做精确匹配的。咱们可以写个自定义的匹配函数,按照精确匹配优先,通配符匹配次之的顺序来处理每一行数据,完美适配你的规则。具体思路如下:
- 先处理精确匹配的规则(比如纽约、旧金山这类明确指定城市的)
- 再处理单星号
*的通配规则(比如法国所有城市、意大利所有城市) - 最后处理双星号
**的规则(也就是排除已匹配的剩余项)
完整实现代码
import pandas as pd def get_classification(row, lookup_df): # 先匹配精确规则(包含精确城市和城市通配符*,优先精确城市) exact_match = lookup_df[ (lookup_df['Continent'] == row['Continent'].strip()) # 清理数据里的空格,避免匹配失败 & (lookup_df['Country'] == row['Country']) & (lookup_df['City'].isin([row['City'], '*'])) ] if not exact_match.empty: # 优先返回精确城市的匹配结果 city_exact = exact_match[exact_match['City'] == row['City']] if not city_exact.empty: return city_exact.iloc[0]['Classification'] # 没有精确城市则返回城市通配符*对应的分类 else: return exact_match[exact_match['City'] == '*'].iloc[0]['Classification'] # 处理双星号**的规则:匹配大洲和国家,且City为**的项 wildcard_match = lookup_df[ (lookup_df['Continent'] == row['Continent'].strip()) & (lookup_df['Country'] == row['Country']) & (lookup_df['City'] == '**') ] if not wildcard_match.empty: return wildcard_match.iloc[0]['Classification'] # 最后处理大洲级别的*规则(比如Africa的Country为*的情况) continent_wildcard = lookup_df[ (lookup_df['Continent'] == row['Continent'].strip()) & (lookup_df['Country'] == '*') & (lookup_df['City'] == '*') ] if not continent_wildcard.empty: return continent_wildcard.iloc[0]['Classification'] # 兜底:如果没有匹配到任何规则,返回"Unclassified" return "Unclassified" # 应用函数到待分类数据 df['Classification'] = df.apply(lambda x: get_classification(x, lookup_df), axis=1) print(df)
输出结果
运行后你会得到符合预期的分类结果:
Continent Country City Classification 0 Europe France Paris France 1 Europe Italy Rome Italy 2 Asia Japan Tokyo Japan 3 America USA San Francisco USA - SF 4 America USA Houston USA - Other 5 America USA DC USA - Other 6 Africa Egypt Cairo Africa
补充说明
- 函数里特意处理了数据中可能存在的空格(比如示例里的
"America "),用.strip()做了清理,避免因为格式问题导致匹配失败 - 匹配顺序是关键:精确城市 > 城市通配符
*> 双星号**> 大洲通配符,这样能保证优先级高的规则先被匹配 - 最后加了兜底的"Unclassified",方便你快速识别没有匹配到规则的数据
内容的提问来源于stack exchange,提问作者user11209442
相关产品推荐
相关产品推荐

