Come creare una colonna media con JSL basata su colonne casualiVorrei creare un elenco di colonne basato su alcuni criteri di selezione. I nomi delle colonne non saranno noti in anticipo. Successivamente, utilizzerò questo elenco di colonne per creare una colonna con una formula che calcoli la media (o la deviazione standard o il valore assoluto) di tali colonne.
Esempio semplice di script che prende in considerazione solo colonne numeriche:
dt = Open( "$SAMPLE_DATA/Cars.jmp" );
ColList = {};
For(i=1, i<=NCols(), i++,
If(Column(i)<
<GETDATATYPE></GETDATATYPE>
<BR /> <BR /> <P>Si noti che ColList è un elenco valido di colonne. Quando questo viene inserito nella formula della prima colonna, l'anteprima nell'editor di formule mostra una valutazione corretta, ma la colonna rimane vuota. A quanto pare, è necessario inserire scalari, elenchi o matrici nella funzione Mean() (ma l'anteprima funzionerà comunque).</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 seconda colonna di formule aggiunge un AsColumn() attorno al riferimento alla colonna... il che è un po' controintuitivo dato che è già una colonna. Ma ora crea una lista, uno scalare o una matrice e la formula mean() funzionerà.</P> <P>Mi sembra di star complicando troppo le cose. Esiste un modo più semplice per generare proceduralmente una colonna di riepilogo di questo tipo?</P>
Oggetto: Come creare una colonna media con JSL basata su colonne casualiSolitamente, in casi semplici come questo, utilizzo la funzione Substitute per sostituire l'elenco con un'altra espressione.
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();
Oggetto: Come creare una colonna media con JSL basata su colonne casualiGrazie, ma questa rimane comunque una soluzione di livello avanzato per un problema semplice. Sono comunque curioso di vedere se qualcuno trova un modo più semplice per aggiungere riferimenti di colonna a una formula di colonna.
Oggetto: Come creare una colonna media con JSL basata su colonne casualiSupponiamo di avere una colonna denominata "TEST" nella tabella dt. Ci sono differenze tra la "base"
- Colonna(dt, "TEST")
- ComeColonna(dt, "TEST")
- "TEST"
- Nome Expr(Come Colonna(dt, "TEST"))
Scopri di più...
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));
Che tipo di soluzione stai cercando? Non si aggiungono riferimenti di colonna alle formule a meno che non si utilizzino le parentesi quadre [] o [Row()] con il riferimento. Se si ottengono le colonne come riferimenti (o stringhe), in genere è necessario convertirle in "accessi di colonna" per poterle utilizzare nelle formule.
Oggetto: Come creare una colonna media con JSL basata su colonne casualiHo inviato una segnalazione di bug a JMP.
Il problema risiede nel fatto che la formula di colonna non accetta argomenti Column("name"), ma questi devono essere prima racchiusi in un'espressione As Column(). Quando si utilizza l'editor di formule visuale, si inseriscono le colonne nei campi degli argomenti, quindi JSL dovrebbe rispecchiare lo stesso comportamento. L'aggiunta di questa funzionalità a JSL semplificherebbe notevolmente la creazione di formule di colonna tramite JSL.
A quanto pare, la finestra di anteprima nell'editor di formule interpreta correttamente questo dato, mostrando un'anteprima.
Oggetto: Come creare una colonna media con JSL basata su colonne casualiColumn() e AsColumn()/:colname non sono la stessa cosa e non devono essere usati in modo simile.
A mio parere, il problema risiede nell'editor di formule e nel modo in cui visualizza le formule create tramite JSL. Non rileva le formule errate (come in questo caso) e non mostra i messaggi di errore quando dovrebbe.
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
In questo caso dovrebbe essere visualizzato nelle proprietà della colonna
jthi_7-1788882167381.pngjthi_7-1788882167381.pngjthi_7-1788882167381.png
e questo nell'editor di formule
jthi_6-1788882151203.pngjthi_6-1788882151203.pngjthi_6-1788882151203.png
E se provi ad applicarlo, si verifica un errore di questo tipo
jthi_5-1788882131736.pngjthi_5-1788882131736.pngjthi_5-1788882131736.png
Se lo si corregge in Column()[] viene visualizzato correttamente e restituisce risultati corretti
jthi_0-1788880964367.pngjthi_0-1788880964367.pngjthi_0-1788880964367.png
Ma spetta agli sviluppatori di JMP decidere come ritengono che questo debba comportarsi.
Oggetto: Come creare una colonna media con JSL basata su colonne casualiJarmo ha sollevato punti validi e ha proposto una soluzione alternativa utilizzando Column("name")[]. Come accennato da Jarmo, l'utilizzo di Column("name")[] non ha un aspetto altrettanto gradevole nell'Editor di formule. La mia soluzione qui sotto non prende in considerazione questa opzione, ma spiega perché crea confusione a molti utenti. Ripete in gran parte quanto già scritto da Jarmo, ma dato che l'avevo già digitato...
In realtà, ciò che illustra lo script dell'utente non è un bug. Si tratta di un comportamento previsto, che evidenzia una confusione comune tra gli utenti riguardo al riferimento alle colonne e al funzionamento della valutazione delle formule di colonna.
Il punto cruciale della confusione sta nel comprendere la differenza tra la sintassi Column("name") e la sintassi :name. Entrambe sono modi legittimi per fare riferimento alle colonne in determinate circostanze, ma ciò che restituiscono è diverso. Nello specifico, Column("name") restituisce un riferimento a un oggetto colonna, mentre :name restituisce il valore nella colonna "name" della riga corrente. Tra l'altro, :name è la forma operatoriale della funzione As Column("name"). In altre parole, sono esattamente la stessa cosa.
Consideriamo il seguente script di esempio a scopo illustrativo. Questo script presuppone che la tabella dati Cars.jmp sia aperta e corrente nella sessione 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
Tenendo conto di queste informazioni, dovrebbe essere chiaro che JMP non può calcolare la media di un insieme di riferimenti di colonna. Questo è il motivo per cui la prima formula di colonna non viene valutata correttamente. La funzione Media() necessita di valori, che vengono forniti nella seconda formula di colonna. Quando una tabella dati valuta le formule di colonna, imposta la riga corrente a 1, quindi valuta l'espressione memorizzata nella proprietà Formula. Inserisce il valore restituito nella cella della colonna nella riga corrente. Quindi imposta la riga corrente al valore successivo e ripete il processo. Questi passaggi vengono ripetuti fino a quando la formula non viene valutata per l'ultima riga. Di conseguenza, la sintassi della formula di colonna deve essere tale da poter essere valutata per ogni riga della tabella dati.
A mio avviso, c'è un risultato inaspettato nel tuo script di esempio. Ovvero, la sintassi `As Column(Column("name"))` viene valutata allo stesso modo di `As Column("name")`. Mi aspettavo che generasse un errore, ma JMP la accetta e interpreta correttamente l'intento. Questo è il vantaggio (a volte) di un linguaggio di scripting rispetto a un linguaggio di programmazione formale. Tuttavia, non consiglierei di utilizzare questa sintassi perché potrebbe non funzionare in futuro.
Penso che il modo migliore per raggiungere l'obiettivo, dato lo script di esempio, sia quello di abbandonare il primo approccio a livello di formula di colonna e utilizzare il secondo. Un'ulteriore modifica consiste nel definire ColList come un elenco di nomi di colonna anziché di riferimenti di colonna. Ecco una versione modificata dello script di esempio dell'utente che dovrebbe essere affidabile.
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 ) ) ) ) ) );
Oggetto: Come creare una colonna media con JSL basata su colonne casualiSebbene da un punto di vista teorico e di implementazione pratica tu abbia probabilmente assolutamente ragione... l'interfaccia utente non si comporta in questo modo. Seleziono le colonne dalla tabella e le trascino sull'operatore mean() e il calcolo viene eseguito. Tuttavia, tramite scripting non posso selezionare le colonne, ma devo selezionare oggetti stringa (che corrispondono ai nomi delle colonne) e poi dire a JSL di interpretarli come riferimenti alle colonne, che posso poi inserire nell'operatore mean. Non sarebbe una soluzione semplice estendere gli operatori JSL in modo che trattino Column("Name") come oggetti colonna che possono essere indicizzati alla riga? Ciò avrebbe molto più senso intuitivo e rispecchierebbe il comportamento dell'interfaccia utente e quindi il modo di pensare dell'utente. Come hai giustamente sottolineato, c'è molta confusione tra gli utenti su questo punto.
E per quanto riguarda le osservazioni di Jarmo: i messaggi di errore nell'editor di formule necessitano di maggiore chiarezza e coerenza. Ripeto: si noti che l'anteprima mostra una valutazione corretta, mentre la formula non viene valutata quando si utilizza la sintassi Column("Name").