From 5bd1e0472e589aab5c8a54669db581e04f281a11 Mon Sep 17 00:00:00 2001 From: noahtren Date: Thu, 4 Apr 2019 17:12:03 -0400 Subject: [PATCH] implementation of analysis package in testing and README --- README.md | 95 +++++++++++++++++++++++++++++++++++++++++++++++- noms/__init__.py | 7 +++- noms/analyze.py | 7 ++-- test.py | 20 ++++++---- 4 files changed, 117 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 96861c0..f7e271b 100644 --- a/README.md +++ b/README.md @@ -102,4 +102,97 @@ for food in m.foods: {'nutrient_id': 269, 'name': 'Sugar', 'group': 'Proximates', 'unit': 'g', 'value': 8.97} {'nutrient_id': 269, 'name': 'Sugar', 'group': 'Proximates', 'unit': 'g', 'value': 1.7} ``` -Note that this sorts the foods in the Meal object from greatest to least in terms of how much sugar each food has. \ No newline at end of file +Note that this sorts the foods in the Meal object from greatest to least in terms of how much sugar each food has. + +## Generate Food Recommendations in Context of a Meal and Pantry +Because it would be computationally expensive to generate a food recommendation in the context of every food in the database, and it may be unrealistic to recommend any food from the database as it may be hard to access, you must define a list of foods that will serve as a pantry object. Here is an example pantry object containing many common whole foods. + +```python + pantry = { + # DAIRY AND EGG + "01001":100, # butter, salted + "01145":100, # butter, without salt + "01079":100, # 2% milk + "01077":100, # milk, whole + "01086":100, # skim milk + "01132":100, # scrambled eggs + "01129":100, # hard boiled eggs + "01128":100, # fried egg + # MEAT + "15076":100, # atlantic salmon + "07935":100, # chicken breast oven-roasted + "13647":100, # steak + "05192":100, # turkey + # FRUIT + "09037":100, # avocado + "09316":100, # strawberries + "09050":100, # blueberry + "09302":100, # raspberry + "09500":100, # red delicious apple + "09040":100, # banana + "09150":100, # lemon + "09201":100, # oranges + "09132":100, # grapes + # PROCESSED + "21250":100, # hamburger + "21272":100, # pizza + "19088":100, # ice cream + "18249":100, # donut + # DRINK + "14400":100, # coke + "14429":100, # tap water + "14433":100, # bottled water + "09206":100, # orange juice + "14278":100, # brewed green tea + "14209":100, # coffee brewed with tap water + # (milk is included in dairy group) + # GRAIN + "12006":100, # chia + "12220":100, # flaxseed + "20137":100, # quinoa, cooked + "20006":100, # pearled barley + "20051":100, # white rice enriched cooked + "20041":100, # brown rice cooked + "12151":100, # pistachio + "19047":100, # pretzel + "12061":100, # almond + # LEGUME + "16057":100, # chickpeas + "16015":100, # black beans + "16043":100, # pinto beans + "16072":100, # lima beans + "16167":100, # peanut butter smooth + # VEGETABLE + "11124":100, # raw carrots + "11090":100, # broccoli + "11457":100, # spinach, raw + "11357":100, # baked potato + "11508":100, # baked sweet potato + "11530":100, # tomato, red, cooked + "11253":100, # lettuce + "11233":100, # kale + "11313":100, # peas + "11215":100, # garlic + # OTHER + "04053":100, # olive oil + "19904":100, # dark chocolate + "11238":100, # shiitake mushrooms + "19165":100, # cocoa powder + } + pantry_food = client.get_foods(pantry) +``` +Now, with a list of possible foods to recommend, you can call noms.generate_recommendations with the meal we set up earlier, which consists of just broccoli and brown rice. +```python +recommendations = noms.generate_recommendations(m, pantry_food, noms.nutrient_dict, 3) +for rec in recommendations: + # a recommendation is a list containing the calculated loss after the recommendation + # is applied, the index of the pantry for the recommendation, and the amount of that + # food / 100g + print(str(round(rec[2] * 100, 2)) + "g", "of", pantry_food[rec[1]].desc["name"]) +``` +``` +50.36g of Seeds, chia seeds, dried +53.3g of Nuts, almonds +56.76g of Peanut Butter, smooth (Includes foods for USDA's Food Distribution Program) +``` +It is reasonable that the function returned these foods from the pantry as the current daily nutrition is low in protein and Omega-3s, which chia seeds satisfy the most. \ No newline at end of file diff --git a/noms/__init__.py b/noms/__init__.py index 6939193..da1bf0a 100644 --- a/noms/__init__.py +++ b/noms/__init__.py @@ -9,4 +9,9 @@ # csv reports from noms.report import export_report, report -from noms.objects.nutrient_dict import index_from_name \ No newline at end of file +# nutrient dict +from noms.objects.nutrient_dict import index_from_name +from noms.objects.nutrient_dict import nutrient_dict + +# recommendation method +from noms.analyze import generate_recommendations \ No newline at end of file diff --git a/noms/analyze.py b/noms/analyze.py index 2bd6768..a6656de 100644 --- a/noms/analyze.py +++ b/noms/analyze.py @@ -82,7 +82,7 @@ def scaled_loss(k, *args): """ return (scaled_loss(sol.x[0], required_normed_nutrients, suggestion, nutrient_dict), sol.x[0]) -def generate_recommendations(meal, pantry, nutrient_dict, n): +def generate_recommendations(meal, pantry, nutrient_dict, n, verbose=False): """ Gives the top n food recommendations to satisfy daily nutrition in context of the current foods, available foods, and a nutrient_dict full @@ -103,7 +103,8 @@ def generate_recommendations(meal, pantry, nutrient_dict, n): rec_index = rec_i rec_optimum = sug_obj[1] rec_data.append([copy.copy(cur_loss), copy.copy(rec_i), copy.deepcopy(sug_obj[1])]) - print(pantry[rec_i].desc['name'], cur_loss) - print("^" * 50) + if verbose: + print(pantry[rec_i].desc['name'], cur_loss) + print("^" * 50) rec_data.sort(key=lambda x: x[0]) return rec_data[:n] \ No newline at end of file diff --git a/test.py b/test.py index f7eb7a5..1ba9789 100644 --- a/test.py +++ b/test.py @@ -6,12 +6,12 @@ def _test(): # Test Search print(client.search_query("Raw Broccoli")) - print(client.search_query("Cola")) + print(client.search_query("Brown Rice")) # Test Search With No Results print(client.search_query("Unicorn meat")) # Test Food (last id in dict is not a food and doesn't return anything) - food_list = client.get_foods({'11090':100, '14400':100, '09120319':100}) + food_list = client.get_foods({'11090':100, '20041':500, '09120319':100}) m = noms.Meal(food_list) # Test Report @@ -54,15 +54,14 @@ def _test(): "09201":100, # oranges "09132":100, # grapes # PROCESSED - "21250":100, # hamburger, 6 oz - "21272":100, # pizza (2 slices) + "21250":100, # hamburger + "21272":100, # pizza "19088":100, # ice cream - "19057":100, # doritos (25) "18249":100, # donut # DRINK "14400":100, # coke "14429":100, # tap water - "14433":100, # aquafina bottled water + "14433":100, # bottled water "09206":100, # orange juice "14278":100, # brewed green tea "14209":100, # coffee brewed with tap water @@ -97,7 +96,6 @@ def _test(): # OTHER "04053":100, # olive oil "19904":100, # dark chocolate - "14058":100, # protein powder isolate "11238":100, # shiitake mushrooms "19165":100, # cocoa powder } @@ -105,6 +103,14 @@ def _test(): P = noms.Meal(pantry_food) for f in P.foods: print(f.desc["name"]) + + # Test recommendations + recommendations = noms.generate_recommendations(m, pantry_food, noms.nutrient_dict, 3) + for rec in recommendations: + # a recommendation is a list containing the calculated loss after the recommendation + # is applied, the index of the pantry for the recommendation, and the amount of that + # food / 100g + print(str(round(rec[2] * 100, 2)) + "g", "of", pantry_food[rec[1]].desc["name"]) if __name__ == "__main__": _test() \ No newline at end of file