Syntaxe acceptable incohérenteAllCols = dt << Get Column Names();
AllColNames = dt << Get Column Names(string);
for(i=3, i<=n items(AllCols), i++,
colcol = AllCols[i];
cname = AllColNames[i];
nnm1 = Col Number(colcol);
Fstr = "num(:\!""||cname||"\!"n)";
Fexpr = parse(Fstr);
newcol = dt << new column("Temp", numeric, formula(eval(evalexpr(Fexpr))));
nnm2 = Col Number(newcol);
if(nnm2 == nnm1,
newcol << delete formula();
dt << Delete Columns(colcol);
newcol << set name(cname), //else
dt << Delete Columns(newcol);
);
);J'utilise JMP18 sous Windows. Lorsque j'écris du code que je souhaite utiliser souvent, j'aime créer un bouton de barre d'outils pour celui-ci. Mais parfois, je trouve que le code qui est acceptable pour être exécuté à partir d'une fenêtre de script ouverte n'est pas acceptable lorsqu'il est exécuté à partir d'une icône de barre d'outils. Voici un exemple, où je fais une boucle dans les colonnes et les change de caractères en numériques si toutes les entrées sont numériques. Lors de l'exécution à partir d'une barre d'outils, l'objection concerne la ligne :
newcol = dt << new column("Temp", numeric, formula(eval(evalexpr(Fexpr))));
Cette syntaxe est acceptable lorsque j'exécute à partir d'une fenêtre de script !
Pourquoi l'interpréteur jsl serait-il différent dans chaque situation ?
Quelle syntaxe serait universellement acceptable ?
Pour les ensembles de données et les colonnes très volumineux, cette opération peut être lente. Existe-t-il une meilleure façon de procéder ?
Automatisation et scriptsFusion et nettoyage des donnéesFenêtresRé: Syntaxe acceptable incohérenteQuel message d'erreur avez-vous reçu ? Je pense que la fenêtre de script contient une table de données actuelle, mais le script de la barre d'outils ne le peut pas. Peut-être simplement en ajoutant
currentDatatable(dt);
au début du script serait suffisant.
Tu pourrais
print(currentDatatable());
au début du script pour savoir ce que le script de la barre d'outils sait.
Ré: Syntaxe acceptable incohérenteLes barres d'outils peuvent ajouter des noms par défaut ici (1) (que vous devriez toujours avoir) à votre script

qui peut alors potentiellement afficher des erreurs qui ne seraient pas visibles si tout était dans la portée globale (mais ce sont quand même généralement des erreurs). Je construis mes formules en utilisant soit Eval(EvalExpr()) soit Eval(Substitute())
Eval(EvalExpr(
newcol = dt << New Column("Temp", numeric, formula(Num(Expr(NameExpr(AsColumn(dt, i))))));
));
Pour les grands ensembles de données, vous devrez peut-être envisager un échantillonnage pour quelque chose comme cela. Il existe également des solutions sans formule qui peuvent être plus rapides, mais cela peut également dépendre de vos données.
Pour une raison quelconque, je n'ai pas publié ceci dans la communauté JMP (ou du moins je n'ai pas pu le trouver), Colonnes de caractères en numérique (github.com) , vous pouvez jeter un œil au code pour voir comment j'ai effectué cette tâche à partir de https://github.com/jthi-jmp-tools/character-columns-to-numeric/blob/main/bin/bin/character_columns_to_numeric.jsl . J'ai depuis refait ce script et si je me souviens bien, j'utilise une méthode un peu différente de nos jours.
Ré: Syntaxe acceptable incohérenteles icônes de la barre d'outils connaissent la table de données actuelle :
Le problème est plutôt l’inverse.
Veuillez définir « dt=current data table() » avant le
dt << Get Column Names();
Ré: Syntaxe acceptable incohérenteMerci Craig.
Le message d'erreur est :
Nom non résolu : 2PCS_X(um) à la ligne 1 dans l'accès ou l'évaluation de '2PCS_X(um)' , "2PCS_X(um)"n /*###*/
"2PCS_X(um)" est le nom de la première colonne à évaluer.
Donc l'expression pour la première colonne est supposée être :
newcol = dtTOSA << nouvelle colonne("Temp", numérique, formule(Num( :"2PCS_X(um)"n )));
Ré: Syntaxe acceptable incohérenteDe plus, dans le script actuel, je n'utilise pas dt comme variable. J'utilise une variable beaucoup plus descriptive, comme dtTOSA. (voir ci-dessus) Chaque fois que je veux faire référence à une table de données particulière, je l'indique toujours explicitement pour éviter toute confusion, comme je l'ai fait dans cette instruction. Je ne vois pas comment l'interpréteur pourrait penser que je fais référence à une table différente.
Ré: Syntaxe acceptable incohérentePeut-être, mais le message d'erreur suggère que JMP ne recherche pas au bon endroit "2PCS_X(um)"n. Je ne sais pas quel contexte le script de la barre d'outils peut utiliser.
Ré: Syntaxe acceptable incohérenteCraig,
J'ai utilisé votre suggestion d'utiliser une instruction d'impression et j'ai constaté qu'elle n'atteignait jamais la ligne que je pensais être le problème.
newcol = dt << new column("Temp", numeric, formula(eval(evalexpr(Fexpr))));Le problème était à cette ligne.
nnm1 = Col Number(colcol);
Alors je l'ai changé pour ça et ça a fonctionné.
nnm1 = dtTOSA << Col Number(colcol);
J'ai découvert que je devais également rappeler à JMP quelle était la table actuelle plus tard dans le code et que je devais utiliser {} dans Supprimer les colonnes avant que cela ne fonctionne. Pour une raison quelconque, JMP ne se soucie pas de la présence de ces accolades s'il est exécuté à partir d'une fenêtre de script.
L'extrait de code est maintenant celui-ci. Au fait, il s'agit d'un extrait d'un code plus long qui crée également cette table et une autre.
AllCols = dtTOSA << Get Column Names();
AllColNames = dtTOSA << Get Column Names(string);
currentDatatable(dtTOSA);
for(i=3, i<=n items(AllCols), i++,
colcol = AllCols[i];
cname = AllColNames[i];
nnm1 = dtTOSA << Col Number(colcol);
Fstr = "num(:\!""||cname||"\!"n)";
Fexpr = parse(Fstr);
newcol = dtTOSA << new column("Temp", numeric, set formula(eval(evalexpr(Fexpr))));
nnm2 = dtTOSA << Col Number(newcol);
if(nnm2 == nnm1,
currentDatatable(dtTOSA);
newcol << delete formula();
dtTOSA << Delete Columns({colcol});
wait(0);
newcol << set name(cname), //else
dtTOSA << Delete Columns({newcol});
);
);Cependant, il y a maintenant un autre problème. Même si je supprime l'ancienne colonne avant de renommer la nouvelle, JMP met un 2 indésirable après le nom de la colonne ! Encore une fois, il ne le fait pas à partir d'une fenêtre de script. J'ai essayé d'inclure une instruction wait(0) mais cela n'a pas aidé.
Comment cela peut-il être résolu ?
Ré: Syntaxe acceptable incohérenteEn fait, il n'effectue pas l'opération de suppression de colonne.
dtTOSA << Delete Columns({colcol});Il conserve donc la colonne de caractères d'origine et la nouvelle colonne numérique.
Ré: Syntaxe acceptable incohérenteÉtrangement, si la condition « else » est remplie, l'instruction de suppression fonctionne correctement.
Ré: Syntaxe acceptable incohérenteBien que la colonne soit référencée de 2 manières différentes (l'une comme nom de chaîne de texte, l'autre comme type de colonne), cela a finalement fonctionné. J'écris du code en jsl depuis 18 ans et je trouve toujours que le référencement des colonnes en tant que variables dans jsl est incohérent et déroutant.
AllCols = dtTOSA << Get Column Names();
AllColNames = dtTOSA << Get Column Names(string);
currentDatatable(dtTOSA);
for(i=3, i<=n items(AllCols), i++,
colcol = AllCols[i];
cname = AllColNames[i];
nnm1 = dtTOSA << Col Number(colcol);
Fstr = "num(:\!""||cname||"\!"n)";
Fexpr = parse(Fstr);
newcol = dtTOSA << new column("Temp", numeric, set formula(eval(evalexpr(Fexpr))));
nnm2 = dtTOSA << Col Number(newcol);
if(nnm2 == nnm1,
currentDatatable(dtTOSA);
newcol << delete formula();
dtTOSA << Delete Columns(eval(cname));
currentDatatable(dtTOSA);
newcol << set name(cname), //else
dtTOSA << Delete Columns({newcol});
);
);Ré: Syntaxe acceptable incohérenteJ'utilise toujours des chaînes de caractères comme base de mes colonnes, puis je construis mes références à partir d'elles selon mes besoins. J'ai trouvé que c'était la manière la plus flexible de gérer différents types de référencement.
Par exemple, si je prends votre script et que je fais quelques hypothèses sur son objectif (à partir de la troisième colonne, je les passe toutes en revue, je crée une nouvelle colonne de formule dans laquelle vous changez les valeurs en valeurs numériques, je compare les valeurs manquantes et j'exécute des actions en fonction du résultat), je l'écrirais comme ceci dans JMP18 :
Names Default To Here(1);
dtTOSA = New Table("Untitled",
Add Rows(4),
Compress File When Saved(1),
New Column("Column 1",
Numeric,
"Continuous",
Format("Best", 12),
Set Values([1, 2, 3, 4])
),
New Column("Column 2", Character, "Nominal", Set Values({"A", "1", "2", "3"})),
New Column("Column 3", Character, "Nominal", Set Values({"1", "2", "3", "4"})),
New Column("Column 4", Character, "Nominal", Set Values({"A", "B", "C", "D"}))
);
wait(1); // demo purposes
cols = dtTOSA << Get Column Names("String");
// Remove From(cols, 1, 2); // skipping this for demo purposes
For Each({colname}, cols,
// colname = cols[3]; // for testing
Eval(EvalExpr(
newcol = dtTOSA << New Column("Temp", numeric, Formula(
Num(Expr(Name Expr(As Column(dtTOSA, colname))))
));
));
newcol << Run Formulas;
newcol << delete formula();
orig_vals = Col Number(Column(dtTOSA, colname));
new_vals = Col Number(Column(dtTOSA, (newcol << get name)));
If(orig_vals == new_vals,
dtTOSA << Delete Columns(colname);
newcol << set name(colname);
,
dtTOSA << Delete Columns(newcol)
);
);
Et si je devais faire cela depuis le début mais en utilisant toujours une idée un peu similaire à la vôtre, je ferais (au moins à cette seconde) quelque chose comme ça
Names Default To Here(1);
dt = New Table("Untitled",
Add Rows(4),
Compress File When Saved(1),
New Column("Column 1",
Numeric,
"Continuous",
Format("Best", 12),
Set Values([1, 2, 3, 4])
),
New Column("Column 2", Character, "Nominal", Set Values({"A", "1", "2", "3"})),
New Column("Column 3", Character, "Nominal", Set Values({"1", "2", "3", "4"})),
New Column("Column 4", Character, "Nominal", Set Values({"A", "B", "C", "D"}))
);
wait(1); // demo purposes
cols = dt << Get Column Names("Character", "String"); // We only need to check character columns
For Each({colname}, cols,
dt_summary = dt << Summary(
Group(Eval(colname)),
Freq("None"),
Weight("None"),
Link to original data table(0),
output table name("Summar of " || colname),
Private
);
orig_vals = Col Number(Column(dt_summary, 1));
Column(dt_summary, 1) << Set Data Type("Numeric");
new_vals = Col Number(Column(dt_summary, 1));
Close(dt_summary, no save);
If(orig_vals == new_vals, // we can change
Column(dt, colname) << Set Data Type("Numeric");
Column(dt, colname) << Set Modeling Type("Continuous");
);
);
J'ai tendance à faire cela en utilisant Transform Each et Num, mais parfois cela peut suffire si vous laissez JMP faire les conversions (il y a des cas où vous ne voudrez peut-être pas le faire cependant..., voir Num() à partir de l'index de script et comment il se comporte avec Num("5%") par exemple. << Restrict évite ce comportement)
Ré: Syntaxe acceptable incohérenteJarmo,
Merci pour vos réflexions. J'ai parfois des milliers de colonnes et des dizaines de milliers de lignes, et la vitesse peut être un problème. La façon dont je le fais maintenant réduit en fait le temps à environ 1/3 de la façon dont je le faisais auparavant, mais cela peut encore prendre plusieurs minutes. Je pourrais expérimenter votre méthode un jour, mais je me demande si vous pensez que créer un tableau récapitulatif à chaque fois serait plus lent ou plus rapide.
En ce qui concerne la gestion des références de colonnes, j'ai essayé d'utiliser Column(dt, colname) mais cela ne fonctionne pas toujours. Mais dans votre script, vous utilisez également As Column(). En règle générale, As Column() est-il utilisé pour les formules ?
Ré: Syntaxe acceptable incohérente
@pcarroll1 a écrit :
En règle générale, As Column() est-il utilisé pour les formules ?
oui, soit sous forme de colonne (columnname) ou :column(dt, columnname)[]
Ré: Syntaxe acceptable incohérentePour la première « question » : si vous essayez d'optimiser la vitesse pour des cas d'utilisation spécifiques, il vous suffit d'essayer celle qui fonctionne le mieux car il existe de nombreuses méthodes différentes et la plus rapide peut dépendre beaucoup de vos données. Dans ce cas, j'ai utilisé le tableau récapitulatif (ou Summarize) pour éviter de vérifier les valeurs répliquées, mais comme je l'ai mentionné, cela dépend de vos données, de vos versions JMP et éventuellement d'autres choses...
Pour les références de colonnes, ma règle est la suivante : utilisez toujours le nom de la colonne et la référence de la table comme point de départ, et construisez la référence finale à partir d'eux . Ce que je considère comme une référence dépend de l'endroit et de la manière dont je l'utilise. Par exemple, si je crée une formule, je veux que ma formule référence les colonnes comme :mycol (et non AsColumn(mycol) ou Column(mycol)[], qui sont généralement également très bien). Et je peux obtenir le format :mycol en utilisant le style assez long de NameExpr(AsColumn(dt,colname)) avec évaluation de l'expression. En général, AsColumn(dt, colname) (OU dt:colname) est identique à Column(dt, colname)[Row()] (ou Column(dt, colname)[]), qui obtiendra la valeur de la ligne actuelle (dans mon esprit, ce n'est pas toujours comme ça. Par exemple, sur les plateformes, je considère que :mycol est une référence plutôt qu'une valeur spécifique sur une ligne...).
À titre d'exemple, cela renverra une valeur manquante car mycol sera évalué immédiatement et la valeur initiale de Row() est 0 dans JMP (ce n'est pas un problème à l'intérieur d'une formule car Row() sera mis à jour tout le temps)
Names Default To Here(1);
dt = open("$SAMPLE_DATA/Big Class.jmp");
colname = "age";
mycol = NameExpr(AsColumn(dt,colname));
show(mycol)
C'est la différence la plus difficile à comprendre avec les références de colonnes, As Column() (valeur de la ligne actuelle) vs Column() (référence à une colonne) dans JMP. Il est très difficile de comprendre comment elles fonctionnent... Je l'ai appris essentiellement en échouant de nombreuses fois. Et maintenant, j'ai une bonne idée de ce qu'il faut utiliser au départ lors de la construction d'une expression (je peux encore me tromper de temps en temps). Ce sujet est quelque chose sur lequel je souhaite écrire un article de blog à un moment donné car mes opinions (actuellement) peuvent différer de celles des autres et je me considère comme un assez bon scripteur JMP sans être un développeur JMP (JSL).
Une chose à noter ici : je ne suis pas un développeur JMP et je ne me soucie pas vraiment de la façon dont les développeurs pensent que JSL fonctionne (je suis parfois en désaccord avec les développeurs). Toutes mes réponses sont toujours basées sur mes expériences avec les versions de JMP que j'ai utilisées.
Je suis vraiment désolé si ce message est un peu déroutant (j'ai peut-être bu quelques bières ce soir:) ). Si vous souhaitez avoir plus d'explications sur mes opinions sur ce sujet, vous pouvez poster sur ce sujet (mais tagguez-moi avec @ pour que je le remarque plus facilement). Vous pouvez également m'envoyer un message privé si nécessaire.