В один прекрасный день я сидел и прикидывал в голове, сколько и чего надо съесть, чтобы получилось 30 гр. белка, 25 гр. жиров и 60 гр. углеводов. Из продуктов у меня были: гречка, яйца и авокадо.

Json (БЖУ указанно на 100 гр. сырого продукта):

{"Гречка": {"Белки": 11.7, "Жиры": 2.7, "Углеводы": 75}, "Яйца": {"Белки": 12.7, "Жиры": 11.5, "Углеводы": 0.7}, "Авокадо": {"Белки": 2, "Жиры": 15, "Углеводы": 9}}

Если вы программист, возможно, вам будет интересно остановиться на чтении и прикинуть, как бы вы ее решали. Статья рассказывает об одном из способов.

С чего все началось

Раньше я считал БЖУ просто в голове или в экселе,  подгоняя плюс-минус. Но тут думаю, а возьму, накидаю скриптик по-быстрому. Начал прикидывать, как это реализовать, и первое, что пришло в голову - взять алгоритм с Задачей о рюкзаке, но уже через пару минут понял, что это не то. Дальше один хороший человек подсказал попробовать матрицы (это был не Морфиус). Мне показалось это прикольным способом, но пришлось вспоминать линейную алгебру. Вроде бы я не далеко жил от школы, но изрядно забыл и жил с математикой как в анекдоте:

Математика спрашивают:

- Ну и чем вам эта ваша математика помогла в реальной жизни?

- Как чем?! Один раз я уронил ключ в канализационный люк. Так сделал из проволоки крючок в форме ИНТЕГРАЛА и ключ достал.

Язык до матрицы доведет

В этой часте статьи без всяких программ, просто руками и матрицами попробуем посчитать соотношение, сколько каких продуктов надо съесть, чтобы получить 30 гр. белка, 25 гр. жиров и 60 гр. углеводов.

Наш json с шапки статьи можно записать в виде вот такой матрицы

Обратная матрица

Следующим шагом надо вычислить обратную матрицу, для этого рассчитываем главный определитель:

∆=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 - алгебраические дополнения.

Транспонированная матрица будет иметь следующий вид:

Найдем алгебраические дополнения матрицы AT

Наша искомая обратная матрица получилась равной следующим значениям:

Умножение матриц

Теперь то, что мы хотим получить (30 гр. белка, 25 гр. жиров и 60 гр. углеводов.), надо умножить на нашу обратную матрицу.

Ура! Вот эти числа 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 и т.д.

В базе есть какое-то кол-во российских продуктов, хотя я бы еще как-то проверял эти данные. Вот, например, макароны ввели, но с ошибкой в углеводах.

Комментарии (18)


  1. EVolans
    12.09.2021 15:55

    Все гораздо проще, идешь в свой магазин и сморишь там белки, и да если это какой нибудь магнит то работает, только на сырые продукты вроде грудки или овощей.
    А дальше все становиться гораздо проще. На что денег хватает хоть как нибудь восполнить раицон желательно не углеводам так и круче.
    Остаются по итогу крупы, и то часть, яйца, курица или индейках, или рульки на борщик, тушеная капуста и другие овощи.

    Считать это бесполезно, достаточно 1 раз прочитать и посчитать свою норму плюс минус.
    Основное это надо пойти купить продуктов и посмотреть что тебе нравиться употреблять и сколько времени можешь уделить на приготовления и как часто (вроде 5л кастрлюли борщика на 6 дней)

    Это я писал как пьющий человек имеющий бюджет 8-10к на еду. Конечно если бюджет больше, то там можно разбавить и зеленью и рыблой и чем угодно вкусным, а считать там особенно гечего) Белков перекушать очень сложно.


    1. rizhenkov
      13.09.2021 13:09

      Не пью. С женой питаемся разнообразно и стараемся, чтобы было вкусно и полезно. Покупаем продукты без глубокой переработки, овощи, фрукты, мясо (кроме свинины) и рыбу (в т.ч. красную). Уходит на двоих около 300-350$ в месяц. То есть в расчёте на одного человека это практически ваш бюджет.


      1. lair
        12.09.2021 17:06
        +1

        Знаете, когда вы сказали СЛАУ, я, кажется, и так все понял.


        Но автору бы не мешало выписать свою задачу в виде системы, тогда бы было понятно, откуда весь сыр-бор.


        1. hint000
          18.09.2021 22:12

          Если действительно интересно, сыр-бор отсюда https://qna.habr.com/q/1037266


  1. lair
    12.09.2021 16:02
    +2

    Если вы не поняли, то я не виноват.

    Да нет, вы как раз и виноваты. Я нигде в вашем посте не вижу объяснения, почему эти операции над матрицей (как раз как их проводить — понятно) дают нужный ответ.


  1. anonymous
    00.00.0000 00:00


  1. Melaeg
    12.09.2021 16:27
    +1

    Кто-то помимо меня еще увидел "бананового" паука на КДПВ в правом верхнем углу?


  1. lgorSL
    12.09.2021 17:04

    Было бы интереснее взять неквадратную матрицу (например, 5 продуктов, матрица 5x3), найти пространство решений и поискать среди них те, которые с неотрицательными количествами продуктов. И, возможно, в критерии выбора добавить "квантование" продуктов типа яиц какими-то количествами - никто не будет готовить "треть яйца".


    1. AmartelRU
      12.09.2021 17:33
      +1

      Выше уже вспомнили про СЛАУ, Вы добавили неотрицательность решений, целочисленность и произвольную размерность матрицы.

      Осталось ввести какой-нибудь критерий вроде минимальной стоимости набора продуктов в качестве целевой функции и решить получившуюся задачу целочисленного линейного программирования (например, использовать intlinprog в Matlab).

      У автора, конечно, всё как-то наивно. Хочешь четвёртый продукт - вводи к белкам, жирам и углеводам ещё какой-нибудь витамин А, иначе не получается квадратная матрица. Решение системы может получиться отрицательным - и будь добр, выплёвывай продукты обратно. А ведь ещё матрица может оказаться вырожденной и обратная просто не будет существовать.


      1. pcdesign Автор
        13.09.2021 13:54

        А ведь ещё матрица может оказаться вырожденной и обратная просто не будет существовать

        Но и в реальной жизни тоже самое. Нельзя взять яблоки, груши и киви и попытаться получить БЖУ 20/20/60 - никак не получиться, сколько там не комбинируй.


  1. rafuck
    12.09.2021 17:35
    +1

    А что делать, если количество продуктов не равно трем?
    Я всегда буду обновлять комментарии…


  1. me21
    13.09.2021 11:39
    +2

    А теперь ещё добавьте витамины, минералы, клетчатку, ведь БЖУ - это ещё не всё ;-)


  1. rizhenkov
    13.09.2021 13:05

    Интересно, насколько было бы реально добавить в рассчёты сочетания вкусов продуктов и изменение свойств при термообработке. Чтобы создать некую нелинейную систему рекомендаций в виде веб-приложения. Этакая кулинарная книга, которая предлагает тебе на выбор идеи "что приготовить" из заданного набора, чтоб было полезно и вкусно.


    1. pcdesign Автор
      13.09.2021 13:15

      Вот в этой базе usda, я у них там видел учет денатурации при термообработке, его можно прикрутить. На счет остального это я не знаю как надо заморочится ))


  1. Ilias
    17.09.2021 20:42

    Ну это совсем простая версия. По идее надо бы комбинировать требования типа "х грамм белка на кг массы", "белки должны составлять у% от всех калорий" и "всего надо есть z калорий в день". И то же самое про жиры и углеводы.


    1. pcdesign Автор
      18.09.2021 09:53

      У вас есть какой-нибудь код с реализацией? Или это абстрактные рассуждения?


      1. Ilias
        18.09.2021 10:03

        Нет, это то, про что я думал, что надо бы сделать самому.


        1. pcdesign Автор
          18.09.2021 10:08

          Поделитесь, пожалуйста, если что-нибудь получится.