如何为DataFrame每行分配对应筛选后的食谱ID列表?
问题描述
需要为现有DataFrame fitbit_dt2 添加一列allwd_recipes,每行存储符合条件的整数(食谱ID)列表:筛选recp_some中不包含当前用户食物过敏原的所有食谱ID。
尝试两种方法均失败:
- 嵌套循环代码报错:
for i in fitbit_dt2.index: allwd_rcp = [] for j in recp_some.index: if fitbit_dt2["Food Intolerances"][i] not in recp_some["ingredients"][j]: allwd_rcp.append(recp_some["id"][j]) fitbit_dt2["allwd_recipes"][i] = fitbit_dt2["allwd_recipes"][i].apply(allwd_rcp)
- 列表推导式导致所有行分配同一个列表:
fitbit_dt2["allwd_recipes"] = [allwd_rcp for i in fitbit_dt2.index]
数据集样例
fitbit_dt2 初始数据
| id | gender | Food Intolerances |
|---|---|---|
| 0 | male | Peanuts |
| 1 | female | None |
| 2 | male | None |
| 3 | female | Kiwi |
| 4 | female | Milk |
| 5 | male | Wheat |
| 6 | male | None |
recp_some 食谱数据
| id | ingredients |
|---|---|
| 10354 | ["romaine lettuce","black olives","grape tomatoes","garlic","pepper","purple onion","seasoning","garbanzo beans","feta cheese crumbles"] |
| 2645 | ["water","vegetable oil","wheat","salt"] |
| 12734 | ["italian seasoning","broiler-fryer chicken","mayonaise","zesty italian dressing"] |
| 2941 | ["sugar","hot chili","fish sauce","lime juice","peanuts"] |
| 40254 | ["bananas","pineapple juice","cherries","coconut rum","cranberry juice","full fat milk","rum","kiwi"] |
期望输出
| id | gender | Food Intolerances | allwd_recipes |
|---|---|---|---|
| 0 | male | Peanuts | [10354,2645,12734,40254] |
| 1 | female | None | [10354,2645,12734,2941,40254] |
| 2 | male | None | [10354,2645,12734,2941,40254] |
| 3 | female | Kiwi | [10354,2645,12734,2941] |
| 4 | female | Milk | [2645,12734,2941] |
| 5 | male | Wheat | [10354,12734,2941,40254] |
| 6 | male | None | [10354,2645,12734,2941,40254] |
修正方案
方法1:用apply逐行处理(简洁高效)
利用Pandas的apply方法,对每行单独计算符合条件的食谱ID列表,避免冗余循环和错误:
# 定义函数:输入过敏原,返回允许的食谱ID列表 def get_allowed_recipes(intolerance): if intolerance == "None": return recp_some["id"].tolist() # 筛选不包含过敏原的食谱,提取ID转为列表 mask = ~recp_some["ingredients"].apply(lambda x: intolerance in x) return recp_some.loc[mask, "id"].tolist() # 为fitbit_dt2添加新列 fitbit_dt2["allwd_recipes"] = fitbit_dt2["Food Intolerances"].apply(get_allowed_recipes)
方法2:修复原循环逻辑(适合理解底层逻辑)
如果坚持用循环,需修正赋值逻辑并避免链式索引警告:
# 初始化新列为独立空列表 fitbit_dt2["allwd_recipes"] = [[] for _ in range(len(fitbit_dt2))] for i in fitbit_dt2.index: allwd_rcp = [] intolerance = fitbit_dt2.loc[i, "Food Intolerances"] for j in recp_some.index: if intolerance == "None" or intolerance not in recp_some.loc[j, "ingredients"]: allwd_rcp.append(recp_some.loc[j, "id"]) # 用.loc赋值避免链式索引问题 fitbit_dt2.loc[i, "allwd_recipes"] = allwd_rcp
关键错误说明
- 第一种尝试错误:
fitbit_dt2["allwd_recipes"][i].apply(allwd_rcp)逻辑混乱,apply是Series/DataFrame的方法,不能直接对单个列表调用,此处直接赋值列表即可。 - 第二种尝试错误:列表推导式引用了外部同一个
allwd_rcp对象,所有行共享同一内存地址,导致所有行内容完全相同;需在推导式内创建新列表,或用apply自动生成独立列表。
内容的提问来源于stack exchange,提问作者Kavya Nagesh
相关产品推荐
相关产品推荐

