如何在Pandas中使用通配符匹配值并返回对应列名?
实现交易描述与推荐类别的匹配
相关代码
以下是读取交易数据和推荐类别数据的代码:
import pandas as pd data = pd.read_csv('transactions(1).csv') userTransactionsDF = pd.DataFrame(data, columns=['Date', 'Original Description', 'Amount', 'Category', 'Account Name']) print(userTransactionsDF.head(1)) # 输出 # Date Original Description ... Category Account Name # 0 4/14/2023 PETCO 304 ... Pet Food & Supplies DISCOVER IT CHROME CARD data2 = pd.read_csv('recommended_categories.csv') recommendedCategoriesDF = pd.DataFrame(data2) print(recommendedCategoriesDF.head(1)) # 输出 # Unnamed: 0 HOUSING TRANSPORT FOOD ... INCOME ENTERTAINMENT SERVICES Other # 0 0 NaN shell qdoba ... NaN nintendo NaN NaN
需求说明
遍历userTransactionsDF中的每条交易记录,检查Original Description字段值是否能匹配recommendedCategoriesDF中的任意值(匹配规则为在目标值两侧添加.+通配符,即描述中需包含该目标值且前后有任意字符),若匹配成功则返回该值所在的列名(类别);若未匹配到任何值,则返回Other。
示例:当Original Description的值为'POS WD Nintendo CA877180016 8'时,需匹配recommendedCategoriesDF中的'nintendo',并返回列名'ENTERTAINMENT'。
错误尝试代码
以下是尝试但思路有误的代码:
for j in userTransactionsDF['Original Description']: for p in userTransactionsDF['Amount']: print('original description = ' + j) # 需要用正则实现通配符匹配逻辑 if (i for i in categories_dict if re.search('.+' + str(categories_dict[i]) + '.+', j)): value = {i for i in categories_dict if re.search('.+' + str(categories_dict[i]) + '.+', j)} print('value = ' + str(value)) categorized_Transactions.loc[len(categorized_Transactions)] = pandas.Series({value: p}) else: categorized_Transactions.loc[len(categorized_Transactions)] = pandas.Series({'Other': p})
正确实现方法
步骤说明
- 构建关键词→类别的映射字典:遍历
recommendedCategoriesDF的每一列,将列中所有非NaN的关键词与对应列名(类别)关联。 - 定义匹配函数:对每条交易描述,检查是否匹配映射字典中的任意关键词(使用正则
.+关键词.+,并忽略大小写),返回对应类别或Other。 - 批量处理交易数据:用pandas的
apply()方法将匹配函数应用到所有交易记录,生成匹配结果。
完整代码
import pandas as pd import re # 读取并预处理数据 data = pd.read_csv('transactions(1).csv') userTransactionsDF = pd.DataFrame(data, columns=['Date', 'Original Description', 'Amount', 'Category', 'Account Name']) data2 = pd.read_csv('recommended_categories.csv') recommendedCategoriesDF = pd.DataFrame(data2) # 移除无用的索引列 recommendedCategoriesDF = recommendedCategoriesDF.drop(columns=['Unnamed: 0']) # 构建关键词到类别的映射字典 keyword_category_map = {} for category_col in recommendedCategoriesDF.columns: # 获取当前类别下的所有非空关键词 keywords = recommendedCategoriesDF[category_col].dropna().astype(str).tolist() for keyword in keywords: # 统一转小写,避免大小写匹配问题 keyword_lower = keyword.lower() keyword_category_map[keyword_lower] = category_col # 定义匹配逻辑函数 def get_matched_category(description): desc_lower = description.lower() for keyword, category in keyword_category_map.items(): # 使用re.escape处理关键词中的特殊字符,避免正则语法冲突 pattern = rf'.+{re.escape(keyword)}.+' if re.search(pattern, desc_lower): return category return 'Other' # 为每条交易匹配类别 userTransactionsDF['Matched Category'] = userTransactionsDF['Original Description'].apply(get_matched_category) # 查看结果 print(userTransactionsDF.head())
关键优化点
- 避免嵌套循环:用pandas的
apply()批量处理,比手动循环更高效且符合pandas最佳实践。 - 处理大小写:将关键词和描述统一转小写,解决大小写不匹配问题。
- 正则安全:用
re.escape()处理关键词,防止关键词包含正则特殊字符(如.、*)导致匹配错误。 - 结构清晰:先构建映射字典,再统一匹配,逻辑更易维护。
内容的提问来源于stack exchange,提问作者Addi O
相关产品推荐
相关产品推荐

