Pandas DataFrame:根据Food列匹配Bowl列生成均值新列的问题
解决DataFrame中基于文本匹配计算均值的问题
给定如下DataFrame:
import pandas as pd df = {'Food': ['Apple', 'orange','kiwi'], 'Bowl': ['Apple, orange, kiwi','Apple, orange, banana','Orange, apple, banana'], 'Price' : [4,8,8]} df = pd.DataFrame(df)
需要创建new列,规则为:
- 以
Food列的每个值为关键词,在Bowl列中搜索(不区分大小写) - 若找到匹配行,取这些行的
Price均值填入new列 - 若无匹配,返回
NaN
预期结果中new列值为[6.67, 6.67, 4]。
原代码的问题
你当前的循环代码存在两个核心问题:
- 每次循环计算的
new变量仅存储当前食物的均值,没有赋值到DataFrame的对应行,最终只会保留最后一次循环的结果 - 使用
statistics.mean不如pandas内置的Series.mean()友好,后者会自动处理无匹配项的情况(返回NaN)
解决方案
推荐使用pandas的apply函数实现向量化操作,代码简洁且效率更高:
import pandas as pd df = {'Food': ['Apple', 'orange','kiwi'], 'Bowl': ['Apple, orange, kiwi','Apple, orange, banana','Orange, apple, banana'], 'Price' : [4,8,8]} df = pd.DataFrame(df) def calculate_mean_price(food): # 生成匹配掩码:Bowl列包含当前食物(不区分大小写) match_mask = df['Bowl'].str.contains(food, case=False, na=False) # 返回匹配行的Price均值,无匹配则返回NaN return df.loc[match_mask, 'Price'].mean() # 为每个Food值计算对应均值,生成new列 df['new'] = df['Food'].apply(calculate_mean_price) # 保留两位小数(可选,根据需求调整) df['new'] = df['new'].round(2) print(df)
执行后输出:
Food Bowl Price new 0 Apple Apple, orange, kiwi 4 6.67 1 orange Apple, orange, banana 8 6.67 2 kiwi Orange, apple, banana 8 4.00
大数据量优化方案
如果你的数据集行数较多(比如超过10万行),apply的效率可能不足,可以通过拆分Bowl列并构建交叉表来优化:
# 拆分Bowl列的食物,生成每行对应多个食物的行 bowl_exploded = df.assign(Food_in_Bowl=df['Bowl'].str.split(', ')).explode('Food_in_Bowl') # 统一大小写,避免匹配误差 bowl_exploded['Food_in_Bowl'] = bowl_exploded['Food_in_Bowl'].str.lower() df['Food_lower'] = df['Food'].str.lower() # 计算每个食物的Price均值 food_price_mean = bowl_exploded.groupby('Food_in_Bowl')['Price'].mean().round(2) # 映射到原DataFrame df['new'] = df['Food_lower'].map(food_price_mean) # 清理临时列 df.drop('Food_lower', axis=1, inplace=True)
这种方法通过一次拆分和分组计算,避免了逐行循环,效率提升明显。
内容的提问来源于stack exchange,提问作者wtialyll
相关产品推荐
相关产品推荐

