在众多新功能中JMP 13在 JSL 中改进了 Minimize() 和 Maximize() 函数。 这些 JSL 函数是迭代优化器,可在给定起始值的情况下找到函数的极值。 下面的 GIF 是一个视觉演示,用于直观地了解算法在简单的一维设置中是如何工作的。

虽然大多数JMP用户会发现预先构建的平台(例如 Fit Y by X 和 Nonlinear)足以解决他们的优化问题,但情况并非总是如此,这些 JSL 函数提供了极大的灵活性和通用性。 这些功能使用户可以访问 JMP 开发人员在创建 JMP 平台时利用的相同优化器。
一般而言,任何有可能报告的地方JMP ,该模型已使用称为最大似然的优化技术进行拟合。 同样,最小二乘这个名称本身描述了用于拟合线性模型的优化方法。 虽然 JMP 有多种可用模型,但有时人们想要拟合 JMP 中未预建的自定义模型。 此外,出于教学原因,学生将统计建模程序转化为优化问题以了解模型的工作原理可能很有用。
接下来的几节说明了使用通用优化器的基础知识。 已经熟悉迭代优化器的用户可能希望跳到最后一节,查看 Minimize() 和 Maximize() 中一些高级功能的示例语法。
在本文的其余部分,我将从 Minimize() 的角度编写所有内容。 请注意,最小化函数 f(x) 等价于最大化 -1 * f(x),因此将“f(x)”与“–f(x)”、“minimize”与“maximize”、“concave”交换”与“凸”等,将结果推广到Maximize()。
简单示例
最基本的优化问题需要两个函数参数:一个表达式和要优化的变量。 与过去一样,诸如 Minimize(表达式, { x, y }) 返回获得的最小值。 为了演示它是如何工作的,第一个示例最小化了一个微不足道的二次表达式。
x = 2; /*starting value for x */
y = 2; /*starting value for y */
expr1 = expr((x ^ 2 + (y - 1) ^ 2));
minFun = Minimize( expr1, {x, y});
Show(minFun, x, y);
输出:
minFun = 0;
x = 0;
y = 1;
经过一番思考,我们可以说服自己这个函数的最小值应该是 0,并且发生在 x = 0 和 y = 1 处。 运行此脚本后,我们看到确实如此。
请注意,x 和 y 已由 Minimize() 函数更改,以反映达到最小函数值的参数值。 此函数的等高线图如下所示:
选择起始值
优化器必须从一组特定的参数值开始,称为起始值,然后反复尝试改进它们。 优化的成败高度依赖于起始值的质量。 开发统计软件的部分艺术围绕着寻找有效的起始值。 有多种方法可以提出它们。 必须在起始值处评估函数(即它不返回缺失值)。有时,您能做的最好的事情就是提出合理的“默认”值,例如将回归参数设置为零。 通常,最好的起始值是通过将更简单的模型拟合到数据并使用这些结果来获得的,例如使用线性最小二乘估计作为逻辑回归的起始值。
全局与局部临界点
需要注意的一个重要警告是,Minimize 会找到局部临界点,这可能是也可能不是全局最小值。 下一个例子是一个简单的多项式来说明这一点。 对于 x = 0、y = 0 的起始值,在 x = 0.25 和 y = -0.0833 处找到局部最小值。 但是,对于 x=-1 和 y = -1,答案是 -infinity。
x = 0; /*starting value for x */
y = 0; /*starting value for y */
expr2 = expr((y * 3 - 2 * x ^ 2 - 12 * x * y));
minFun = Minimize(expr2, {x, y});
Show( x, y, minFun);
输出:
x = 0.25;
y = -0.0833333333333333;
minFun = -0.125;
x = -1; /*starting value for x */
y = -1; /*starting value for y */
minFun = Minimize(expr2, {x, y});
Show( x, y, minFun);
输出:
Optimization failed: Failed: Maximum Iterations Exceeded
x = -6.55731043158825e+85;
y = -1.31136919553771e+89;
minFun = -1.03197258530774e+176;
请注意,Minimize() 不会为此给出任何警告,因为它不知道它是否达到了局部或全局最小值。 事实上,在这个例子中,第一组起始值收敛到鞍点,在这种情况下,它是一个方向的最小值和另一个方向的最大值。 如果需要全局最小值,而问题不是凸的(或者如果您不确定),那么一种选择是尝试多个起始值以检查它们是否都收敛到同一位置。 或者,如果有两个或更少的参数,则可以绘制函数,这样可以很容易地判断它是否是局部最小值,例如,这里是最后一个函数的计数图,具有两个不同的起始值:
实际示例 1:最小化损失函数
在统计学中,参数估计通常是通过找到使平方误差项之和最小化的参数值来确定的,总和(观察到 - 预测)^ 2。例如,考虑非线性 NIST Dan Wood 测试用例(“ ” )。
在这里,我们希望在给定模型的情况下最小化误差平方和,即找到参数
和
最小化
.
下面的 JSL 代码实现了这一点。
x = [1.309, 1.471, 1.49, 1.565, 1.611, 1.68];
y = [2.138, 3.421, 3.597, 4.34, 4.882, 5.66];
b1 = 1; /*starting value for b1 */
b2 = 5; /*starting value for b2 */
sseExpr = Expr(
Summation( i = 1, 6, (y[i] - b1 * x[i] ^ b2) ^ 2 )
);
minFun = Minimize( sseExpr, {b1, b2} );
Show( b1, b2, minFun );
输出:
b1 = 0.768858626467797;
b2 = 3.86041439611906;
minFun = 0.00431730849313329;
等高线图:
现实示例 2:简单的线性逻辑回归
如前所述,优化例程的另一个常见用途是寻找最大似然估计。 例如,假设我们观察到 100 个二元响应值 y 和相关的连续预测变量 x,并且我们想要拟合逻辑回归模型。 对于简单的线性逻辑回归,我们假设对于每个 i,
, 在哪里
. 相关的对数似然是
. 为简洁起见,我跳过了推导,但可以找到更多细节这里.以下 JSL 代码最大限度地提高了这种可能性:
b0 = 0;
b1 = 0;
logLik = Expr(
Summation( i = 1, 100, y[i] * log( logist(b0 + b1 * x[i]) ) + (1 - y[i]) * log(1- logist(b0 + b1 * x[i]) ) )
);
minFun = Maximize( logLik, {b0, b1} );
Show( b0, b1);
输出:
b0 = 0.169912186525928;
b1 = 2.37904556815702;
因此,该模型预测对于一些新的 x 值,估计概率为:

使用拟合图:

如果有兴趣,请参阅附加的 JSL 脚本,了解我在此示例中使用的 x 和 y 的具体值以及我是如何生成它们的。
新的可选功能 <
我最喜欢的新功能允许用户通过使用可选参数 <
x = [1.309, 1.471, 1.49, 1.565, 1.611, 1.68];
y = [2.138, 3.421, 3.597, 4.34, 4.882, 5.66];
b1 = 1; /*starting value for b1 */
b2 = 5; /*starting value for b2 */
sseExpr = Expr(
Summation( i = 1, 6, (y[i] - b1 * x[i] ^ b2) ^ 2 )
);
{objVal, iters, gradient, hessian} = Minimize( sseExpr, {b1, b2} , <<SHOWDETAILS></SHOWDETAILS>
输出:
nParm=2 Newton ******************************************************
Iter nFree Objective RelGrad NormGrad2 Ridge nObj nGrad nHess Parm0 Parm1
0 2 149.7192 332.8046 182170.1 0 1 1 1 1 5
1 2 31.87877 101.5969 19003.84 0 1 1 1 1.010662 4.225573
2 2 4.215765 28.12531 1448.206 0 1 1 1 1.024865 3.630484
3 2 0.378951 7.636836 51.97781 0 1 1 1 1.058064 3.252922
4 2 0.153712 0.003012 0.615041 0.125 2 1 1 1.008287 3.272327
5 2 0.08553 0.100794 0.100071 0.031 1 1 1 0.937871 3.42031
6 2 0.035115 0.074061 0.132669 0.016 1 1 1 0.868411 3.588806
7 2 0.00829 0.164555 1.452852 0 1 1 1 0.772783 3.836035
8 2 0.00432 1.62e-5 0.00021 0 1 1 1 0.769751 3.858031
9 2 0.004317 2.313e-9 2.057e-8 0 1 1 1 0.768859 3.860414
Convergence SUCCESS: Gradient
Time: 0.033333333209157
b1 = 0.768858626467797;
b2 = 3.86041439611906;
objVal = 0.00431730849313329;
iters = 9;
gradient = [-0.000193577585687388, -0.000060622489899298];
hessian = [351.567213300015 123.108731500088, 123.108731500088 43.9222933905666];
Minimize() 和 Maximize() 的所有可选功能列表
- 设置上限和下限:设置变量的下限和/或上限。 例如, Minimize( x^2, x(1,5) ),限制 x 保持在 1 和 5 之间,Minimize ( x^2, x(. , 5) ),确保 x 小于 5,没有下限.
- 设置最大迭代次数: 最大迭代次数默认为 250,但可以使用 <新的MaxIter )。 默认为 250。
- 设置收敛容差: 收敛标准可以用 <新公差)。 默认值为 10^-8。
- 显示更多详情:选项<
- 对导数使用数值近似:默认情况下,Minimize() 将尝试找到解析导数,但在某些情况下,数值近似可能会更好。 通过将“<
- 输入用户定义的渐变:大多数情况下,Minimize() 将能够默认计算分析梯度。 在不太可能发生的情况下,用户可以输入自己的渐变。 为此,请使用 <
- 输入用户定义的 Hessian : 输入用户自定义的粗麻布就更麻烦了。 语法很快就会变得复杂,我建议仅将其用作最后的手段。 要输入解析粗麻布,请使用 <
带有所有可选参数的简单示例
下面是一个有用的 Minimize() 模板,其中选择了所有可选参数。 在 JMP 13.2 中,也可以在使用 JMP 的脚本索引中的最小化下找到此示例。 这是示例 3(通过选择示例 1 旁边的下拉菜单来选择它)。
x = 0;
y = 0;
{objVal, iters, gradient, hessian} =
Minimize(
((2 * x ^ 2 + 12 * x * y - y * 3)),
{x( -1, 1 ), y( -1, 1 )},
<<MAXITER></MAXITER>
请继续关注未来可能发布的有关新 JSL 函数 Constrained Minimize() 和 Constrained Maximize() 的博客文章,它们可以优化非线性目标函数和线性约束的问题。
嗨,霍克斯温德,
我很高兴您发现这篇博文很有用!
好点子! Minimize() 实际上并没有收敛于我为 GIF 选择的(相当糟糕的)函数的默认容差。 我完全根据它的外观选择了该功能。 Minimize() 很难处理它,因为基于梯度的优化方法与导数并不总是存在的函数作斗争。 在这种情况下,绝对值函数会引起问题。
有时有一些简单的解决方案,例如将 a 限制为非负,如下所示:
a = 2
xpr = expr(3^abs(a));
minimize(xpr, {a(0,.)}, <<SHOWDETAILS></SHOWDETAILS>
我没有在 GIF 代码中这样做,因为我认为该函数看起来更好,具有抛物线形状。 但是你可以看到,即使在 GIF 中,算法也很难收敛,在接近尾声的地方,箭头在真正的最小值附近来回跳跃。
感谢您的详细解释。 最小化例程应该对我的新项目有用。
我已经拆分了各个部分,并且 a=只有 GIF 图有问题 - 尝试最小化 xpr = expr(3^abs(a));但它不会收敛(我改变了最初的猜测)并且有后续错误。
附上脚本部分。 建议表示赞赏。
[为简洁起见,管理员删除了脚本。 它可以在博客所附的 JSL 文件中找到。]