[JSL] Script pour un test T bilatéral sur un grand nombre de mesuresBonjour à tous,
Je voudrais écrire un script JSL pour automatiser un TOST (Two-One Side T-Test) sur un grand nombre de métriques (500+).
Le TOST fonctionne par paire de « niveaux », donc travailler avec 2x niveaux est facile, car il ne nécessite qu'une seule rangée par « paire ».
J'ai déjà écrit un script qui fonctionne bien pour les niveaux 2x en générant un « tableau de données combiné » et en y ajoutant plus de colonnes avec une formule, qui aboutissent aux résultats suivants : « Équivalent » ou « Non équivalent ».
Le problème s'épaissit lorsque je souhaite travailler avec plus de 2 niveaux. Il faudrait alors trouver toutes les paires uniques possibles de « niveaux », puis exécuter les calculs TOST pour chaque combinaison de métriques + paires de niveaux.
J'ai trouvé un moyen (sur ce forum) de trouver toutes les paires uniques possibles à partir d'une liste et de les mettre dans un tableau ou dans une liste imbriquée (NchooseKmatrix()).
Mais je suis coincée là. Ce dont j'ai besoin c'est :
1- pour remplir une nouvelle table avec toutes les combinaisons possibles de métriques (colonne 1) et toutes les paires de niveaux possibles (colonne 2 et colonne 3).
2- Ajoutez ensuite les statistiques pour chaque paire de niveaux sur chaque ligne
À partir de ce point, je pourrai comprendre les mathématiques pour finaliser le TOST.
J'ai joint un script qui génère un tableau factice, puis un tableau de données combiné à partir de l'analyse à sens unique, puis ma tentative infructueuse de créer un troisième tableau avec toutes les combinaisons de métriques + paires uniques de niveaux
Merci d'avance pour votre aide
Names Default To Here( 1 );
clear symbols();
Deletesymbols();
//Create table with random distribution (table 1)
dt = New Table( "tabletest",
Add Rows( 500 ),
New Column( "Product", Character, "Nominal", formula("Product " ||char( Random Integer( 1, 4 )))),
New Column( "Metric1", Numeric, "Continuous", formula( Random Normal( 10, 1 ) ) ),
New Column( "Metric2", Numeric, "Continuous", formula( Random Gamma( 10, 1 ) ) ),
New Column( "Metric3", Numeric, "Continuous", formula( Random Gamma( 10, 2 ) ) )
);
Column( dt, "Metric1" ) << set property( "spec limits", {LSL( 5 ), USL( 25 ), Show Limits( 0 )} );
Column( dt, "Metric2" ) << set property( "spec limits", {LSL( 0 ), USL( 40 ), Show Limits( 0 )} );
Column( dt, "Metric3" ) << set property( "spec limits", {LSL( 5 ), USL( 40 ), Show Limits( 0 )} );
dt << save( "$Desktop\tabletest.jmp" );
//Get a list from all unique Product
SplitBy = "Product";
summarize(ColumnSplitBy=by(Column (SplitBy)));
show(ColumnSplitBy);
For( i = N Items( ColumnSplitBy ), i > 0, i--,
If( ColumnSplitBy[i] == "",
Remove From( ColumnSplitBy, i, 1 );
)
);
//Get Column name
MetricCols = dt << Get Column Names( numeric, continuous, "string" );
//Get all unique combo of 2 Products
ColumnSplitByCombo = aslist( nchoosekMatrix(nitems(ColumnSplitBy), 2));
show (ColumnSplitByCombo);
//Create a combinaed datatable with stats (Table 2)
ow = dt << Oneway(
Y(Eval(MetricCols)),
X(Eval(SplitBy)),
Means and Std Dev(1),
SendToReport(
Dispatch(
{"Means and Std Deviations"},
"Std Dev Lower 95%",
NumberColBox,
{Visibility("Visible")}
),
Dispatch(
{"Means and Std Deviations"},
"Std Dev Upper 95%",
NumberColBox,
{Visibility("Visible")}
)
),
Invisible
);
tb = Report(ow[1])[Outline Box("Means and Std Deviations"), Table Box(1)];
dt2 = tb << Make Combined Data Table;
tb << close window;
//Create new table for the result, each row has a unique pair of Levels
dt3 = astable( nchoosekMatrix(nitems(ColumnSplitBy), 2), << column names({"x", "y"}) );
dt3 << new column ("first", character, << set values ( ColumnSplitBy[dt3:x << get values]));
dt3 << new column ("second", character, << set values ( ColumnSplitBy[dt3:y << get values]));
dt3 << delete columns (1::2);
//Create a nested list with each pair of levels
Listdt3 = aslist( nchoosekMatrix(nitems(ColumnSplitBy), 2));
show (Listdt3);
// I tried to use associate array() to match the level and name but couldn't make it work- Prédicateur
Automatisation et scriptsRe: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresJ'ai joint un document "Untitled.png" avec des captures d'écran pour (je l'espère) mieux expliquer ma demande.
Merci!
Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresVous pouvez par exemple d'abord empiler votre colonne de groupe, la mettre à jour avec les résultats et la diviser à nouveau.
Cet exemple ne prend pas en compte le fait qu'il peut y avoir plusieurs métriques
// Loop over Metrics and perform these for each of them
// Concatenate results into single table
dt3 = As Table(NChooseK Matrix(N Items(ColumnSplitBy), 2), <<COLUMN names=""></COLUMN>// Metrics should be taken into account here OR stacked table should contain them
dt4 << Update(
With(dt2),
Match Columns(:Data = :Level)
);
ou n'a pas la séparation finale qui ressemble très probablement à ceci

Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresBonjour @Voizingu : Le TOST vérifie simplement si l'intervalle de confiance de 100(1-2alpha)% est entièrement contenu dans certaines limites d'équivalence ; donc, peut-être qu'une solution de contournement adéquate serait d'utiliser la procédure de comparaisons multiples Fit Y by X pour effectuer toutes les combinaisons à votre place ?
Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresExiste-t-il une raison pour laquelle vous ne pouvez pas utiliser le test d’équivalence intégré dans la plateforme Oneway ?
Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresBonjour Jarmo,
Stack > Update > Split est une excellente idée !!!
J'ai réussi à l'implémenter avec succès, mais mon code est un peu sale (beaucoup de boucles For(), étapes intermédiaires,...).
Au lieu de:
- Concaténer le tableau plusieurs fois
- Puis remplir une colonne à partir d'une liste de métriques répétées
J'aimerais m'améliorer dans l'optimisation de mon code.
Existe-t-il un moyen de remplir dt5 de manière plus propre/optimisée ? (en utilisant peut-être des commandes JMP natives ?)
J'aimerais avoir vos suggestions à ce sujet
Mais en tout cas, merci beaucoup de m'avoir aidé à ce sujet 
- Prédicateur
Names Default To Here( 1 );
clear symbols();
Deletesymbols();
//Create table with random distribution (table 1)
dt = New Table( "tabletest",
Add Rows( 5000 ),
New Column( "Product", Character, "Nominal", formula("Product " ||char( Random Integer( 1, 4 )))),
New Column( "Metric1", Numeric, "Continuous", formula( Random Normal( 10, 1 ) ) ),
New Column( "Metric2", Numeric, "Continuous", formula( Random Gamma( 10, 1 ) ) ),
New Column( "Metric3", Numeric, "Continuous", formula( Random Gamma( 10, 2 ) ) ),
);
Column( dt, "Metric1" ) << set property( "spec limits", {LSL( 5 ), USL( 25 ), Show Limits( 0 )} );
Column( dt, "Metric2" ) << set property( "spec limits", {LSL( 0 ), USL( 40 ), Show Limits( 0 )} );
Column( dt, "Metric3" ) << set property( "spec limits", {LSL( 5 ), USL( 40 ), Show Limits( 0 )} );
dt << save( "$Desktop\tabletest.jmp" );
//Get a list from all unique Product
SplitBy = "Product";
summarize(ColumnSplitBy=by(Column (SplitBy)));
show(ColumnSplitBy);
For( i = N Items( ColumnSplitBy ), i > 0, i--,
If( ColumnSplitBy[i] == "",
Remove From( ColumnSplitBy, i, 1 );
)
);
//Get Column name
MetricCols = dt << Get Column Names( numeric, continuous, "string" );
show(MetricCols);
//Get all unique combo of 2 Products
ColumnSplitByCombo = aslist( nchoosekMatrix(nitems(ColumnSplitBy), 2));
show (ColumnSplitByCombo);
//Create a combinaed datatable with stats (Table 2)
ow = dt << Oneway(
Y(Eval(MetricCols)),
X(Eval(SplitBy)),
Means and Std Dev(1),
SendToReport(
Dispatch(
{"Means and Std Deviations"},
"Std Dev Lower 95%",
NumberColBox,
{Visibility("Visible")}
),
Dispatch(
{"Means and Std Deviations"},
"Std Dev Upper 95%",
NumberColBox,
{Visibility("Visible")}
)
),
Invisible
);
tb = Report(ow[1])[Outline Box("Means and Std Deviations"), Table Box(1)];
dt2 = tb << Make Combined Data Table;
tb << close window;
//Create new table for the result, each row has a unique pair of Levels
dt3 = astable( nchoosekMatrix(nitems(ColumnSplitBy), 2), << column names({"x", "y"}) );
dt3 << new column ("first", character, << set values ( ColumnSplitBy[dt3:x << get values]));
dt3 << new column ("second", character, << set values ( ColumnSplitBy[dt3:y << get values]));
dt3 << delete columns (1::2);
//Create a nested list with each pair of levels
Listdt3 = aslist( nchoosekMatrix(nitems(ColumnSplitBy), 2));
show (Listdt3);
// I tried to use associate array() to match the level and name but couldn't make it work
// Loop over Metrics and perform these for each of them
// Concatenate results into single table
dt3 = As Table(NChooseK Matrix(N Items(ColumnSplitBy), 2), <<COLUMN names=""></COLUMN>Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresBonjour MRB3855,
Vous soulevez un excellent point, je ne voulais pas mettre trop d'informations dans mon premier message pour me concentrer sur mon problème de script, mais dans mon code initial (qui fonctionne pour 2 niveaux), j'ai défini les limites d'équivalence à 5% de la plage [LSL;USL].
Il s'agit bien sûr d'une valeur arbitraire que je peux modifier si nécessaire.
Il me permet de passer au crible plus de centaines de métriques et de signaler les métriques « Non équivalentes » à partir de ces critères, qui sont généralement au nombre d'une douzaine.
Ensuite, à partir de cette liste, je peux effectuer une analyse approfondie :
- Analyse de la variance
- TOST avec une gamme appropriée
- etc...
Pour votre deuxième point, si je comprends bien, vous suggérez d'exécuter la plateforme TOST pour chaque métrique et de sélectionner les données et de les placer dans un tableau via Display Box() ? Si tel est le cas, c'est en effet une solution possible, mais je préférerais exécuter les calculs moi-même pour comprendre le principe TOST et également gagner du temps de traitement.
J'espère que cela a du sens:)
Merci pour votre aide
- Prédicateur
Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresBonjour Marc,
Oui, au début, j'ai pensé à utiliser la plateforme TOST et à sélectionner les statistiques avec Display Box(), mais j'ai préféré l'approche différente pour calculer chaque paramètre individuellement pour obtenir les mêmes résultats que ceux donnés par la plateforme.
Après coup, cela aurait peut-être été une approche plus rapide que de réinventer la roue, mais j'ai maintenant investi tellement de temps là-dedans, et je suis si près d'y parvenir que je pourrais aussi bien finir ce que j'ai commencé (à la dure), haha !
L’un des avantages de cela est que je comprends maintenant chaque étape de la méthode TOST.
Merci
- Prédicateur
Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresJ'utiliserais probablement des boucles moi-même, mais vous pouvez le faire avec certaines opérations matricielles. Ce script nécessiterait une réécriture pour le rendre plus facile à lire à mon avis (variables mieux nommées, utilisation du nom de la table de sortie, fermeture des tables inutiles et nettoyage général)
Voir plus...
Names Default To Here(1);
//Create table with random distribution (table 1)
dt = New Table("tabletest",
Add Rows(5000),
New Column("Product",
Character,
"Nominal",
formula("Product " || Char(Random Integer(1, 4)))
),
New Column("Metric1", Numeric, "Continuous", formula(Random Normal(10, 1))),
New Column("Metric2", Numeric, "Continuous", formula(Random Gamma(10, 1))),
New Column("Metric3", Numeric, "Continuous", formula(Random Gamma(10, 2))),
);
Column(dt, "Metric1") << set property("spec limits", {LSL(5), USL(25), Show Limits(0)});
Column(dt, "Metric2") << set property("spec limits", {LSL(0), USL(40), Show Limits(0)});
Column(dt, "Metric3") << set property("spec limits", {LSL(5), USL(40), Show Limits(0)});
SplitBy = "Product";
Summarize(ColumnSplitBy = by(Column(SplitBy)));
MetricCols = dt << Get Column Names(numeric, continuous, "string");
ColumnSplitByCombo = As List(NChooseK Matrix(N Items(ColumnSplitBy), 2));
//Create a combinaed datatable with stats (Table 2)
ow = dt << Oneway(
Y(Eval(MetricCols)),
X(Eval(SplitBy)),
Means and Std Dev(1),
SendToReport(
Dispatch({"Means and Std Deviations"}, "Std Dev Lower 95%", NumberColBox,
{Visibility("Visible")}
),
Dispatch({"Means and Std Deviations"}, "Std Dev Upper 95%", NumberColBox,
{Visibility("Visible")}
)
),
Invisible
);
tb = Report(ow[1])[Outline Box("Means and Std Deviations"), Table Box(1)];
dt2 = tb << Make Combined Data Table;
tb << close window;
//Create a nested list with each pair of levels
Listdt3 = As List(NChooseK Matrix(N Items(ColumnSplitBy), 2));
mcols = N Items(MetricCols);
l = Repeat(Listdt3, mcols);
m = J(N Items(l) / mcols, mcols) :*</img> (1::mcols);
mfinal = Sort Ascending(Shape(m, 1, N Items(l)));
dt3 = As Table(Matrix(l), <<COLUMN names=""></COLUMN>
</CODE><NOSCRIPT><CODE class=" language-jsl"><DIV class="lia-spoiler-noscript-container"><DIV class="lia-spoiler-noscript-content">Noms par défaut ici(1); //Créer une table avec une distribution aléatoire (table 1) dt = New Table("tabletest", Add Rows(5000), New Column("Product", Character, "Nominal", formula("Product " || Char(Random Integer(1, 4))) ), New Column("Metric1", Numeric, "Continuous", formula(Random Normal(10, 1))), New Column("Metric2", Numeric, "Continuous", formula(Random Gamma(10, 1))), New Column("Metric3", Numeric, "Continuous", formula(Random Gamma(10, 2))), ); Column(dt, "Metric1") << set property("spec boundaries", {LSL(5), USL(25), Show Limits(0)}); Column(dt, "Metric2") << set property("spec boundaries", {LSL(0), USL(40), Show Limits(0)}); Column(dt, "Metric3") << set property("spec boundaries", {LSL(5), USL(40), Show Limits(0)}); SplitBy = "Product"; Summarize(ColumnSplitBy = by(Column(SplitBy))); MetricCols = dt << Obtenir les noms de colonnes (numérique, continu, "chaîne"); ColumnSplitByCombo = As List(NChooseK Matrix(N Items(ColumnSplitBy), 2)); //Créer un tableau de données combiné avec des statistiques (Tableau 2) ow = dt << Oneway( Y(Eval(MetricCols)), X(Eval(SplitBy)), Moyennes et écart type(1), SendToReport( Dispatch({"Moyennes et écarts type"}, "Écart type inférieur 95%", NumberColBox, {Visibility("Visible")} ), Dispatch({"Moyennes et écarts type"}, "Écart type supérieur 95%", NumberColBox, {Visibility("Visible")} ) ), Invisible ); tb = Report(ow[1])[Outline Box("Moyennes et écarts type"), Table Box(1)]; dt2 = tb << Créer un tableau de données combiné; tb << fermer la fenêtre; //Créer une liste imbriquée avec chaque paire de niveaux Listdt3 = As List(NChooseK Matrix(N Items(ColumnSplitBy), 2)); mcols = N Items(MetricCols); l = Repeat(Listdt3, mcols); m = J(N Items(l) / mcols, mcols) (1::mcols); mfinal = Sort Ascending(Shape(m, 1, N Items(l))); dt3 = As Table(Matrix(l), < <COLUMN names=""></COLUMN></DIV></DIV>
<P><SPAN class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><span class="lia-inline-image-display-wrapper" image-alt="jthi_1-1724774273332.png" style="width: 400px;"><img src="https://us.v-cdn.net/6038925/uploads/images/67576i7A33F8F17FEAD03D/jthi_1-1724774273332.png" role="button" title="jthi_1-1724774273332.png" alt="jthi_1-1724774273332.png" /></span></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></P>
<P><SPAN class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="jthi_2-1724774284315.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_2-1724774284315.png" style="width: 304px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_2-1724774284315.png" style="width: 304px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_2-1724774284315.png" style="width: 304px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_2-1724774284315.png" style="width: 304px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_2-1724774284315.png" style="width: 304px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_2-1724774284315.png" style="width: 304px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_2-1724774284315.png" style="width: 304px;"><span class="lia-inline-image-display-wrapper" image-alt="jthi_2-1724774284315.png" style="width: 304px;"><img src="https://us.v-cdn.net/6038925/uploads/images/67577i906F6E675ADD899F/jthi_2-1724774284315.png" role="button" title="jthi_2-1724774284315.png" alt="jthi_2-1724774284315.png" /></span></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></P>
<P><SPAN class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><SPAN class="lia-inline-image-display-wrapper" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><span class="lia-inline-image-display-wrapper" image-alt="jthi_0-1724774190734.png" style="width: 400px;"><img src="https://us.v-cdn.net/6038925/uploads/images/67575i9361F045B1E7C693/jthi_0-1724774190734.png" role="button" title="jthi_0-1724774190734.png" alt="jthi_0-1724774190734.png" /></span></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></SPAN></P>
<P> </P> Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresSalut Jarmo,
Merci pour votre réponse rapide.
Cette ligne est en panne
m = J(N Items(l) / mcols, mcols) (1::mcols);
Pouvez-vous expliquer à quoi cela sert ?
Je n'utilise généralement pas de matrices, j'ai essayé de me déboguer mais je n'ai pas réussi...
Merci pour votre aide
Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresPour une raison quelconque, il manque:*
m = J(N Items(l) / mcols, mcols) :*</img> (1 :: mcols);
Le but est de créer une matrice comme celle-ci

que vous convertissez ensuite en

en utilisant la forme.
Utilisez également les boucles, elles sont généralement beaucoup plus faciles à lire et à comprendre que les étranges « astuces » matricielles.
Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresSalut Jarmo,
J'ai testé plusieurs versions de cette ligne, en ajoutant des caractères spéciaux qui pourraient être perdus dans la traduction, mais non...
Cette ligne ne fonctionne pas de mon côté (j'utilise JMP Pro 17)

Ce n'est pas grave, cette optimisation utilisant Matrix est vraiment sympa à avoir. Comme tu l'as dit, l'utilisation de boucles fonctionne aussi, donc je vais opter pour ça:)
Merci encore d'avoir pris le temps de m'aider (encore une fois) !

- Prédicateur
Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresJ'ai joint la partie du code qui se casse dans la communauté en tant que capture d'écran

Il s'agit d'une multiplication élément par élément de matrices E Mult()
@Ryan_Gilmore La communauté JMP mange:* (: * espace ajouté ici)
Bloc de code JSL :
m = J(N Items(l) / mcols, mcols) :*</img> (1::mcols);
Texte:
m = J(N éléments(l) / mcols, mcols):* (1::mcols);
Capture d'écran pendant l'édition

Capture d'écran de l'aperçu

Re: [JSL] Script pour un test T bilatéral sur un grand nombre de mesuresBonjour @Voizingu Tout est dit, il semble que vous ayez une solution qui fonctionne pour vous. Excellent ! Cependant, pour ne pas le perdre, l'intervalle de confiance doit être un intervalle de 100(1-2alpha)%. Autrement dit, si vous voulez que votre taux d'erreur de type 1 soit de 5 %, l'intervalle utilisé pour juger de l'équivalence doit être un intervalle de confiance de 90 % (et non de 95 %). Il s'agit d'un test unilatéral à deux côtés … chaque côté étant testé à alpha = 0,05. Voir ci-joint,