
问题背景与挑战
在数据处理中,我们经常需要根据文本描述为数据项添加类别标签。一个常见的场景是,我们拥有一个包含关键词及其对应类别的字典,以及一个dataframe,其中某一列的文本值包含这些关键词。例如,我们有一个商品名称列表,希望根据商品名称中的特定词汇(如“apple”、“grape”)将其归类为“fruit”。
直接使用Pandas的map函数进行字典映射是处理一对一精确匹配的常用方法。然而,当字典的键不是DataFrame列值的精确匹配,而是其子字符串时,map函数将无法直接应用。例如,如果字典是{'apple': 'fruit'},而DataFrame中的项是'apple from happy orchard',直接df['Item'].map(category_dict)将返回NaN,因为它无法找到完全匹配的键。
解决方案:结合apply与自定义匹配逻辑
为了解决子字符串匹配的问题,我们可以利用Pandas DataFrame的apply方法,结合一个自定义的lambda函数。这个lambda函数将遍历字典中的所有键值对,检查字典的键是否作为子字符串存在于DataFrame的当前单元格中。
1. 准备数据与字典
首先,我们定义用于映射的字典和示例DataFrame:
import pandas as pd
# 类别字典,键是关键词,值是类别
category_dict = {
'apple': 'fruit',
'grape': 'fruit',
'chickpea': 'beans',
'coffee cup': 'tableware'
}
# 示例DataFrame
data = {
'Item': [
'apple from happy orchard',
'grape from random vineyard',
'chickpea and black bean mix',
'coffee cup with dog decal'
],
'Cost': [15, 20, 10, 14]
}
df = pd.DataFrame(data)
print("原始DataFrame:")
print(df)2. 应用自定义匹配函数
核心的解决方案在于使用df['Item'].apply()方法。apply方法会对DataFrame指定列的每一个元素执行一个函数。在这里,我们传递一个lambda函数,该函数接收列中的每个字符串x作为输入,并执行以下逻辑:
- 遍历字典项: for key, value in category_dict.items() 遍历字典中的每一个关键词和类别。
- 子字符串匹配: if key in x 检查当前的关键词key是否是当前DataFrame项x的子字符串。
- 获取第一个匹配项: next((value for key, value in category_dict.items() if key in x), None) 这行代码使用了一个生成器表达式。它会寻找第一个满足key in x条件的键值对,并返回其对应的value。如果没有任何键匹配成功,next函数将返回其第二个参数None。
# 应用自定义函数添加 'Category' 列
df['Category'] = df['Item'].apply(
lambda x: next((value for key, value in category_dict.items() if key in x), None)
)
print("\n添加 'Category' 列后的DataFrame:")
print(df)输出结果:
原始DataFrame:
Item Cost
0 apple from happy orchard 15
1 grape from random vineyard 20
2 chickpea and black bean mix 10
3 coffee cup with dog decal 14
添加 'Category' 列后的DataFrame:
Item Cost Category
0 apple from happy orchard 15 fruit
1 grape from random vineyard 20 fruit
2 chickpea and black bean mix 10 beans
3 coffee cup with dog decal 14 tableware注意事项与进阶考量
-
性能考量: 对于非常大的DataFrame和/或字典,apply方法在Python循环中执行,可能不是最高效的。如果性能成为瓶颈,可以考虑以下优化:
匹配优先级: next()函数会返回第一个找到的匹配项。如果一个DataFrame项可以匹配字典中的多个键(例如,"apple pie"可以匹配"apple"和"pie"),则字典中迭代顺序靠前的键会优先匹配。如果需要特定的优先级,应确保字典的键按照所需的优先级顺序排列(例如,将更具体的键放在前面,或对字典键进行排序)。
-
无匹配项处理: 当前代码中,如果DataFrame中的项没有匹配到字典中的任何关键词,Category列将赋值为None。你可以根据需求修改next函数的默认值,例如将其设置为'Other'或保留为pd.NA。
# 示例:无匹配项时赋值为 'Unknown' df['Category_with_unknown'] = df['Item'].apply( lambda x: next((value for key, value in category_dict.items() if key in x), 'Unknown') ) -
大小写敏感性: key in x 是大小写敏感的。如果需要进行大小写不敏感的匹配,应在比较前将key和x都转换为小写:
df['Category_case_insensitive'] = df['Item'].apply( lambda x: next((value for key, value in category_dict.items() if key.lower() in x.lower()), None) )
总结
通过灵活运用Pandas的apply函数结合自定义的lambda表达式,我们可以有效地解决在DataFrame中基于字典进行子字符串匹配并添加分类列的问题。这种方法提供了一种强大且可定制的解决方案,适用于各种复杂的文本数据分类场景。在实际应用中,根据数据规模和性能需求,可以进一步考虑优化匹配逻辑和算法。










