将目标函数和约束转化为代码

问题描述

很不幸,我已经尝试解决个人项目中的一个问题几个星期了。最近我从数学堆栈交换中得到了这个问题的答案的帮助:https://math.stackexchange.com/a/4089367/907708,我现在正在尝试将答案中的方程翻译成 python 代码,但我一直卡住了。

为了便于访问,我将在此处重申问题(我尝试发布答案,但格式很古怪,因此您必须参考上述答案的链接才能找到它。哎呀)

问题:

情况:我试图最小化列表中一系列不同高度的点之间的标准偏差,限制条件是列表中的每个点可以在 0 到 2 个单位的任何位置升高以最小化点之间的标准偏差。

示例:我有一个在 x 轴上等距但在 y 轴上不等距的点列表。

h = [20,24,28,20,18,32,30,24]

列表中的每个数字代表该点的高度。

我还有一个限制,即列表中的每个点都可以增加一个介于 0 到 2 之间的 c 值,以帮助实现更小的标准偏差。

我正在尝试创建一个算法来优化最小化 h 的点的标准偏差,约束条件是 h 中的每个点都可以由 0 <= c <= n 提升为任何 h具有任意值和任意 n > 0

的长度

我对优化问题非常陌生,虽然我看到过与我的问题相似的问题,但我没有看到任何我已经能够收集到足够的信息来帮助我进一步寻求答案的问题。

如果可能的话,我希望有人能帮我定义目标函数、约束和其他必要的函数,以便我找到答案。

这不是家庭作业问题,因此我没有课程材料来帮助指导我找到答案。我唯一的指导来自这篇文章评论和答案。请理解,我绝不是数学家,所以我真的需要我能得到的所有帮助。谢谢!

结束问题:

我查看了无数的 scipy.optimize 示例,试图弄清楚如何格式化我的代码以使其工作,但到目前为止我一直没有成功。我希望对这个主题有更多知识的人可以帮助我翻译这些公式,或者告诉我应该查看哪些图书馆或材料以帮助回答这个问题。 (我会发布迄今为止我尝试过的代码片段的集合,但它们都没有给我带来任何有价值的东西,我认为它们不会提供任何有价值的见解来回答问题,所以我故意省略了它们)

非常感谢您提供任何反馈,我一定会快速回复您的任何问题或评论。非常感谢!

解决方法

您可以安装PyGad。遗传算法非常适合这类优化问题。此外,恕我直言,它更容易实施。只需执行pip install pygad。下面是解决您的问题的代码。我正在使用 PyGad 的默认配置。适应度函数评估任何候选解决方案的好坏程度。由于 PyGad 尝试最大化(并且我们想要最小化),我们在适应度函数中返回 1/evaluation。我们可以通过为任何无效的候选解决方案返回 -100(不良适应度)来设置约束。我插入了数学堆栈解决方案中给出的公式并预先计算了 x_bar,即使它应该花费不到 5 秒的时间。问题特定的配置是:fitness_funcnum_genesci 值的初始猜测 (init_range_low/high)。

import pygad
import numpy as np


X = [20,24,28,20,18,32,30,24]
X_BAR = np.array(X).sum()/len(X)

def fitness_function(solution,solution_idx):
    c_bar = np.array(solution).sum()/len(solution)
    accum = 0
    for i,ci in enumerate(solution):
        if ci < 0 or ci > 2:
            return -100
        accum += (X[i] + ci - (X_BAR + c_bar))**2
    fitness = 1/accum
    return fitness


ga_instance = pygad.GA(num_generations=100,num_parents_mating=7,fitness_func=fitness_function,sol_per_pop=50,num_genes=len(X),init_range_low=0,init_range_high=2,parent_selection_type="sss",keep_parents=7,crossover_type="single_point",mutation_type="random",mutation_percent_genes=10)

ga_instance.run()
ga_instance.plot_result()

sol,sol_fitness,sol_idx = ga_instance.best_solution()
print("Parameters of the best solution : {solution}".format(solution=sol))

以下是适应度的演变:

enter image description here

最后,算法给出的解决方案是:

[1.99574728e+00 1.00786156e+00 2.17545152e-02 1.16404525e+00
 1.98465204e+00 1.98997128e+00 1.98167328e+00 1.32911147e-02
 1.17406735e-03 1.30281600e-04 1.99916130e+00 1.17383310e+00]
,

另一种使用 scipy.optimize.minimize 的解决方案:

from scipy.optimize import minimize

x = np.array([20,24])

# define the objective to minimize 
# (here c is the variable and x is a additional argument)
def obj(c,x): return np.sum((x+c -(np.mean(x) + np.mean(c)))**2)

# Variable bounds: 0 <= ci <= 2
bounds = [(0,2) for _ in range(len(x))]

# initial guess for the solver
c0 = np.ones_like(x)

# call the solver and pass a function that only depends on the variable c
res = minimize(lambda c: obj(c,x),x0=c0,bounds=bounds)

# your solution
print(res.x)

给予

array([2.,1.11111256,0.,2.,1.11111446])