【问题标题】:MLE application with gekko in python在 python 中使用 gekko 的 MLE 应用程序
【发布时间】:2021-08-24 01:18:09
【问题描述】:

我想在 python 中使用 gekko 包实现 MLE(最大似然估计)。假设我们有一个DataFrame,它包含两列:['Loss', 'Target'],它的长度等于 500。
首先我们必须导入我们需要的包:

from gekko import GEKKO
import numpy as np
import pandas as pd

然后我们像这样简单地创建DataFrame

My_DataFrame = pd.DataFrame({"Loss":np.linspace(-555.795 , 477.841 , 500) , "Target":0.0})
My_DataFrame = My_DataFrame.sort_values(by=["Loss"] , ascending=False).reset_index(drop=True)
My_DataFrame 

看起来像这样:

['Target'] 列的某些组件 应使用我在图片下方写下的公式计算(其余部分保持为零。我在继续中解释了更多信息,请继续阅读),以便您可以完美地看到它。公式的两个主要元素是“Kasi”和“Betaa”。我想为他们找到最大化My_DataFrame[‘Target’] 总和的最佳价值。所以你明白了,接下来会发生什么!

现在让我向您展示我是如何为此目的编写代码的。首先我定义我的目标函数:

def obj_function(Array):
    """
    [Purpose]:
        + it will calculate each component of My_DataFrame["Target"] column! then i can maximize sum(My_DataFrame["Target"]) and find best 'Kasi' and 'Betaa' for it!
    
    [Parameters]:
        + This function gets Array that contains 'Kasi' and 'Betaa'.
        Array[0] represents 'Kasi' and Array[1] represents 'Betaa'

    [returns]:
        + returns a pandas.series.
        actually it returns new components of My_DataFrame["Target"]
    """
    # in following code if you don't know what is `qw`, just look at the next code cell right after this cell (I mean next section).
    # in following code np.where(My_DataFrame["Loss"] == item)[0][0] is telling me the row's index of item. 
    for item in My_DataFrame[My_DataFrame["Loss"]>160]['Loss']:
        My_DataFrame.iloc[np.where(My_DataFrame["Loss"] == item)[0][0] , 1] = qw.log10((1/Array[1])*(  1 + (Array[0]*(item-160)/Array[1])**( (-1/Array[0]) - 1 )))

    return My_DataFrame["Target"]

如果您对obj_function 函数中的for loop 中发生的事情感到困惑,请查看下图,它包含一个简短的示例!如果没有,请跳过这部分:

那么我们只需要进行优化。为此,我使用gekko 包。 请注意我想找到“Kasi”和“Betaa”的最佳值,所以我有两个主要变量,我没有任何约束! 那么让我们开始吧:

# i have 2 variables : 'Kasi' and 'Betaa', so I put nd=2
nd = 2
qw = GEKKO()

# now i want to specify my variables ('Kasi'  and 'Betaa') with initial values --> Kasi = 0.7 and Betaa = 20.0
x = qw.Array(qw.Var , nd , value = [0.7 , 20])
# So i guess now x[0] represents 'Kasi' and x[1] represents 'Betaa'

qw.Maximize(np.sum(obj_function(x)))

然后当我想用qw.solve()解决优化时:

qw.solve()

但我收到了这个错误:

例外:此稳态 IMODE 只允许标量值。

我该如何解决这个问题? (为方便起见,将完整的脚本收集在下一节中)

from gekko import GEKKO
import numpy as np
import pandas as pd


My_DataFrame = pd.DataFrame({"Loss":np.linspace(-555.795 , 477.841 , 500) , "Target":0.0})
My_DataFrame = My_DataFrame.sort_values(by=["Loss"] , ascending=False).reset_index(drop=True)

def obj_function(Array):
    """
    [Purpose]:
        + it will calculate each component of My_DataFrame["Target"] column! then i can maximize sum(My_DataFrame["Target"]) and find best 'Kasi' and 'Betaa' for it!
    
    [Parameters]:
        + This function gets Array that contains 'Kasi' and 'Betaa'.
        Array[0] represents 'Kasi' and Array[1] represents 'Betaa'

    [returns]:
        + returns a pandas.series.
        actually it returns new components of My_DataFrame["Target"]
    """
    # in following code if you don't know what is `qw`, just look at the next code cell right after this cell (I mean next section).
    # in following code np.where(My_DataFrame["Loss"] == item)[0][0] is telling me the row's index of item. 
    for item in My_DataFrame[My_DataFrame["Loss"]>160]['Loss']:
        My_DataFrame.iloc[np.where(My_DataFrame["Loss"] == item)[0][0] , 1] = qw.log10((1/Array[1])*(  1 + (Array[0]*(item-160)/Array[1])**( (-1/Array[0]) - 1 )))

    return My_DataFrame["Target"]



# i have 2 variables : 'Kasi' and 'Betaa', so I put nd=2
nd = 2
qw = GEKKO()

# now i want to specify my variables ('Kasi'  and 'Betaa') with initial values --> Kasi = 0.7 and Betaa = 20.0
x = qw.Array(qw.Var , nd)
for i,xi in enumerate([0.7, 20]):
   x[i].value = xi
# So i guess now x[0] represents 'Kasi' and x[1] represents 'Betaa'

qw.Maximize(qw.sum(obj_function(x)))

提出的潜在脚本在这里:

from gekko import GEKKO
import numpy as np
import pandas as pd


My_DataFrame = pd.read_excel("[<FILE_PATH_IN_YOUR_MACHINE>]\\Losses.xlsx")
# i'll put link of "Losses.xlsx" file in the end of my explaination
# so you can download it from my google drive.


loss = My_DataFrame["Loss"]
def obj_function(x):
    k,b = x
    target = []

    for iloss in loss:
        if iloss>160:
            t = qw.log((1/b)*(1+(k*(iloss-160)/b)**((-1/k)-1)))
            target.append(t)
    return target


qw = GEKKO(remote=False)
nd = 2
x = qw.Array(qw.Var,nd)

# initial values --> Kasi = 0.7 and Betaa = 20.0
for i,xi in enumerate([0.7, 20]):
   x[i].value = xi
   
# bounds
k,b = x
k.lower=0.1; k.upper=0.8
b.lower=10;  b.upper=500
qw.Maximize(qw.sum(obj_function(x)))
qw.options.SOLVER = 1
qw.solve()
print('k = ',k.value[0])
print('b = ',b.value[0])

python 输出:

目标函数 = -1155.4861315885942
b = 500.0
k = 0.1

注意在python输出中b代表“Betaa”,k代表“Kasi”。
输出看起来有点奇怪,所以我决定测试一下!为此我使用了 Microsoft Excel Solver
(我把excel文件的链接放在我解释的最后,所以你可以自己检查一下,如果 你想要的。)如下图所示,已经完成了excel优化和最佳解决方案 已成功找到(优化结果见下图结果)。

excel 输出:

目标函数 = -108.21
Betaa = 32.53161
卡斯 = 0.436246

如您所见,python outputexcel output 之间存在巨大差异,并且似乎 excel 的表现相当不错! 所以我猜问题仍然存在,建议的 python 脚本性能不佳......
Implementation_in_Excel.xls Microsoft excel 应用程序优化文件可用here。(你也可以看到优化数据选项卡中的选项 --> 分析 --> Slover。)
在 excel 和 python 中用于优化的数据是相同的,可用here(非常简单,包含 501 行和 1 列)。
*如果您无法下载文件,请告诉我,我会更新它们。

【问题讨论】:

    标签: python python-3.x optimization gekko mle


    【解决方案1】:

    初始化将[0.7, 20] 的值应用于每个参数。应该使用标量来初始化value,而不是:

    x = qw.Array(qw.Var , nd)
    for i,xi in enumerate([0.7, 20]):
       x[i].value = xi
    

    另一个问题是gekko 需要使用特殊函数来为求解器执行自动微分。对于目标函数,切换到求和的gekko 版本为:

    qw.Maximize(qw.sum(obj_function(x)))
    

    如果loss 是通过更改x 的值来计算的,则目标函数具有logical expressions that need special treatment 用于基于梯度的求解器的求解。尝试将if3() 函数用于条件语句或slack variables(首选)。目标函数被评估一次以构建符号表达式,然后将其编译为字节码并使用其中一个求解器求解。符号表达式位于 gk0_model.apm 文件的 m.path 中。

    对编辑的回应

    感谢您发布包含完整代码的编辑。这是一个潜在的解决方案:

    from gekko import GEKKO
    import numpy as np
    import pandas as pd
    
    loss = np.linspace(-555.795 , 477.841 , 500)
    def obj_function(x):
        k,b = x
        target = []
    
        for iloss in loss:
            if iloss>160:
                t = qw.log((1/b)*(1+(k*(iloss-160)/b)**((-1/k)-1)))
                target.append(t)
        return target
    qw = GEKKO(remote=False)
    nd = 2
    x = qw.Array(qw.Var,nd)
    # initial values --> Kasi = 0.7 and Betaa = 20.0
    for i,xi in enumerate([0.7, 20]):
       x[i].value = xi
    # bounds
    k,b = x
    k.lower=0.6; k.upper=0.8
    b.lower=10;  b.upper=30
    qw.Maximize(qw.sum(obj_function(x)))
    qw.options.SOLVER = 1
    qw.solve()
    print('k = ',k.value[0])
    print('b = ',b.value[0])
    

    求解器到达解的边界。可能需要扩大界限,以免任意限制成为解决方案。


    更新

    这是一个最终解决方案。代码中的目标函数有问题,所以应该修复这里是正确的脚本:

    from gekko import GEKKO
    import numpy as np
    import pandas as pd
    
    My_DataFrame = pd.read_excel("<FILE_PATH_IN_YOUR_MACHINE>\\Losses.xlsx")
    loss = My_DataFrame["Loss"]
    
    def obj_function(x):
        k,b = x
        q = ((-1/k)-1)
        target = []
    
        for iloss in loss:
            if iloss>160:
                t = qw.log(1/b) + q* ( qw.log(b+k*(iloss-160)) - qw.log(b))
                target.append(t)
        return target
    
    qw = GEKKO(remote=False)
    nd = 2
    x = qw.Array(qw.Var,nd)
    
    # initial values --> Kasi = 0.7 and Betaa = 20.0
    for i,xi in enumerate([0.7, 20]):
       x[i].value = xi
    
    qw.Maximize(qw.sum(obj_function(x)))
    qw.solve()
    print('Kasi = ',x[0].value)
    print('Betaa = ',x[1].value)
    

    输出:

     The final value of the objective function is  108.20609317143486
     
     ---------------------------------------------------
     Solver         :  IPOPT (v3.12)
     Solution time  :  0.031200000000000006 sec
     Objective      :  108.20609317143486
     Successful solution
     ---------------------------------------------------
     
    
    Kasi =  [0.436245842]
    Betaa =  [32.531632983]
    

    结果接近 Microsoft Excel 的优化结果。

    【讨论】:

    • 谢谢亲爱的教授。在最大化部分,我认为你的意思是qw.Maximize(qw.sum(obj_function(x)))。你用了m.sum(...),我不知道m是什么,但我想你的意思是qw。我使用了你的初始化步骤,但我得到了这个错误:"TypeError: x must be a python list of GEKKO parameters, variables, or expressions" 它指的是qw.Maximize(qw.sum(obj_function(x)))部分代码!
    • 你是对的 - gekko 模型被称为qw。您能否发布一个完整的脚本以便我们验证修复?目标函数需要返回一个 Gekko 表达式,而不仅仅是值。
    • 当然!我更新了问题并将集成脚本添加到问题末尾。如果你能检查出来,我将不胜感激。
    • 感谢亲爱的教授您对我的帮助!我试图测试这个优化来验证结果!所以我在 MICROSOFT EXCEL solver 中尝试了这种优化,结果明显不同!我更新了问题并解释了验证路线!我希望您阅读我的新解释,如果您能帮助我,我将不胜感激。谢谢。
    • 现在完成了,亲爱的教授。我编辑了你的答案。请检查一下。再次,非常感谢。
    【解决方案2】:

    qw.Maximize() 只是设置优化的目标,你仍然需要在你的模型上调用solve()

    【讨论】:

    • 是的,谢谢。但我有一个错误,所以我会更新这个问题。谢谢!
    • 我认为您需要以不同的方式构建目标函数...
    • 这里有人可以帮我吗?
    【解决方案3】:

    如果我没看错,My_DataFrame 已在全局范围内定义。
    问题是obj_funtion 尝试访问它(成功),然后修改它的值(fails) 这是因为默认情况下您无法从本地范围修改全局变量。

    修复:

    obj_function的开头,加一行:

    def obj_function(Array):
        # comments
        global My_DataFrame
        for item .... # remains same
    

    这应该可以解决您的问题。

    补充说明:

    如果你只是想访问My_DataFrame,它可以正常工作,而且你不需要添加global关键字

    另外,只是想感谢您为此付出的努力。有一个关于你想要做什么的正确解释、相关背景信息、一个优秀的图表(Whiteboard 也非常棒),甚至是一个最小的工作示例。 这应该是所有SO问题的方式,它会让每个人的生活更轻松

    【讨论】:

    • 我做了你的建议,但不幸的是问题还没有解决,它只是返回初始值:(
    • 谢谢!感谢您尝试帮助我和您的友善态度♥
    • @Shayan 也许this 可以帮忙?
    • 我认为这是许多帖子所涵盖的单独错误,例如this one。谷歌错误以找到更多结果
    • 谢谢,最近没看到!粗暴地我试图找到解决问题的方法!谢谢。
    猜你喜欢
    • 2021-02-04
    • 2021-11-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-03
    相关资源
    最近更新 更多