Maison > Article > développement back-end > Suivi de la santé avec l'ingénierie des données - Optimisation des repas de chapitre
Bonjour à tous ! Ce sera mon premier message alors soyez dur avec moi, critiquez-moi là où vous pensez que je peux m'améliorer et j'en tiendrai sûrement compte la prochaine fois.
Au cours des derniers mois, j'ai été profondément préoccupé par la santé, principalement en faisant de l'exercice et en surveillant ce que je mange, et maintenant que je pense en avoir une solide maîtrise, je voulais voir comment je peux optimiser davantage dans le cas où il y a certaines choses que j'aurais pu manquer.
Pour ce chapitre, je souhaite étudier mes repas tout au long de mon parcours de santé et conclure avec un plan de repas pour la semaine prochaine qui (1) atteint mes besoins minimum en protéines, (2) ne dépasse pas ma limite calorique, (3) répond à mes besoins minimum en fibres et (4) minimise les coûts.
Nous commençons par présenter l'ensemble de données, les aliments que nous avons suivis à l'aide de Cronometer. Cronometer a travaillé à mes côtés tout au long de mon parcours et maintenant, je vais exporter les données que j'ai saisies pour les analyser moi-même avec les objectifs que j'ai précédemment énumérés.
Heureusement pour moi, Cronometer me permet d'exporter facilement des données vers un fichier .csv sur leur site Web.
Pour ce chapitre, nous exporterons uniquement l'ensemble de données « Entrées d'aliments et de recettes ».
Nous commençons par examiner les données que nous avons obtenues des « Entrées d'aliments et de recettes ». L'ensemble de données est très complet, ce qui, j'en suis sûr, sera formidable pour les prochains chapitres ! Dans ce chapitre, nous souhaitons le limiter au nom de l'aliment, à sa quantité, à ses protéines, à ses calories et à ses fibres.
# Importing and checking out the dataset df = pd.read_csv("servings.csv") df.head()
Nous avons déjà quelques colonnes définies pour nous, dans « Nom de l'aliment », « Quantité », « Énergie (kcal) », « Fibres (g) » et « Protéines (g) ». Parfait! Maintenant, la seule chose qui nous manque est d'obtenir le coût de chaque aliment en fonction d'une certaine quantité, car il n'était pas suivi dans l'ensemble de données. Heureusement pour moi, c'est moi qui ai saisi les données en premier lieu afin de pouvoir saisir les prix que je connais. Cependant, je ne saisirai pas les prix de tous les produits alimentaires. Au lieu de cela, nous demandons à notre bon vieil ami ChatGPT son estimation et remplissons les prix que nous connaissons en peaufinant le fichier .csv. Nous stockons le nouvel ensemble de données dans « cost.csv », que nous avons dérivé en prenant les colonnes « Nom de l'aliment » et « Quantité » de l'ensemble de données d'origine.
# Group by 'Food Name' and collect unique 'Amount' for each group grouped_df = df.groupby('Food Name')['Amount'].unique().reset_index() # Expand the DataFrame so each unique 'Food Name' and 'Amount' is on a separate row expanded_df = grouped_df.explode('Amount') # Export the DataFrame to a CSV file expanded_df.to_csv('grouped_food_names_amounts.csv') # Read the added costs and save as a new DataFrame df_cost = pd.read_csv("cost.csv").dropna() df_cost.head()
Certains aliments ont été abandonnés simplement parce qu'ils étaient trop spécifiques et n'entraient pas dans le champ d'application des données relatives à leur faible teneur en calories, à leur valeur nutritive et/ou à leur bon marché (ou simplement parce que je ne pouvais pas me donner la peine de refaire la recette). ). Nous aurions alors besoin de fusionner deux blocs de données, l'ensemble de données d'origine et celui avec le coût, afin d'obtenir l'ensemble de données supposé « final ». Étant donné que l'ensemble de données d'origine contient les entrées pour chaque aliment, cela signifie que l'ensemble de données d'origine contient plusieurs entrées du même aliment, en particulier ceux que je mange à plusieurs reprises (c'est-à-dire les œufs, la poitrine de poulet, le riz). Nous souhaitons également remplir les colonnes sans valeurs avec « 0 », car la source la plus probable de problèmes ici serait les colonnes « Énergie », « Fibres », « Protéines » et « Prix ».
merged_df = pd.merge(df, df_cost, on=['Food Name', 'Amount'], how='inner') specified_columns = ['Food Name', 'Amount', 'Energy (kcal)', 'Fiber (g)', 'Protein (g)', 'Price'] final_df = merged_df[specified_columns].drop_duplicates() final_df.fillna(0, inplace=True) final_df.head()
Parfait ! Notre jeu de données est terminé et maintenant, nous commençons par la deuxième partie, l'optimisation. Rappelant les objectifs de l'étude, nous souhaitons identifier le moindre coût étant donné une quantité minimale de protéines et de fibres, et une quantité maximale de calories. L'option ici est de forcer brutalement chaque combinaison, mais dans l'industrie, le terme approprié est « Programmation linéaire » ou « Optimisation linéaire », mais ne me citez pas là-dessus. Cette fois, nous utiliserons puLP, une bibliothèque Python destinée à faire exactement cela. Je ne sais pas grand-chose sur son utilisation à part suivre le modèle, alors parcourez leur documentation au lieu de lire mon explication non professionnelle sur son fonctionnement. Mais pour ceux qui veulent écouter mon explication informelle du sujet, nous résolvons essentiellement y = ax1 + bx2 + cx3 + ... + zxn.
Le modèle que nous suivrons est le modèle de l'étude de cas du problème de mélange, où nous suivons des objectifs similaires mais dans ce cas, nous voulons mélanger nos repas tout au long de la journée. Pour commencer, nous aurions besoin de convertir le DataFrame en dictionnaires, en particulier le « Nom de l'aliment » en tant que liste de variables indépendantes qui servent de série de x, puis l'Énergie, les Fibres, les Protéines et le Prix en tant que dictionnaire tel que « Nom de l'aliment » : valeur pour chacun. Notez que le montant sera supprimé à partir de maintenant et sera plutôt concaténé avec le « Nom de l'aliment » car nous ne l'utiliserons pas de manière quantitative.
# Concatenate Amount into Food Name final_df['Food Name'] = final_df['Food Name'] + ' ' + final_df['Amount'].astype(str) food_names = final_df['Food Name'].tolist() # Create dictionaries for 'Energy', 'Fiber', 'Protein', and 'Price' energy_dict = final_df.set_index('Food Name')['Energy (kcal)'].to_dict() fiber_dict = final_df.set_index('Food Name')['Fiber (g)'].to_dict() fiber_dict['Gardenia, High Fiber Wheat Raisin Loaf 1.00 Slice'] = 3 fiber_dict['Gardenia, High Fiber Wheat Raisin Loaf 2.00 Slice'] = 6 protein_dict = final_df.set_index('Food Name')['Protein (g)'].to_dict() price_dict = final_df.set_index('Food Name')['Price'].to_dict() # Display the results print("Food Names Array:", food_names) print("Energy Dictionary:", energy_dict) print("Fiber Dictionary:", fiber_dict) print("Protein Dictionary:", protein_dict) print("Price Dictionary:", price_dict)
For those without keen eyesight, continue scrolling. For those who did notice the eerie 2 lines of code, let me explain. I saw this while I was grocery shopping but the nutrition facts on Gardenia's High Fiber Wheat Raisin loaf do not actually have 1 slice be 9 grams of Fiber, it has 2 slices for 6 grams. This is a big deal and has caused me immeasurable pain knowing that the values may be incorrect due to either a misinput of data or a change of ingredients which caused the data to be outdated. Either way, I needed this justice corrected and I will not stand for any less Fiber than I deserve. Moving on.
We go straight into plugging in our values using the template from the Case Study data. We set variables to stand for the minimum values we want out of Protein and Fiber, as well as the maximum Calories we are willing to eat. Then, we let the magical template code do its work and get the results.
# Set variables min_protein = 120 min_fiber = 40 max_energy = 1500 # Just read the case study at https://coin-or.github.io/pulp/CaseStudies/a_blending_problem.html. They explain it way better than I ever could. prob = LpProblem("Meal Optimization", LpMinimize) food_vars = LpVariable.dicts("Food", food_names, 0) prob += ( lpSum([price_dict[i] * food_vars[i] for i in food_names]), "Total Cost of Food daily", ) prob += ( lpSum([energy_dict[i] * food_vars[i] for i in food_names]) <= max_energy, "EnergyRequirement", ) prob += ( lpSum([fiber_dict[i] * food_vars[i] for i in food_names]) >= min_fiber, "FiberRequirement", ) prob += ( lpSum([protein_dict[i] * food_vars[i] for i in food_names]) >= min_protein, "ProteinRequirement", ) prob.writeLP("MealOptimization.lp") prob.solve() print("Status:", LpStatus[prob.status]) for v in prob.variables(): if v.varValue > 0: print(v.name, "=", v.varValue) print("Total Cost of Food per day = ", value(prob.objective))
In order to get 120 grams of protein and 40 grams of fiber, I would need to spend 128 Philippine Pesos on 269 grams of chicken breast fillet, and 526 grams of mung beans. This... does not sound bad at all considering how much I love both ingredients. I will definitely try it out, maybe for a week or a month just to see how much money I would save despite having just enough nutrition.
That was it for this chapter of Tracking Health with Data Engineering, if you want to see the data I worked on in this chapter, visit the repository or visit the notebook for this page. Do leave a comment if you have any and try to stay healthy.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!