Comment créer une colonne moyenne avec JSL à partir de colonnes aléatoiresJe souhaite créer une liste de colonnes en fonction de certains critères de sélection. Les noms des colonnes ne seront pas connus à l'avance. J'utiliserai ensuite cette liste pour créer une colonne de formule qui calcule la moyenne (ou l'écart type ou le nombre) des valeurs de ces colonnes.
Exemple de script simple qui prend en compte toutes les colonnes numériques :
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
ColList = {};
For(i=1, i<=NCols(), i++,
If(Column(i)<
<GETDATATYPE></GETDATATYPE>
<BR /> <BR /> <P>Notez que ColList est une liste de colonnes valide. Lorsqu'elle est insérée dans la formule de la première colonne, l'aperçu dans l'éditeur de formules affiche un résultat correct, mais la colonne reste vide. Il semble donc nécessaire d'insérer des scalaires, une liste ou une matrice dans la fonction Mean() (l'aperçu fonctionnera néanmoins correctement).</P> <P><SPAN class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><span class="lia-inline-image-display-wrapper" image-alt="pauldeen_0-1788272598908.png" style="width: 400px;"><img src="https://us.v-cdn.net/6038925/uploads/images/115064i3C11FFA7C1D866DE/pauldeen_0-1788272598908.png" role="button" title="pauldeen_0-1788272598908.png" alt="pauldeen_0-1788272598908.png" /></span><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN><SPAN class="lia-inline-image-caption" onclick="event.preventDefault();">pauldeen_0-1788272598908.png</SPAN></SPAN></P> <P>La deuxième colonne de formule ajoute une fonction AsColumn() autour de la référence de colonne, ce qui peut paraître contre-intuitif puisqu'il s'agit déjà d'une colonne. Mais elle crée désormais une liste, un scalaire ou une matrice, et la formule mean() fonctionnera.</P> <P>J'ai l'impression que je me complique la vie. Existe-t-il une méthode plus simple pour générer automatiquement une telle colonne récapitulative ?</P>
Re : Comment créer une colonne moyenne avec JSL à partir de colonnes aléatoiresDans les cas simples comme celui-ci, j'utilise généralement la fonction Substitute pour remplacer la liste par une autre expression.
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Cars.jmp");
collist = dt << Get Column Names("Numeric", "String");
colrefs = Transform Each({colname}, collist,
Name Expr(As Column(dt, colname))
);
mexpr = Substitute(colrefs, Expr(List), Expr(Mean));
Eval(EvalExpr(
dt << New Column("AVG", Numeric, Continuous, Formula(
Expr(Name Expr(mexpr))
));
));
Write();
Re : Comment créer une colonne moyenne avec JSL à partir de colonnes aléatoiresMerci, mais cela reste une solution complexe pour un problème simple. Je suis curieux de savoir si quelqu'un trouvera une méthode plus simple pour ajouter des références de colonnes à une formule de colonne.
Re : Comment créer une colonne moyenne avec JSL à partir de colonnes aléatoiresSupposons que nous ayons une colonne nommée « TEST » dans la table dt. Il existe des différences entre les valeurs « basiques » et « de base ».
- Colonne(dt, "TEST")
- AsColumn(dt, "TEST")
- "TEST"
- Nom Expr(Comme Colonne(dt, "TEST"))
Voir plus...
Names Default To Here(1);
dt = Open("$SAMPLE_DATA/Cars.jmp");
Row() = 0; // default row value
col = "Size";
Show(col);
Show(Column(dt, col));
Show(AsColumn(dt, col));
Show(Name Expr(AsColumn(dt, col)));
Show(dt:col);
Show(AsName(col));
Write("\!N\!N");
Row() = 1;
Show(Column(dt, col)[Row()]);
Show(AsColumn(dt, col));
Show(Name Expr(AsColumn(dt, col)));
Show(dt:col);
Show(AsName(col));
Quel type de solution recherchez-vous ? Vous n’ajoutez pas de références de colonnes aux formules, sauf si vous utilisez `[]` ou `[Row()]` avec la référence. Si vos colonnes sont obtenues sous forme de références (ou de chaînes de caractères), vous devrez généralement les convertir en « accès aux colonnes » pour pouvoir les utiliser dans les formules.
Re : Comment créer une colonne moyenne avec JSL à partir de colonnes aléatoiresJ'ai soumis un rapport de bug à JMP.
Le problème est que la formule de colonne n'accepte pas les arguments de type `Column("nom")`, mais doit d'abord être placée dans une expression `AsColumn()`. L'éditeur visuel de formules permet de glisser-déposer des colonnes dans les champs d'arguments ; JSL devrait donc offrir le même comportement. L'ajout de cette fonctionnalité à JSL simplifierait grandement la création de formules de colonne.
Apparemment, la fenêtre d'aperçu de l'éditeur de formules interprète cela correctement puisqu'elle affiche un aperçu.
Re : Comment créer une colonne moyenne avec JSL à partir de colonnes aléatoiresLes fonctions Column() et AsColumn()/:colname ne sont pas identiques et ne doivent pas être utilisées de la même manière.
À mon avis, le problème vient de l'éditeur de formules et de son affichage des formules générées en JSL. Il ne détecte pas les formules incorrectes (comme dans ce cas) et n'affiche pas les messages d'erreur lorsqu'il le devrait.
jthi_1-1788881236165.pngjthi_1-1788881236165.pngjthi_1-1788881236165.png
jthi_2-1788881243139.pngjthi_2-1788881243139.pngjthi_2-1788881243139.png
jthi_4-1788881274171.pngjthi_4-1788881274171.pngjthi_4-1788881274171.png
Dans ce cas, cela devrait apparaître dans les propriétés de la colonne.
jthi_7-1788882167381.pngjthi_7-1788882167381.pngjthi_7-1788882167381.png
et ceci dans l'éditeur de formules
jthi_6-1788882151203.pngjthi_6-1788882151203.pngjthi_6-1788882151203.png
Et si vous essayez de l'appliquer, une erreur comme celle-ci se produit.
jthi_5-1788882131736.pngjthi_5-1788882131736.pngjthi_5-1788882131736.png
Si vous le corrigez en Column()[], l'affichage est correct et il renvoie les résultats corrects.
jthi_0-1788880964367.pngjthi_0-1788880964367.pngjthi_0-1788880964367.png
Mais il appartient aux développeurs de JMP de décider comment ils estiment que cela devrait se comporter.
Re : Comment créer une colonne moyenne avec JSL à partir de colonnes aléatoiresJarmo soulève des points pertinents et propose une solution alternative : utiliser Column("name")[]. Comme il le mentionne, cette syntaxe est moins esthétique dans l'éditeur de formules. Ma solution ci-dessous n'aborde pas cette option, mais explique pourquoi elle prête à confusion pour de nombreux utilisateurs. Elle reprend en grande partie les informations déjà fournies par Jarmo, mais comme je les avais déjà rédigées…
En réalité, ce que le script de l'auteur du message initial illustre n'est pas un bug. Il s'agit d'un comportement normal, qui met en évidence une confusion fréquente chez les utilisateurs concernant les références aux colonnes et le fonctionnement de l'évaluation des formules de colonnes.
La confusion provient principalement de la différence entre la syntaxe `Column("name")` et la syntaxe `:name`. Les deux permettent de faire référence à des colonnes dans certains cas, mais leur résultat diffère. Plus précisément, `Column("name")` renvoie une référence à un objet colonne, tandis que `:name` renvoie la valeur de la colonne « name » de la ligne courante. Par ailleurs, `:name` est l'opérateur de la fonction `AsColumn("name")`. En d'autres termes, il s'agit exactement de la même chose.
L'exemple de script suivant illustre ce propos. Ce script suppose que la table de données Cars.jmp est ouverte et active dans votre session JMP.
Names Default To Here(1);
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
// sending messages to a column; either syntax works
Column(dt, "Year") << Set Property("Range Check", LELE(87, 97));
dt:Head IC << Set Property("Spec Limits", {LSL( 150 ), Show Limits( 1 )});
// Return values
// returns a column object reference shown as Column( "Year" ) in log
Column(dt, "Year"); // returns Column( "Year" )
// returns value in Year column on the current row.
// Since current row is 0 (the default invalid row number), returns missing (.)
:Year; // returns .
// Set the current row to the first row
Row() = 1;
:Year; // returns 87
Compte tenu de ces informations, il est clair que JMP ne peut pas calculer la moyenne d'un ensemble de références de colonnes. C'est pourquoi la première formule de colonne ne s'exécute pas correctement. La fonction Moyenne() nécessite des valeurs, qui sont fournies dans la deuxième formule de colonne. Lors de l'évaluation des formules de colonnes par une table de données, la ligne courante est initialisée à 1, puis l'expression stockée dans la propriété Formule est évaluée. Le résultat est placé dans la cellule de la colonne correspondante sur la ligne courante. Ensuite, la ligne courante est initialisée à la valeur suivante et le processus se répète. Ces étapes sont répétées jusqu'à ce que la formule soit évaluée pour la dernière ligne. Par conséquent, la syntaxe de la formule de colonne doit permettre son évaluation pour chaque ligne de la table de données.
Votre exemple de script présente un résultat inattendu : la syntaxe `As Column(Column("name"))` est interprétée de la même manière que `As Column("name")`. Je m'attendais à une erreur, mais JMP l'accepte et interprète correctement l'intention. C'est là l'avantage (parfois) d'un langage de script par rapport à un langage de programmation classique. Cependant, je déconseille l'utilisation de cette syntaxe, car elle pourrait ne plus fonctionner à l'avenir.
À mon avis, la meilleure façon d'atteindre l'objectif, compte tenu du script d'exemple, est d'abandonner la première approche au niveau de la formule de colonne et d'utiliser la seconde. La modification supplémentaire consiste à définir ColList comme une liste de noms de colonnes plutôt que de références de colonnes. Voici une version modifiée du script d'exemple initial qui devrait être plus fiable.
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
ColList = {};
For( i = 1, i <= N Cols(), i++,
If( Column( i ) << GetDataType == "Numeric",
Insert Into( ColList, <FONT color="#FF6600"><STRONG>Column( i ) << Get Name</STRONG></FONT> )
)
);
MeanExpr2 = Name Expr( Mean() );
For( i = 1, i <= N Items( ColList ), i++,
Insert Into( MeanExpr2, Name Expr( As Column( ColList[i] ) ) )
);
Eval( Eval Expr( dt << New Column( "Average of numerics 2", Formula( Expr( Name Expr( MeanExpr2 ) ) ) ) ) );
Re : Comment créer une colonne moyenne avec JSL à partir de colonnes aléatoiresD'un point de vue théorique et pratique, vous avez probablement tout à fait raison… mais ce n'est pas ainsi que se comporte l'interface utilisateur. Je sélectionne des colonnes du tableau et les fais glisser sur l'opérateur `mean()` pour effectuer le calcul. Cependant, en programmation, je ne peux pas sélectionner directement les colonnes ; je dois sélectionner des chaînes de caractères (correspondant aux noms de colonnes) et indiquer à JSL de les interpréter comme des références de colonnes, que je peux ensuite injecter dans l'opérateur `mean()`. Ne serait-il pas simple d'améliorer les opérateurs JSL pour qu'ils traitent `Column("Name")` comme des objets colonne indexables sur la ligne ? Ce serait beaucoup plus intuitif et refléterait le comportement de l'interface utilisateur, et donc le raisonnement de l'utilisateur. Comme vous l'avez souligné, ce point est source de nombreuses confusions chez les utilisateurs.
Pour répondre aux remarques de Jarmo : les messages d’erreur dans l’éditeur de formules gagneraient à être plus clairs et plus cohérents. À noter également : l’aperçu affiche une évaluation correcte alors que la formule ne s’évalue pas correctement avec la syntaxe Column("Name").