Dovresti scorrere una tabella di dati o utilizzare Recode o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiUna recente discussione comunitaria Re: script per trovare e sostituire un valore numerico con un valore mancante nell'intera tabella aveva una voce molto bella fornita da @SDF1 che è stata scelta come soluzione
names default to here(1);
dt=current data table();
For( i = 1, i <= N Rows( dt ), i++,
For( l = 1, l <= N Cols( dt ), l++,
If( Column( l )[i] == 999,
Column( l )[i] = .
)
)
);
Quando ho visto la soluzione, mi è venuto in mente un vecchio insegnamento che affermava approssimativamente: "Non scorrere una tabella di dati.Il ciclo è lento. Usa le funzionalità integrate di JMP"
Così ho iniziato a modificare @SDF1 codice.
Ho determinato che il mio standard di fallback di "Get Rows Where()" sarebbe stato più veloce.Dopotutto, consente di impostare tutte le righe trovate con un'istruzione di assegnazione, dopo che il "molto veloce" Get Rows Where() ha trovato le righe..
Un'altra soluzione, che ho visto spinto raccomandato dalla comunità è la funzione Recode in JMP.
Così:
Ipotesi: le funzioni JMP integrate di Ottieni righe dove e Ricodifica saranno più veloci di Loop down e su un'intera tabella di dati.
Ho selezionato la tabella dati Semiconductor Capability come una tabella di buone dimensioni, 132 colonne e 1455 righe
Ho scritto un piccolo script che imposta 10 valori casuali in ogni colonna su 999.
names default to here(1);
dt=current data table();
for(i=5,i<=ncols(dt),i++,
if(col stddev(ascolumn(dt,i))!=0,
for(k=1,k<=10,k++,
column(dt,i)[randominteger(1,1455)]=999;
)
));
Questo è il valore originale da modificare nella Discussione sopra menzionata.Il 999 deve essere modificato in mancante (.) dagli script.
Metodo:
- Avvio di JMP 16.
- Leggi la tabella dei dati sulla capacità dei semiconduttori
- Eseguire lo script per impostare i 999 valori in ciascuna colonna
- Ripeti i 2 passaggi precedenti per ciascuno dei 3 metodi e ricodifica il tempo fino al millisecondo.
- Ripetere i passaggi precedenti per JMP15
Ecco lo script per Recode
Names Default To Here( 1 );
dt = Current Data Table();
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
dt << Recode Column(
As Column( dt, i ),
{If( _rcNow == 999, ., _rcNow )},
Target Column( As Column( dt, i ) )
)
);
show(hptime()-start)
Il codice per Ottieni righe dove
names default to here(1);
dt=current data table();
start=hptime();
for(i=5,i<= ncols(dt),i++,
column(dt,i)[dt<<GET rows="" where=""></GET>
Ed ecco i risultati sorprendenti

Il For Loop vince a mani basse.E dai risultati, il Get Rows Where dovrebbe essere usato con parsimonia.
Commenti e correzioni sono ben accetti......
Tabella datiSceneggiaturaRi: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiSi, capisco @brady_brady . Si potrebbe fare questo, tuttavia:
NamesDefaultToHere(1);
// Make an example table with some rogue '999' values
nr = 10; // Number of rows
nc = 10; // Number of columns
p = 0.1; // Fraction of rogue values
val = 999; // Rogue value
m = J(nr, nc, RandomInteger(1, 10));
m = Shape(m, nr*nc, 1);
m[RandomIndex(nr*nc, Floor(nr*nc*p))] = val;
m = Shape(m, nr, nc);
dt = AsTable(m);
dt << setName("Rogue Values");
Wait(3);
// Set rogue values to '.'
mask = J(nr*nc, 1, 1);
mask[Loc(dt[0,0] == val)] = .;
mask = Shape(mask, nr, nc);
dt[0,0] = mask :*</img> dt[0,0];
Ma dubito fortemente che questo sarebbe più veloce di quello che hai già, non ultimo a causa della moltiplicazione saggia dell'elemento.
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiIl confronto è un po' sbagliato qui -- la funzionalità "Ottieni righe dove" valuterà la sua espressione su ogni riga, quindi è necessario ridurre al minimo eventuali ricerche superflue prima di eseguire il ciclo -- in particolare, il tuo iteratore è esterno e dovrà fare un po' di movimento per trovarlo su ogni riga.Inoltre, valuterà la funzione AsColumn su ogni riga, cercando ogni volta sia 'dt' che 'i'.Questo è _molto_ costoso.Il modo corretto per farlo sarebbe il seguente:
names default to here(1);
dt=current data table();
start=hptime();
names = dt << Get Column Names( "string" );
for(i=5,i<= ncols(dt),i++,
Eval( Parse( Eval InserT( JSL Quote(
column(dt,i)[dt<<GET rows="" where=""></GET>
Noterai che questo viene eseguito nell'ordine di 3000 volte più veloce, il che dovrebbe renderlo paragonabile se non migliore degli altri metodi che hai
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiSì ... l'ostacolo è che mentre è possibile accedere alle matrici con un singolo indice (che presuppone il layout della riga principale), le tabelle di dati non possono. Quindi, purtroppo, non esiste un analogo
m[loc(m, 9999)] = .
dove m è una matrice pxq, nel mondo della tabella dei dati... da qui le righe che precedono e seguono questa nel codice sopra. Sebbene il codice sia ancora veloce, sarebbe DAVVERO veloce se fosse disponibile l'accesso a indice singolo per le tabelle.
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiPer il ' sovraccarico nella creazione di una matrice' lo sospetto indicizzazione tabella dati potrebbe aiutare.@Craige_Hales saprebbe.
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiEcco un modo per evitare il loop, anche se c'è un sovraccarico nella creazione di una matrice e nell'assegnazione successiva alla tabella. Questo approccio funziona rapidamente su questi dati, più o meno come loc_2d, ma quando la tabella diventa enorme, mi aspetto che le sue prestazioni relative ne risentano, ma non l'ho verificato.
expr_mat = expr(
m = dt[0, 5 :: N Col( dt )];
m[Loc( m, 999 )] = .;
dt[0, 5 :: N Col( dt )] = m;
);
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiForse sono andato un po 'troppo in profondità su questo (ma almeno ho avuto un'idea su come eseguire questo tipo di test in seguito, se necessario).
Ho scritto una sorta di script di test con espressioni diverse per testare diversi modi di sostituire il 999 con quello mancante. Ho testato con due set di dati (Semiconductor Capability.jmp e Probe.jmp) e ho modificato la quantità di valori mancanti nelle colonne.
Loc() è il più veloce a sostituire i valori (nessuna sorpresa lì). Missing Value Codes() è "sempre" veloce ma ha casi d'uso un po' più limitati rispetto a Loc() ed è un po' più una seccatura da usare se ci fossero più valori da sostituire.

Il più veloce è stato loc_2d (non si è preoccupato di cambiare i nomi delle variabili da questo: Utilizzo di Loc con una matrice 2D ). Devo ancora eseguire il ciclo per ottenere i valori impostati (almeno per quanto ne so), quindi molto probabilmente il motivo per cui questo è più veloce del solo Loc() è che salterà alcune colonne. Di seguito sono expr_loc2d e expr_loc:
expr_loc = Expr(
for(i=5,i<= ncols(testData),i++,
column(testData,i)[Loc(testData[0,i], 999)]=.;
);
);
expr_loc_2d = Expr(
mat = testData[0,5::NCols(testData)];
nr = N Rows(mat);
nc = N Cols(mat);
blacklocs = Loc(mat, 999) - 1;
rowlocs = Floor((blacklocs) / nc ) + 1;
collocs = Mod((blacklocs), nc ) + 1 + 4;
uniqCols = Associative Array(collocs) << get keys;
For(i_2d = 1, i_2d <= N Items(uniqCols), i_2d++,
testData[rowlocs[Loc(collocs, uniqCols[i_2d])], uniqCols[i_2d]] = .;
);
);
Inoltre sembra essere importante usare AsColumn(Column(dt, i)) come @Ryan_Gilmore ha detto (non si è nemmeno preoccupato di testare << ottenere righe dove senza di essa, perché sarà molto lento), ma ho testato la ricodifica con e senza Column(). Ho anche appena notato che ho perso una Column() dalla ricodifica, quindi esegui un paio di test rapidi (non allegati nei dati o nello script):
Differenza abbastanza grande tra questi tre:
expr_recode_ascolumn = Expr(
For(i = 5, i <= N Cols(testData), i++,
testData << Recode Column(
As Column(dt, i),
{If( _rcNow == 999, ., _rcNow)},
Target Column(As Column(testData, i))
)
);
);
expr_recode_ascolumn_column = Expr(
For(i = 5, i <= N Cols(testData), i++,
testData << Recode Column(
As Column(dt, i),
{If( _rcNow == 999, ., _rcNow)},
Target Column(As Column(Column(testData, i)))
)
);
);<BR />
expr_recode_ascolumn_column_column = Expr(
For(i = 5, i <= N Cols(testData), i++,
testData << Recode Column(
As Column(Column(dt, i)),
{If( _rcNow == 999, ., _rcNow)},
Target Column(As Column(Column(testData, i)))
)
);
);

In allegato lo script del test e alcuni dati sui risultati. Lo script molto probabilmente avrà degli errori qua e là. Dovrebbe essere abbastanza facile aggiungere nuove espressioni se qualcuno vuole farlo. Una cosa che non ho testato affatto è l'utilizzo di << Begin/End data update.
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiDiscussione interessante! La notazione della matrice della tabella dati, che penso sia apparsa per la prima volta in JMP 13, è abbastanza efficiente per l'assegnazione.
Per questo particolare problema è quasi 500 volte più veloce del ciclo for (0,003 contro 1,5 secondi, laptop Mac JMP 15).
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
Try( dt[Loc( dt[0, i], 999 ), i] = . )
);
Show( HP Time() - start);
Il try() è necessario per evitare un errore per le colonne senza "999".
Il ciclo sulle colonne è ancora necessario perché l'assegnazione diretta per l'intera matrice, che per un momento ho pensato sarebbe stata ancora più veloce, non funziona. Errore: "Più pedici richiedono singoli pedici a ogni livello interno nell'accesso o nella valutazione...", che a pensarci bene ha senso.
// The left Data Table matrix syntax is OK on its own, but not for assignment.
dt[0, 5 :: N Col( dt )][Loc( dt[0, 5 :: N Col( dt )], 999 )] = .;
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiAvrei potuto essere cauto nell'usare i loop a un certo punto, ma dopo aver seguito un corso di algoritmo (che non ho mai finito ..) un po' meno. Devi solo essere efficiente con loro, molto spesso esegui il loop troppo (complessità temporale e notazione Big O). Anche l'uso dei loop è molto più semplice che cercare di risolvere problemi con la matematica pura.
Con JMP di solito vado solo con le opzioni sicure che ho imparato ad un certo punto, poiché la velocità è raramente un problema. Ma quando il tempo è un problema (un'applicazione ha impiegato più di 6 minuti per aprirsi al lavoro) inizierò a cercare modi per renderlo più veloce (sono riuscito a farlo partire in meno di 2 minuti). In questo caso sono riuscito a renderlo più veloce utilizzando Loc() con diverse combinazioni di altre funzioni (cancella riga, imposta stato riga).
Oltre a Loc(), l'uso di Summarize() sembra essere "molto" più veloce rispetto alla mia opzione preferita da tempo per ottenere valori univoci nella colonna (array associativo() << get keys). Quando il conteggio delle righe aumenta, l'array associativo() << get keys diventa sempre più lento e Summarize() non sembra soffrire dello stesso problema, almeno non così velocemente. Quindi ho provato a iniziare a utilizzare di più Summarize() (non so mai quanto siano alti i datatable).
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiQuindi saltiamo AsColumn() con (andando di più con un'intuizione e non ho testato che questo sostituirà tutti i valori corretti):
start=hptime();
for(i=5,i<= ncols(dt),i++,
column(dt,i)[Loc(dt[0,i], 999)]=.;
if(mod(i,10)==0,show(i));
);
show(hptime()-start);
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiSono d'accordo sul fatto che Loc() sia il metodo migliore.
Per me, il rallentamento sembra verificarsi a causa di As Column. Vedo una differenza significativa tra,
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
As Column( column(dt, i) );
);
Show( HP Time() - start );
e
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
As Column( dt, i );
);
Show( HP Time() - start );
Modifica della sintassi As Column nel codice da @txnelson domanda originale, il ciclo For è ancora il più veloce ma gli altri sono più comparabili.
Ri: Dovresti scorrere una tabella di dati o utilizzare Recode o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiCiao @txnelson ,
Confronto molto interessante, e nemmeno i risultati che mi sarei aspettato. Ricordo quando ho iniziato a studiare programmazione al college e mi è stato anche insegnato qualcosa di simile: diffida dei loop perché sono lenti.
Di sicuro, con alcuni calcoli e in alcuni programmi, ho riscontrato che i cicli For sono molto lenti, più lenti delle alternative. Non essendo un grande programmatore, però, tendo a ripiegare su ciò che so fare, che non è sempre veloce o elegante. A volte per me, la logica di un ciclo mi consente di scrivere un codice funzionante per fare ciò che voglio che faccia, il che mi consente di passare ai passaggi successivi.
Trovo interessante il fatto che le opzioni For Loop e Recode siano leggermente più lente per JMP 16 rispetto a 15, ma il Get Rows Where migliorato riducendo il tempo quasi della metà, è un cambiamento sostanziale.
Grazie!,
ds
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiForse @Craige_Hales potrebbe avere una soluzione ancora più veloce. Ho avuto l'idea di usare i calcoli Matrix (soprattutto Loc()) dai suoi post/blog della sua comunità.
Ho creato uno strumento al lavoro più veloce che apre il set di dati e quindi elimina i vecchi dati (in base alla selezione dell'utente). In origine utilizzava << Seleziona dove ed Elimina righe. L'ho sostituito con un po' di magia Loc() ed è diventato anche molto più veloce. Mi è piaciuto molto Loc() ultimamente.
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di dati@jthi ,
Il tuo codice basato su matrice è arrivato come il più veloce.
0,299795 secondi........
Ri: Dovresti scorrere una tabella di dati o utilizzare Ricodifica o utilizzare Ottieni righe dove per modificare i valori in una tabella di datiHo fatto un po' di ottimizzazione al lavoro su alcuni vecchi script che abbiamo. Alcune delle cose che ho dovuto cambiare erano relative a ottenere righe dove. Ho iniziato a utilizzare sempre più operazioni di matrice (principalmente Loc()) se ho bisogno di un codice JSL veloce.
Ad esempio, potresti modificare le righe get dove seguire (non ho verificato se sostituisce i valori corretti o tutti):
start=hptime();
for(i=5,i<= ncols(dt),i++,
column(dt,i)[Loc(ascolumn(dt,i) << get as matrix, 999)]=.;
if(mod(i,10)==0,show(i));
);
show(hptime()-start);
C'è anche la possibilità di utilizzare le proprietà della colonna Etichette valore e Codici valore mancanti che potrebbero funzionare in alcuni casi. Mi piace usarli quando possibile, perché così non cambierai i dati.