目 录CONTENT

文章目录

用时5坤时,我用gpt4-code-interpreter写了一个饲料配方优化算法

慧行说
2023-07-19 / 4 评论 / 0 点赞 / 901 阅读 / 1,671 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-09-06,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

code interpreter上线好几周了,其实上线第一天我就迫不及待使用了起来,是真的香,只是最近一直太忙没时间写code-interpreter的分享,直到今天项目告一段落,才有时间分享下我使用code-interpreter的体会。

最近参与了一个项目,就是如何用最优的成本计算出一个饲料配方。在动物养殖业中,制定出营养均衡,成本合理的饲料配方至关重要。然而,手动计算饲料配方不仅耗时耗力,而且容易出错。在这个背景下,我决定借助OpenAI的GPT-4代码解释器,开发一个自动优化饲料配方的算法。以下就是我如何在5坤时内完成这个项目的全过程,全程没写一句代码,纯用code interpreter帮我输出整个项目的结构跟代码。跟code interpreter沟通的全记录我也会放在本文的结尾。

首先我们确定下需求的逻辑,我们有3份输入数据:

  • 动物营养标准:确定不同动物所需要的具体营养标准;
  • 原料参数:对应原料所拥有的营养参数,以及对应的价格;
  • 参与配方原料:用于配方的原料;

有了这三份数据之后,我们通过一个函数来计算最优的饲料配比。

    def optimize(self):
        c = self.feed.feeds['Cost'].values
        A = -self.feed.feeds[['crude_protein_percentage', 'calcium_percentage', 'available_phosphorus_percentage', 'available_lysine_percentage', 'available_methionine_percentage', 'available_methionine_cystine_percentage', 'available_threonine_percentage', 'available_tryptophan_percentage']].values.T
        b = -self.animal.nutrients[['crude_protein_percentage', 'calcium_percentage', 'available_phosphorus_percentage', 'available_lysine_percentage', 'available_methionine_percentage', 'available_methionine_cystine_percentage', 'available_threonine_percentage', 'available_tryptophan_percentage']].values[0]
        bounds = [(0, None)] * len(self.feed.feeds)
        res = linprog(c, A_ub=A, b_ub=b, bounds=bounds, method='simplex')

这部分核心代码解释如下:

  1. c = self.feed.feeds['Cost'].values 这行代码是获取每种饲料的成本,用于后续的最小化成本的目标函数。
  2. A = -self.feed.feeds[nutrient_columns].values.T 这行代码是获取每种饲料中每种营养素的含量。注意这里取负值是因为 linprog 函数默认求解的是小于等于约束,而我们的需求是所有饲料中营养素的总和需要大于等于动物的营养需求。
  3. b = -self.animal.nutrients[nutrient_columns].values[0] 这行代码是获取动物的营养需求。同样地,这里也取负值是为了匹配 linprog 函数的约束条件。
  4. bounds 是一个包含了每种饲料比例的最小值和最大值的列表。这些边界值用于保证求解出的饲料比例在合理范围内。
  5. res = linprog(c, A_ub=A, b_ub=b, bounds=bounds, method='simplex') 这行代码是调用线性规划函数 linprog 来求解最优饲料配方。c 是目标函数系数,A_ubb_ub 分别是不等式约束条件的系数矩阵和常数向量,bounds 是每种饲料比例的边界,method='simplex' 是指定使用单纯形法来求解。
  6. linprog 函数会返回一个优化结果对象 res,我们可以通过 res.x 来获取最优解,即每种饲料的最优比例。如果优化过程没有成功(例如因为没有找到满足所有约束的解),那么 res.success 将为 False,这时我们会抛出一个运行时错误。

逻辑确定之后直接通过code interpreter进行沟通,通过逐步引导,最终为我输出了结论,并且计算完成了。

image-20230719160153917

下面是整体的代码:

diet_optimizer.py

# Filename: diet_optimizer.py

import json
import pandas as pd
from scipy.optimize import linprog


class Animal:
    def __init__(self, nutrients):
        self.nutrients = pd.DataFrame(nutrients, index=[0])

    @classmethod
    def from_json(cls, filepath, phase):
        with open(filepath, 'r') as f:
            data = json.load(f)
        nutrients = data['nutrition_standards_growth_phases']['standards'][phase]
        return cls(nutrients)


class Feed:
    def __init__(self, feeds):
        self.feeds = pd.DataFrame(feeds)
        self.feeds.rename(columns={'unit_price': 'Cost'}, inplace=True)
        # Drop the rows where 'Cost' is NaN
        self.feeds.dropna(subset=['Cost'], inplace=True)
        # Replace NaN values in nutrient columns with 0
        nutrient_columns = ['crude_protein_percentage', 'calcium_percentage', 'available_phosphorus_percentage', 'available_lysine_percentage', 'available_methionine_percentage', 'available_methionine_cystine_percentage', 'available_threonine_percentage', 'available_tryptophan_percentage']
        self.feeds[nutrient_columns] = self.feeds[nutrient_columns].fillna(0)

    @classmethod
    def from_json(cls, filepath):
        with open(filepath, 'r') as f:
            data = json.load(f)
        feeds = data['raw_materials']
        return cls(feeds)


class DietOptimizer:
    def __init__(self, animal, feed):
        self.animal = animal
        self.feed = feed

    def optimize(self):
        c = self.feed.feeds['Cost'].values
        A = -self.feed.feeds[['crude_protein_percentage', 'calcium_percentage', 'available_phosphorus_percentage', 'available_lysine_percentage', 'available_methionine_percentage', 'available_methionine_cystine_percentage', 'available_threonine_percentage', 'available_tryptophan_percentage']].values.T
        b = -self.animal.nutrients[['crude_protein_percentage', 'calcium_percentage', 'available_phosphorus_percentage', 'available_lysine_percentage', 'available_methionine_percentage', 'available_methionine_cystine_percentage', 'available_threonine_percentage', 'available_tryptophan_percentage']].values[0]
        bounds = [(0, None)] * len(self.feed.feeds)
        res = linprog(c, A_ub=A, b_ub=b, bounds=bounds, method='simplex')

        # Convert the optimal amounts to proportions and then to percentages
        optimal_proportions = 100 * res.x / res.x.sum()
        min_cost_per_unit = (res.x * self.feed.feeds['Cost']).sum()

        return res.x, optimal_proportions, min_cost_per_unit

    def calculate_nutrient_totals(self, amounts):
        nutrient_columns = ['crude_protein_percentage', 'calcium_percentage', 'available_phosphorus_percentage',
                            'available_lysine_percentage', 'available_methionine_percentage',
                            'available_methionine_cystine_percentage', 'available_threonine_percentage',
                            'available_tryptophan_percentage']
        # Reshape amounts to a 2D array
        amounts_2d = amounts.reshape(-1, 1)
        nutrient_totals = (amounts_2d * self.feed.feeds[nutrient_columns].values).sum(axis=0)
        return pd.Series(nutrient_totals, index=nutrient_columns)

main.py

# Filename: main.py

from diet_optimizer import Animal, Feed, DietOptimizer

def main():
    # Specify the nutrition requirement phase
    phase = 'nursery_phase_1'

    # Load data from JSON files
    animal = Animal.from_json('json/animal_nutrition.json', phase)
    feed = Feed.from_json('json/feed_nutrition.json')

    # Create a diet optimizer
    optimizer = DietOptimizer(animal, feed)

    # Optimize the diet
    optimal_amounts, optimal_proportions, min_cost_per_unit = optimizer.optimize()

    # Calculate the total nutrients in the optimal diet
    nutrient_totals = optimizer.calculate_nutrient_totals(optimal_amounts)

    # Print the results
    print('最优的饲料配方比例和单位内的最低成本如下:')
    for feed_name, proportion in zip(feed.feeds['material_name'], optimal_proportions):
        # Only print the feed name and proportion if the proportion is not 0
        if proportion > 0:
            print(f'{feed_name}:{proportion:.2f}%')
    print(f'单位内的最低成本是 {min_cost_per_unit:.2f}(元/千克)')

    print('\n最优饲料配方中的营养总量如下:')
    print(nutrient_totals)

if __name__ == '__main__':
    main()

执行主程序输出如下,基本实现了配方比例优化。
image-20230719160500670

0

评论区