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

虽然大多数联合管理计划用户会发现预构建的平台(例如 Fit Y by X 和非线性)足以解决他们的优化问题,但情况并非总是如此,并且这些 JSL 函数提供了极大的灵活性和通用性。 这些功能使用户能够访问 JMP 开发人员在创建 JMP 平台时所利用的相同优化器。
一般来说,任何有可能报告的地方联合管理计划,该模型已采用称为最大似然的优化技术。 同样,最小二乘这个名字本身描述了用于拟合线性模型的优化方法。 虽然 JMP 提供多种可用模型,但有时人们想要拟合 JMP 中未预先构建的自定义模型。 此外,出于教学原因,学生将统计建模程序转化为优化问题以了解模型的工作原理也很有用。
接下来的几节将说明使用通用优化器的基础知识。 已经熟悉迭代优化器的用户可能希望跳到最后一节,查看 Minimize() 和 Maximize() 中一些高级功能的示例语法。
在本文的其余部分中,我将从 Minimize() 的角度来编写所有内容。 请注意,最小化函数 f(x) 相当于最大化 -1 * f(x),因此将“f(x)”替换为“–f(x)”,“最小化”替换为“最大化”,“凹” ”与“凸”等,会将结果推广到 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 时。 运行这个脚本后,我们发现情况确实如此。
请注意,Minimize() 函数已更改 x 和 y,以反映实现最小函数值的参数值。 该函数的等值线图如下所示:
选择起始值
优化器必须从一组特定的参数值(称为起始值)开始,然后迭代地尝试改进它们。 优化的成功和失败很大程度上取决于起始值的质量。 开发统计软件的一部分艺术围绕着寻找有效的起始值。 有多种方法可以提出它们。 重要的是该函数可以在起始值处进行计算(即它不返回缺失值)。有时,您能做的最好的事情就是提出有效的合理“默认”值,例如将回归参数设置为零。 通常,最佳起始值是通过将更简单的模型拟合到数据并使用这些结果来获得的,例如使用线性最小二乘估计作为逻辑回归的起始值。
全局关键点与局部关键点
需要注意的一个重要警告是,最小化会找到局部临界点,这可能是也可能不是全局最小值。 下一个例子是一个简单的多项式来说明这一点。 当初始值 x = 0、y = 0 时,在 x = 0.25 和 y = -0.0833 处找到局部最小值。 然而,对于 x=-1 且 y = -1,答案为 –无穷大。
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:最小化损失函数
在统计学中,参数估计值通常是通过查找使误差项平方和最小化的参数值来确定的,sum(观察值 – 预测值)^ 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:简单线性 Logistic 回归
如前所述,优化例程的另一个常见用途是查找最大似然估计。 例如,假设我们观察到 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,但可以使用 <新的最大迭代器)。 默认为 250。
- 设置收敛容差:收敛标准可以通过 <新的宽容度)。 默认值为 10^-8。
- 显示更多详情:选项<
- 使用导数的数值近似:默认情况下,Minimize() 将尝试查找解析导数,但在某些情况下,数值近似可能效果更好。 通过将“<
- 输入用户定义的渐变:大多数时候,Minimize() 默认能够计算解析梯度。 万一需要的话,用户可以输入自己的梯度。 为此,请使用 <
- 输入用户定义的 Hessian :输入用户定义的hessian就更麻烦了。 语法很快就会变得复杂,我建议仅将其作为最后的手段。 要输入分析 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 文件中找到。]