Parmi les nombreuses nouveautés de JMP13 sont les fonctions Minimize() et Maximize() remaniées en JSL. Ces fonctions JSL sont des optimiseurs itératifs qui trouvent les valeurs extrêmes d'une fonction à partir de valeurs de départ. Le GIF ci-dessous est une démonstration visuelle pour donner une intuition du fonctionnement de l'algorithme dans un cadre unidimensionnel simple.

Alors que la plupart JMP les utilisateurs trouveront que les plateformes pré-construites (telles que Fit Y by X et Nonlinear) suffisent à leurs problèmes d'optimisation, ce n'est pas toujours le cas, et ces fonctions JSL offrent une grande flexibilité et généralité. Ces fonctions donnent à l'utilisateur l'accès aux mêmes optimiseurs dont profitent les développeurs JMP lorsqu'ils créent des plates-formes JMP.
D'une manière générale, partout où il y a une probabilité signalée dans JMP , le modèle a été équipé d'une technique d'optimisation appelée Maximium Likelihood. De même, le nom « Moindres carrés » décrit lui-même la méthode d’optimisation utilisée pour ajuster les modèles linéaires. Bien que JMP propose une grande variété de modèles, il arrive parfois que l'on souhaite adapter un modèle personnalisé qui n'est pas prédéfini dans JMP. Aussi, pour des raisons pédagogiques, il peut être utile aux étudiants de transformer des programmes de modélisation statistique en problèmes d’optimisation pour comprendre le fonctionnement du modèle.
Les sections suivantes illustrent les bases de l'utilisation d'un optimiseur général. Les utilisateurs déjà familiers avec les optimiseurs itératifs souhaiteront peut-être passer à la dernière section pour voir un exemple de syntaxe pour certaines des fonctionnalités avancées de Minimize() et Maximize().
Pour le reste de cet article, j'écrirai tout du point de vue de Minimize(). Notez que minimiser une fonction, f(x), équivaut à maximiser -1 * f(x), donc échanger « f(x) » avec « –f(x) », « minimiser » avec « maximiser », « concave » avec « convexe », etc., généralisera les résultats à Maximize().
Exemple simple
Le problème d'optimisation le plus élémentaire nécessite deux arguments de fonction : une expression et les variables à optimiser. Comme par le passé, un appel tel que Minimize( expression , { x, y }) renvoie la valeur minimale obtenue. Pour démontrer comment cela fonctionne, le premier exemple minimise une expression quadratique triviale.
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);
Sortir:
minFun = 0;
x = 0;
y = 1;
Après réflexion, nous pouvons nous convaincre que le minimum de cette fonction devrait être 0 et se produire à x = 0 et y = 1. Après avoir exécuté ce script, nous constatons que c'est effectivement le cas.
Notez que x et y ont été modifiés par la fonction Minimize() pour refléter les valeurs d'argument qui ont atteint la valeur minimale de la fonction. Un tracé de contour pour cette fonction est présenté ici :
Choisir les valeurs de départ
L'optimiseur doit commencer par un ensemble particulier de valeurs de paramètres, appelées valeurs de départ, puis essayer de les améliorer de manière itérative. Le succès et l'échec de l'optimisation dépendent fortement de la qualité des valeurs de départ. Une partie de l’art du développement de logiciels statistiques consiste à trouver des valeurs de départ efficaces. Il existe diverses manières de les réaliser. Il est essentiel que la fonction puisse être évaluée aux valeurs de départ (c'est-à-dire qu'elle ne renvoie pas de valeur manquante).Parfois, le mieux que vous puissiez faire est de trouver des valeurs « par défaut » raisonnables qui fonctionnent bien, comme définir des paramètres de régression égaux à zéro. Souvent, les meilleures valeurs de départ sont obtenues en ajustant un modèle plus simple aux données et en utilisant ces résultats, par exemple en utilisant des estimations des moindres carrés linéaires comme valeurs de départ pour une régression logistique.
Points critiques mondiaux ou locaux
Une mise en garde importante à prendre en compte est que Minimize trouve des points critiques locaux, qui peuvent ou non être le minimum global. L’exemple suivant est un polynôme simple qui illustre cela. Avec les valeurs de départ de x = 0, y = 0, un minimum local se trouve à x = 0,25 et y = -0,0833. Cependant, pour x=-1 et y = -1, la réponse va à –infini.
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);
Sortir:
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);
Sortir:
Optimization failed: Failed: Maximum Iterations Exceeded
x = -6.55731043158825e+85;
y = -1.31136919553771e+89;
minFun = -1.03197258530774e+176;
Notez que Minimize() ne donne aucun avertissement à ce sujet car il ne sait pas s'il a atteint un minimum local ou global. En fait, dans cet exemple, le premier ensemble de valeurs de départ converge vers un point de selle , qui, dans ce cas, est un minimum dans un sens et un maximum dans un autre. Si un minimum global est souhaité et que le problème n'est pas convexe (ou si vous n'êtes pas sûr), une option consiste à essayer plusieurs valeurs de départ pour vérifier si elles convergent toutes vers le même emplacement. Alternativement, s'il y a deux paramètres ou moins, la fonction peut être tracée, ce qui permet de savoir facilement s'il s'agit d'un minimum local, par exemple voici le tracé du compteur de la dernière fonction avec les deux valeurs de départ différentes :
Exemple réaliste 1 : minimiser une fonction de perte
En statistiques, les estimations des paramètres sont souvent déterminées en trouvant les valeurs des paramètres qui minimisent la somme des termes d'erreur quadratique, somme (observée – prédite) ^ 2. À titre d'exemple, considérons le Cas de test non linéaire NIST Dan Wood (« » ).
Ici, nous voulons minimiser la somme des erreurs quadratiques étant donné le modèle, c'est-à-dire trouver les arguments pour
et
qui minimise
.
Le code JSL suivant implémente cela.
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 );
Sortir:
b1 = 0.768858626467797;
b2 = 3.86041439611906;
minFun = 0.00431730849313329;
Tracé de contour :
Exemple réaliste 2 : régression logistique linéaire simple
Comme mentionné, une autre utilisation courante des routines d’optimisation consiste à trouver des estimations du maximum de vraisemblance. Par exemple, disons que nous avons observé 100 valeurs de réponse binaires, y, et un prédicteur continu associé, x, et que nous souhaitons ajuster un modèle de régression logistique. Pour une régression logistique linéaire simple, nous supposons que pour chaque i,
, où
. La vraisemblance du journal associée est
. Par souci de concision, j'ai sauté les dérivations, mais plus de détails peuvent être trouvés ici .Le code JSL suivant maximise cette probabilité :
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);
Sortir:
b0 = 0.169912186525928;
b1 = 2.37904556815702;
Ainsi, ce modèle prédit que pour une nouvelle valeur x, les probabilités estimées sont :

Avec un tracé de l'ajustement :

Si vous êtes intéressé, veuillez consulter le script JSL ci-joint pour les valeurs spécifiques de x et y que j'ai utilisées pour cet exemple ainsi que pour voir comment je les ai générées.
Nouvelle fonctionnalité facultative <
Ma nouvelle fonctionnalité préférée permet à l'utilisateur de récupérer les détails de la sortie en utilisant l'argument facultatif <
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>
Sortir:
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];
Liste de toutes les fonctionnalités facultatives pour Minimize() et Maximize()
- Définir des limites supérieure et inférieure : Définissez des limites inférieures et/ou supérieures pour les variables. Par exemple, Minimize( x^2, x(1,5) ), restreint x pour qu'il reste entre 1 et 5, et Minimize ( x^2, x(. , 5) ), garantit que x est inférieur à 5 sans limite inférieure .
- Définir le nombre maximum d'itérations : Le nombre maximum d'itérations est par défaut de 250 mais peut être modifié avec < nouveauMaxIter ). La valeur par défaut est 250.
- Définir la tolérance pour la convergence : Le critère de convergence peut être modifié avec < nouveauTolérance ). La valeur par défaut est 10^-8.
- Afficher plus de détails : L'option <
- Utiliser l'approximation numérique pour les dérivés : Par défaut, Minimize() tentera de trouver des dérivées analytiques, mais dans certains cas, les approximations numériques peuvent mieux fonctionner. Sélectionnez cette option en ajoutant "<
- Entrée du dégradé défini par l'utilisateur : La plupart du temps, Minimize() sera capable de calculer les gradients analytiques par défaut. Dans le cas peu probable où cela serait souhaité, un utilisateur peut saisir son propre dégradé. Pour ce faire, utilisez <
- Saisir le Hessian défini par l'utilisateur : La saisie d'un hessian défini par l'utilisateur est encore plus fastidieuse. La syntaxe se complique très rapidement et je recommande de ne l'utiliser qu'en dernier recours. Pour saisir une toile de jute analytique, utilisez <
Exemple simple avec tous les arguments facultatifs
Vous trouverez ci-dessous un modèle utile de Minimize() avec tous les arguments facultatifs sélectionnés. Dans JMP 13.2, cet exemple se trouve également sous Réduire dans l'index des scripts avec JMP. C'est l'exemple 3 (sélectionnez-le en choisissant le menu déroulant à côté de l'exemple 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>
Restez informé pour un éventuel futur article de blog sur les nouvelles fonctions JSL, Constrained Minimize() et Constrained Maximize(), qui optimisent les problèmes avec les fonctions objectives non linéaires et les contraintes linéaires.
Salut Hockswender,
Je suis heureux que vous ayez trouvé l'article de blog utile !
Bon point! Minimize() ne converge pas réellement vers la tolérance par défaut pour la fonction (plutôt horrible) que j'ai choisie pour mon GIF. J'ai choisi cette fonction uniquement en fonction de son apparence. Minimize() a des difficultés car les méthodes d'optimisation basées sur le gradient ont du mal avec les fonctions où la dérivée n'existe pas toujours. Dans ce cas, la fonction valeur absolue pose problème.
Il existe parfois des solutions simples, comme restreindre a pour qu'il soit non négatif, comme dans :
a = 2
xpr = expr(3^abs(a));
minimize(xpr, {a(0,.)}, <<SHOWDETAILS></SHOWDETAILS>
Je ne l'ai pas fait dans le code GIF parce que je pensais que la fonction était plus esthétique avec une forme parabolique. Mais vous pouvez voir que l’algorithme a du mal à converger même dans le GIF, où vers la fin, les flèches sautent autour du vrai minimum.