Итак, я думаю, что есть решение без каких-либо существенных для циклов. Просто используя несколько соединений. Но прежде чем мы сможем достичь этого, нам нужно привести данные в более подходящую форму.
flattened_items = df.order_items.apply(pd.Series).stack().reset_index().assign(
**{"order_item": lambda x:x[0].str[0], "item_count": lambda x:x[0].str[1]})
print(flattened_items.head())
level_0 level_1 0 order_item item_count
0 0 0 (Coffee, 4) Coffee 4
1 0 1 (Salad, 10) Salad 10
2 0 2 (Chicken, 8) Chicken 8
3 1 0 (Fish&Chips, 9) Fish&Chips 9
4 1 1 (Pasta, 5) Pasta 5
Итак, по сути, я просто сплющил список кортежей в два столбца. Обратите внимание, что для вашей настройки вам может понадобиться запустить reset_index
один на исходном Dataframe df (в противном случае это похоже на ваш образец из Dataframe)
Далее мы создадим Dataframe, который подает еду к элементам через
flattend_orders = pd.merge(df[["order_id", "order_type"]],
flattened_items[["level_0","order_item", "item_count"]],
left_index=True, right_on="level_0").drop("level_0", axis=1)
meal_dct = {"Breakfast": breakfastMenu, "Lunch": lunchMenu, "Dinner": dinnerMenu}
meal_df = pd.DataFrame.from_dict(meal_dct, orient="index").stack().reset_index(
).drop("level_1", axis=1).rename(columns={"level_0": "Meal", 0: "Item"})
, который выглядит как
print(meal_df.head())
Meal Item
0 Breakfast Pancake
1 Breakfast Coffee
2 Breakfast Eggs
3 Breakfast Cereal
4 Lunch Steak
Теперь мы можем просто выполнить внутреннее объединение order_type
и order_item
merged = pd.merge(flattend_orders, meal_df, left_on=["order_type", "order_item"],
right_on=["Meal", "Item"]).drop(["Meal", "Item"], axis=1)
и получим
order_id order_type order_item item_count
0 ORDB10489 Lunch Salad 10
1 ORDB10489 Lunch Chicken 8
2 ORDK04121 Lunch Chicken 5
3 ORDZ00319 Dinner Fish&Chips 9
4 ORDB00980 Dinner Fish&Chips 10
5 ORDZ00319 Dinner Pasta 5
6 ORDB00980 Dinner Pasta 6
7 ORDY10003 Breakfast Coffee 2
8 ORDY10003 Breakfast Cereal 1
9 ORDK04121 Lunch Steak 9
Теперь, возможно, это уже достаточно хорошо, но вы можете предпочесть вернуть список кортежей. Для этого:
merged.groupby(["order_id", "order_type"]).apply(lambda x: list(zip(x["order_item"],
x["item_count"]))).reset_index().rename(columns={0:"order_items"})
дает
order_id order_type order_items
0 ORDB00980 Dinner [(Fish&Chips, 10), (Pasta, 6)]
1 ORDB10489 Lunch [(Salad, 10), (Chicken, 8)]
2 ORDK04121 Lunch [(Chicken, 5), (Steak, 9)]
3 ORDY10003 Breakfast [(Coffee, 2), (Cereal, 1)]
4 ORDZ00319 Dinner [(Fish&Chips, 9), (Pasta, 5)]
Обратите внимание, что уродство здесь связано с преобразованием данных из (возможно) недостаточно форматов. Кроме того, все для петель и яблок происходит только от преобразования данных.
По сути, мой ответ можно обобщить следующим образом:
pd.merge(df, df_meal)
, если мы примем только правильный формат данных. Кстати, я просто выбрал item_count
в качестве названия в качестве наилучшего предположения.