首页 > 解决方案 > pandas apply() 函数无需返回值?/ 快速循环 df?

问题描述

我有一个大型(~145000 行)我正在研究的食谱数据库。我有一列“parsed_ingredients”,看起来像这样(每行多个字典):

[{'orig_name': '1,00 kg Kalbsbraten ',
  'orig_amount': '1.00',
  'orig_unit': 'kg',
  'amount': 0.25,
  'unit': 'g',
  'splitted_ingredient': 'Kalbsbraten',
  'splitted_slized_ingredient': 'Kalbsbraten',
  'further_specification': '',
  'alternatives': '',
  'matched_ingredient_id': 'U030100',
  'matched_ingredient_st': 'Kalb Hackfleisch roh',
  'calorie': 148,
  'protein': 19.726,
  'carb': 0.0,
  'fat': 7.713},
 {'orig_name': '1,00  Zwiebel(n) ',
  'orig_amount': '1.00',
  'orig_unit': 'Anzahl',
  'amount': 9.0,
  'unit': 'g',
  'splitted_ingredient': 'Zwiebel(n)',
  ...
]

基本上,我正在尝试为基于项目和基于用户(基于内容)的推荐系统准备我的 df,因此我正在尝试创建一个矩阵,其中包含配方中包含的每种成分的列。

我尝试了以下方法,但遇到的问题是,对于如此多的行,它非常慢:

for index, row in df.iterrows():
    extracted_ingredient = ""
    for ingredient in row["parsed_ingredients"]:
        extracted_ingredient = ingredient["matched_ingredient_st"]
        if not extracted_ingredient == "None":
            df.loc[index, extracted_ingredient] = 1

因此,我尝试编写一个与 apply 一起使用的函数,因为我读到它的计算速度要快得多,但后来意识到 apply 总是希望我返回一些东西以保存在 DF 中(否则我会得到 'TypeError: 'NoneType' object is not callable' :

def ingredient_extraction(content, dataframe=df):
    for newrow in content:
        for entry in newrow:
            if not entry["matched_ingredient_st"] == "None":
                df[entry["matched_ingredient_st"]] = 1

df.apply(ingredient_extraction(df["parsed_ingredients"], df), axis=1)

有什么方法可以让熊猫将此功能应用于我的 df 吗?或者有没有更好的方法来加快在 iterrows 中完成的操作?

标签: pythonpandasdataframe

解决方案


只是一个想法的粗略轮廓。

假设你有一个像这样的 DataFrame:

recipe_id | parsed_ingredients
------------------------------
 1        | [{...}, {...}, ...]
 2        | [{...}, {...}, ...]
 3        | [{...}, {...}, ...]

使用该explode方法,展开 DataFrame 以每行显示一个成分字典。

df = df.explode('parsed_ingredients')
df.head()

recipe_id | parsed_ingredients
------------------------------
 1        | {...}
 1        | {...}
     ...
 2        | {...}
 2        | {...}
     ...
 3        | {...}
 3        | {...}
     ...

现在matched_ingredient_st从每个字典中提取

df['matched_ingredient_st'] = df['parsed_ingredients'].apply(lambda x: x['matched_ingredient_st'])
df['match'] = 1 # Added for the next step
df.head()

recipe_id | parsed_ingredients | matched_ingredient_st | match
--------------------------------------------------------------
 1        | {...}              | ingredient_a          | 1
 1        | {...}              | ingredient_b          | 1
     ...
 2        | {...}              | ingredient_b          | 1
 2        | {...}              | ingredient_d          | 1
     ...
 3        | {...}              | ingredient_c          | 1
 3        | {...}              | ingredient_d          | 1
     ...

现在您可以使用内置的 pivot 方法将 DataFrame 还原为原始数据集中的类似格式

df = df.pivot(index='recipe_id ', columns='matched_ingredient_st ', values='match')
df.head()

   | ingredient_a | ingredient_b | ingredient_c | ingredient_d 
---------------------------------------------------------------
 1 |       1      |       1      |       0      |       0      |
 2 |       0      |       1      |       0      |       1      |
 3 |       0      |       0      |       1      |       1      |

实际上并没有在 Python 中运行它,但是那里有逻辑和方法。


推荐阅读