![](https://habrastorage.org/getpro/habr/upload_files/f7b/855/c83/f7b855c8303b7028b4bd1d9c32b30451.jpg)
В один прекрасный день я сидел и прикидывал в голове, сколько и чего надо съесть, чтобы получилось 30 гр. белка, 25 гр. жиров и 60 гр. углеводов. Из продуктов у меня были: гречка, яйца и авокадо.
Json (БЖУ указанно на 100 гр. сырого продукта):
{"Гречка": {"Белки": 11.7, "Жиры": 2.7, "Углеводы": 75}, "Яйца": {"Белки": 12.7, "Жиры": 11.5, "Углеводы": 0.7}, "Авокадо": {"Белки": 2, "Жиры": 15, "Углеводы": 9}}
Если вы программист, возможно, вам будет интересно остановиться на чтении и прикинуть, как бы вы ее решали. Статья рассказывает об одном из способов.
![](https://habrastorage.org/getpro/habr/upload_files/216/f7f/976/216f7f9763dc74caca1c669591c52eb5.jpg)
С чего все началось
Раньше я считал БЖУ просто в голове или в экселе, подгоняя плюс-минус. Но тут думаю, а возьму, накидаю скриптик по-быстрому. Начал прикидывать, как это реализовать, и первое, что пришло в голову - взять алгоритм с Задачей о рюкзаке, но уже через пару минут понял, что это не то. Дальше один хороший человек подсказал попробовать матрицы (это был не Морфиус). Мне показалось это прикольным способом, но пришлось вспоминать линейную алгебру. Вроде бы я не далеко жил от школы, но изрядно забыл и жил с математикой как в анекдоте:
Математика спрашивают:
- Ну и чем вам эта ваша математика помогла в реальной жизни?
- Как чем?! Один раз я уронил ключ в канализационный люк. Так сделал из проволоки крючок в форме ИНТЕГРАЛА и ключ достал.
Язык до матрицы доведет
В этой часте статьи без всяких программ, просто руками и матрицами попробуем посчитать соотношение, сколько каких продуктов надо съесть, чтобы получить 30 гр. белка, 25 гр. жиров и 60 гр. углеводов.
Наш json с шапки статьи можно записать в виде вот такой матрицы
![](https://habrastorage.org/getpro/habr/upload_files/956/12a/0a4/95612a0a4fe24d995c32446a77daf22f.png)
Обратная матрица
Следующим шагом надо вычислить обратную матрицу, для этого рассчитываем главный определитель:
∆=11.7*(11.5*9 - 15*0.7) - 12.7*(2.7*9 - 15*75) + 2*(2.7*0.7 - 11.5*75) = 13345.77
Обратную матрицу получим по вот такой формуле, где Aij - алгебраические дополнения.
![](https://habrastorage.org/getpro/habr/upload_files/6a4/5ad/c0a/6a45adc0a6fc0b8eae9fbad394375b4e.png)
Транспонированная матрица будет иметь следующий вид:
![](https://habrastorage.org/getpro/habr/upload_files/8ed/043/352/8ed043352a0238cfcf57b4634302a66e.png)
Найдем алгебраические дополнения матрицы AT
![](https://habrastorage.org/getpro/habr/upload_files/188/273/991/188273991e05b0f325664c13a4ef8f30.png)
Наша искомая обратная матрица получилась равной следующим значениям:
![](https://habrastorage.org/getpro/habr/upload_files/69f/d10/2d3/69fd102d3b163f5a2de0ec6e46ed88d3.png)
Умножение матриц
Теперь то, что мы хотим получить (30 гр. белка, 25 гр. жиров и 60 гр. углеводов.), надо умножить на нашу обратную матрицу.
![](https://habrastorage.org/getpro/habr/upload_files/7d0/76a/1ea/7d076a1ea892b327b4aae25138713654.png)
Ура! Вот эти числа 0.78, 1.6 и 0.31 нам и нужны! Если их умножить на 100 грамм, то получится, что надо съесть:
78 грамм гречки, 160 грамм яиц и 31 грамм авокадо
Как говорил один профессор в институте:
- Как это вы не поняли?! Уже даже я все понял!
Полный код на Python
Код для python я чуть-чуть усложнил, добавил не три продукта, а еще вставил оливковое масло, и добавил возможность вставить любое кол-во продуктов и заставил искать комбинации из троек.
pip install numpy
Полный код. Вставляйте в файл и запускайте:
from itertools import combinations
import numpy as np
# Сами продукты, чем больше ввести тем больше вероятность,
# того, что найдутся нужные комбинации
data = {"Гречка": {"Белки": 11.7, "Жиры": 2.7, "Углеводы": 75},
"Яйца": {"Белки": 12.7, "Жиры": 11.5, "Углеводы": 0.7},
"Авокадо": {"Белки": 2, "Жиры": 15, "Углеводы": 9},
"Оливковое масло": {"Белки": 0, "Жиры": 99.8, "Углеводы": 0},
}
# Макронутриенты (БЖУ), которые нужно получить
neaded = [30, 25, 60]
def get_gramms(data, neaded):
results = []
# Разбиваем на всевозможные комбинации по 3 шт.
for comb in combinations(data.keys(), 3):
meals = [list(data[a].values()) for a in comb]
# Инициация матрицы
m = np.matrix(meals)
# Обратная матрица
try:
m_inverse = np.linalg.inv(m)
except np.linalg.LinAlgError:
continue
need = np.array(neaded)
# Умножаем матрицу
res = need.dot(m_inverse)
if np.all(res > 0):
# Отсекаем результаты с отрицательными значениями
# Ведь нельзя съесть минус -20 гр. гречки
res_list = res.tolist()[0]
res_dict = {name: f'{int(100*res_list[i])} гр.'
for i, name in enumerate(comb)}
results.append(res_dict)
return results
print(get_gramms(data, neaded))
Результат работы программы:
[{'Гречка': '75 гр.', 'Яйца': '162 гр.', 'Авокадо': '28 гр.'},
{'Гречка': '78 гр.', 'Яйца': '163 гр.', 'Оливковое масло': '4 гр.'}]
Выдала два варианта. Либо надо съесть гречку 75гр., яйца 162 гр., авокадо 28 гр. Ну, либо гречка 78 гр., яйца 163 гр. и 4 гр. оливкового масла. Любопытно, что компьютер выдал немного другие веса хотя и не принципиально, они чуть-чуть отличаются от того что мы получили, когда считали руками. Я глубоко не копал, но для интереса надо будет как-нибудь разобраться.
Код на github:
https://github.com/Alexmod/macronutrients
P.S. На выходных мне было скучно. Вот я и накидал все это, и конечно же ни о каком совершенстве речь не идет. Но решил поделится моими потугами вспомнить математику.
Всякое разное про макронутриенты
Рекомендации по белку
Европейская ассоциация безопасности пищевых продуктов (EFSA) установила Контрольное потребление белка населением (PRI) на уровне 0,83 грамма на килограмм массы тела
В Рекомендациях по питанию северных стран (NNR) количество белка колеблется от 0,80 до 0,83 г на килограмм массы тела как для мужчин, так и для женщин со скромным уровнем физической активности.
Всемирная организация здравоохранения (ВОЗ) устанавливает Безопасный уровень потребления белка (SLP) на уровне 0,83 г на килограмм в день
Источник информации
WHO/ FAO/ UNU (2007) World Health Organization/ Food and Agriculture Organization/ United Nations University, Protein and amino acid requirements in human nutrition; Report of a joint FAO/WHO/UNU Expert Consultation Technical Report Series No 935. WHO, Geneva (2007)
Это, скажем так, сколько нужно потреблять для здоровья человеку в среднем без спорта и при низкой физической активности. Для занимающихся силовыми видами спорта рекомендуют от 1 до 2.5 гр. белка на вес тела, но рекомендации эти исходят уже не от ВОЗ, а от тренеров и нутрициологов, поэтому здесь такой разброс значений.
Рекомендации по жирам
ВОЗ рекомендует ограничить потребление жиров в пределах 30% ежедневного потребления энергии, при этом на насыщенные жиры должно приходиться менее 10%.
Рекомендации по углеводам
С "углями" все не просто, ведь и сахар, и апельсин, и гречка по большому счету углеводы. Поэтому невозможно дать какую-то простую унифицированную формулу. И есть отдельные рекомендации, сколько там должно быть фруктозы, сколько глюкозы рекомендует ВОЗ и т.д. Углеводы - это ключ к управлению весом тела, так что урезая или добавляя, или изменяя пропорции простых и сложных углеводов и трансформируют свое тело в зависимости от стоящей задачи. И эта тема для отдельной громадной статьи, которую и писать надо не такому дилетанту как я.
Про калории
Если вы знаете БЖУ, то калорийность вы можете получить в любой момент вот по такой формуле:
1 г белка дает организму - 4.1 ккал
1 г жира - 9.29 к. ккал
1 г. углеводов - 4.1 к. ккал
https://ru.wikipedia.org/wiki/Пищевая_энергетическая_ценность
БЖУ с шапки статьи мы можем пересчитать в килокалории:
30 гр. белка *4.1 + 25 гр. жиров * 9.29 + 60 гр углеводов * 4.1 = 601 ккал.
Читал когда-то о таком исследовании. Взяли две группы обезьян. Обе группы получали одинаковое количество калорий. Одну группы кормили правильным сбалансированным питанием с нужными макронутриентами, другую группу кормили всякими сластешками (тортиками и конфетками). После взвешивания оказалось, что группа, которая ела "мусорную" (как говорят нутрициологи) еду из сладостей, поправилась, а группа с правильным рационом осталась при своем весе, хотя калории были одинаковыми.
База данных продуктов
У американцев есть официальная База данных продуктов питания (USDA) (англ. USDA National Nutrient Database), созданная Министерством сельского хозяйства США.
База данных содержит несколько разделов: описание пищи, пищевой ценности, вес и размеры, примечания, источники данных. Всего 25 пищевых групп. Замеряются: пищевая ценность, липиды, влажность, углеводы, энергия, минералы, аскорбиновая кислота, тиамин, определённые витамины, протеин, фолиевая кислота, холин, жирные кислоты, холестерин, аминокислоты, вес и размеры и прочее.
API к USDA
Получить ключ можно здесь
И там сразу же будет предложен пример с запросом инфы о яблоке:
https://api.nal.usda.gov/fdc/v1/foods/search?query=apple&pageSize=2&api_key=ВАШ_КЛЮЧ
Ответ на запрос
{"totalHits":21874,"currentPage":1,"totalPages":10937,"pageList":[1,2,3,4,5,6,7,8,9,10],"foodSearchCriteria":{"query":"apple","generalSearchInput":"apple","pageNumber":1,"numberOfResultsPerPage":50,"pageSize":2,"requireAllWords":false},"foods":[{"fdcId":1648210,"description":"APPLE","lowercaseDescription":"apple","dataType":"Branded","gtinUpc":"070038322238","publishedDate":"2021-03-19","brandOwner":"Associated Wholesale Grocers, Inc.","brandName":"BEST CHOICE","ingredients":"FILTERED WATER, APPLE JUICE CONCENTRATE, ASCORBIC ACID (VITAMIN C).","marketCountry":"United States","foodCategory":"Fruit & Vegetable Juice, Nectars & Fruit Drinks","allHighlightFields":"<b>Ingredients</b>: FILTERED WATER, <em>APPLE</em> JUICE CONCENTRATE, ASCORBIC ACID (VITAMIN C).","score":904.62524,"foodNutrients":[{"nutrientId":1003,"nutrientName":"Protein","nutrientNumber":"203","unitName":"G","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":0.0},{"nutrientId":1004,"nutrientName":"Total lipid (fat)","nutrientNumber":"204","unitName":"G","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":0.0},{"nutrientId":1005,"nutrientName":"Carbohydrate, by difference","nutrientNumber":"205","unitName":"G","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":11.7},{"nutrientId":1008,"nutrientName":"Energy","nutrientNumber":"208","unitName":"KCAL","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":46.0},{"nutrientId":2000,"nutrientName":"Sugars, total including NLEA","nutrientNumber":"269","unitName":"G","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":11.7},{"nutrientId":1093,"nutrientName":"Sodium, Na","nutrientNumber":"307","unitName":"MG","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":15.0},{"nutrientId":1162,"nutrientName":"Vitamin C, total ascorbic acid","nutrientNumber":"401","unitName":"MG","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":32.5}]},{"fdcId":1662719,"description":"APPLE","lowercaseDescription":"apple","dataType":"Branded","gtinUpc":"887434010245","publishedDate":"2021-03-19","brandOwner":"Oneonta Trading Corporation","brandName":"PINK LADY","ingredients":"","marketCountry":"United States","foodCategory":"Pre-Packaged Fruit & Vegetables","allHighlightFields":"","score":904.62524,"foodNutrients":[{"nutrientId":1003,"nutrientName":"Protein","nutrientNumber":"203","unitName":"G","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":0.41},{"nutrientId":1004,"nutrientName":"Total lipid (fat)","nutrientNumber":"204","unitName":"G","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":0.0},{"nutrientId":1005,"nutrientName":"Carbohydrate, by difference","nutrientNumber":"205","unitName":"G","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":14.0},{"nutrientId":1008,"nutrientName":"Energy","nutrientNumber":"208","unitName":"KCAL","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":54.0},{"nutrientId":2000,"nutrientName":"Sugars, total including NLEA","nutrientNumber":"269","unitName":"G","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":10.3},{"nutrientId":1079,"nutrientName":"Fiber, total dietary","nutrientNumber":"291","unitName":"G","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":2.1},{"nutrientId":1087,"nutrientName":"Calcium, Ca","nutrientNumber":"301","unitName":"MG","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":8.0},{"nutrientId":1089,"nutrientName":"Iron, Fe","nutrientNumber":"303","unitName":"MG","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":0.15},{"nutrientId":1092,"nutrientName":"Potassium, K","nutrientNumber":"306","unitName":"MG","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":107},{"nutrientId":1093,"nutrientName":"Sodium, Na","nutrientNumber":"307","unitName":"MG","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":0.0},{"nutrientId":1104,"nutrientName":"Vitamin A, IU","nutrientNumber":"318","unitName":"IU","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":41.0},{"nutrientId":1162,"nutrientName":"Vitamin C, total ascorbic acid","nutrientNumber":"401","unitName":"MG","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":2.0},{"nutrientId":1253,"nutrientName":"Cholesterol","nutrientNumber":"601","unitName":"MG","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":0.0},{"nutrientId":1257,"nutrientName":"Fatty acids, total trans","nutrientNumber":"605","unitName":"G","derivationCode":"LCCS","derivationDescription":"Calculated from value per serving size measure","value":0.0},{"nutrientId":1258,"nutrientName":"Fatty acids, total saturated","nutrientNumber":"606","unitName":"G","derivationCode":"LCCD","derivationDescription":"Calculated from a daily value percentage per serving size measure","value":0.0}]}],"aggregations":{"dataType":{"Branded":21699,"SR Legacy":89,"Survey (FNDDS)":81,"Foundation":5},"nutrients":{}}}
USDA SQLite
Энтузиасты создали sqlite базу. Возможно для кого-то удобнее будет работать с ней, чем с API
https://github.com/alyssaq/usda-sqlite
Хоть база давно и не обновлялась, это не имеет значение, т.к. БЖУ перловки и 10 лет назад и сейчас одинаковое. В usda добавляются всякие производители со своими готовыми блюдами, вряд ли они вам будут нужны.
USDA CSV || MS Access
Самую последнюю версию базы можно выкачать в csv или MS Access формате:
https://fdc.nal.usda.gov/download-datasets.html
Еще база продуктов
Open Food Facts создан некоммерческой ассоциацией, каждый может туда добавлять продукты:
https://world.openfoodfacts.org/data
Тоже есть API, и есть возможность скачать дамп MongoDB, csv, json и т.д.
В базе есть какое-то кол-во российских продуктов, хотя я бы еще как-то проверял эти данные. Вот, например, макароны ввели, но с ошибкой в углеводах.