Ottimizzazione di un codice JSL (lento) basato su cicli FOR()Ciao,
Devo scrivere un codice per l'analisi dei dati sull'affidabilità.
Diverse metriche (metric1, metric2,...metricN) vengono misurate prima dell'inizio dell'esperimento (REL_T0), quindi misurate nuovamente dopo ogni evento di rilascio (DROP1, DROP2,... DROPN...).
Il mio obiettivo è calcolare il valore di deriva tra REL_T0 e ciascuna misura dopo gli eventi di caduta per ciascun numero di serie e ciascuna metrica.
Il mio codice iniziale è basato su cicli FOR() — che so che non sono assolutamente ottimali — e funziona bene con piccoli set di dati.
Tuttavia, devo ottimizzare il mio codice per farlo funzionare più velocemente con set di dati più grandi.
Attualmente, con 10.000 righe e 50 metriche, sono necessari circa 20 minuti per completare il processo, il che è decisamente troppo.
Ho provato a organizzare i cicli FOR() in modo diverso ma senza un impatto significativo.
Sono sicuro che ci sono modi per eseguire questi semplici calcoli in modo molto più veloce, utilizzando i comandi proprietari JSL.
Che cosa ne pensate?
Il codice seguente crea una tabella fittizia e quindi esegue il mio codice iniziale per ottenere nuove colonne "∆_metricN" con la deriva calcolata.
Vorrei fare la stessa cosa usando i comandi JSL invece dei loop FOR() che renderebbero il mio codice velocissimo!
Grazie mille in anticipo.
Predicatore.
//Create dummy table
RawData = New Table( "RawData",
Add Rows( 20 ),
New Column( "serial_number", Character, set values( {"A","A","A","A","A","A","A","B","B","B","B","B","B","C","C","C","C","C","C","C"})),
New Column( "rel_event", Character, set values( {
"REL_T0","DROP1","DROP2","DROP3","DROP4","DROP5","DROP6",
"REL_T0","DROP1","DROP2","DROP3","DROP4","DROP5",
"REL_T0","DROP1","DROP2","DROP3","DROP4","DROP5", "DROP6"})),
New Column("metric1", Continuous, set values({1,2,3,5,7,10,13,2,4,5,6,8,11,1,2,4,5,5,9,12}) ),
New Column("metric2", Continuous, set values({2,3,4,7,9,14,18,2,3,4,7,9,14,2,5,7,8,9,11,13}) );
);
RawData << save( "$Desktop\RawData.jmp" );
Column(RawData, "rel_event") << Set Property( "Value ordering", {"REL_T0","DROP1","DROP2","DROP3","DROP4","DROP5","DROP6"} );
//Create handle for data table to be analyzed
RawData = Current Data Table();
ChosenDataCol = {"metric1", "metric2"};
NumDataCol = N Items( ChosenDataCol );
NumRow = N Row( RawData );
RawDataCol = RawData << get column names;
Show( NumDataCol );
Show( ChosenDataCol );
Show( RawData );
Show( NumRow );
Show( RawDataCol );
//Scan each selected data row for which Deltas must be computed
For( cpt = 1, cpt <= NumDataCol, cpt++,
//Create column to receive delta data
DeltaCol = RawData << New Column( "∆_" || Char( ChosenDataCol[cpt] ), Numeric, "Continuous" );
TargetCol = Column( RawData, ChosenDataCol[cpt] );
serial_numberlist = {}; //List of unique serial_number's within the data table of interest
Show( cpt );
Show( ChosenDataCol[cpt] );
For( i = 1, i <= NumRow, i++,
Currentserial_number = :serial_number[i];
If( Contains( serial_numberlist, Currentserial_number ) == 0,
Insert Into( serial_numberlist, Currentserial_number )
);
);//For i
Show( serial_numberList );
Numserial_number = N Items( serial_numberlist );
Show( Numserial_number );
//Scan data table for each unique serial_number
For( i = 1, i <= Numserial_number, i++,
Currentserial_number = serial_numberList[i];
Currentserial_numberrows = RawData << GetRowsWhere( :serial_number == Currentserial_number ); //matrix of rows containing current serial_number
Show( Currentserial_numberrows );
NumCurrentserial_numberrows = N Row( Currentserial_numberrows );
Show( NumCurrentserial_numberrows );
show(i);
TzeroExist = 0;
TzeroVal = 0;
//identify Time Zero value for each serial_number under consideration
For( j = 1, j <= NumCurrentserial_numberrows, j++,
CurrentRead = :rel_event[Currentserial_numberrows[j]];
Show( CurrentRead );
If( CurrentRead == "REL_T0",
TzeroVal = TargetCol[Currentserial_numberrows[j]];
Show( TzeroVal );
TzeroExist = 1;
);
); //For j
//Calculate Drift
For( j = 1, j <= NumCurrentserial_numberrows, j++,
If( TzeroExist == 1,
DeltaCol[Currentserial_numberrows[j]] = TargetCol[Currentserial_numberrows[j]] - TzeroVal
)
); //For j
);//For i
);//For cpt Modellazione statistica avanzataAutomazione e scriptingRi: Ottimizzazione di un codice JSL (lento) basato su cicli FOR()Grazie Jarmo per la tua risposta.
Mi piace l'idea di utilizzare For Each Row(), semplifica l'intero script.
Ma per aggiungere più contesto e rendere lo script più robusto, REL_T0 potrebbe non essere sempre la prima riga per numero di serie (il database non sempre interroga i dati nell'ordine corretto nella tabella JMP), e anche la deriva potrebbe essere positiva OR negativo, quindi non so se Col Min() è adatto qui (forse non l'ho letto bene).
È possibile ancorare start_row al valore REL_T0 per numero di serie direttamente?
Ri: Ottimizzazione di un codice JSL (lento) basato su cicli FOR()Sì, è possibile con piccole modifiche direttamente allo script. Ho aggiunto la colonna di debug che puoi rimuovere per mostrare che corrisponde alle righe corrette
Names Default To Here(1);
dt = New Table("RawData",
Add Rows(27),
Compress File When Saved(1),
New Column("serial_number",
Character,
"Nominal",
Set Values(
{"A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "C", "C", "C", "D", "D", "D", "D", "D", "D", "D"}
)
),
New Column("rel_event",
Character,
"Nominal",
Set Values(
{"REL_T0", "DROP1", "DROP2", "DROP3", "DROP4", "DROP5", "DROP6", "REL_T0", "DROP1", "DROP2", "DROP3", "DROP4", "DROP5", "REL_T0", "DROP1",
"DROP2", "DROP3", "DROP4", "DROP5", "DROP6", "DROP1", "DROP2", "DROP3", "REL_T0", "DROP4", "DROP5", "DROP6"}
)
),
New Column("metric1",
Numeric,
"Continuous",
Format("Best", 10),
Set Values([1, 2, 3, 5, 7, 10, 13, 2, 4, 5, 6, 8, 11, 1, 2, 4, 5, 5, 9, 12, 1, 2, 4, 5, 5, 9, 12])
),
New Column("metric2",
Numeric,
"Continuous",
Format("Best", 10),
Set Values([2, 3, 4, 7, 9, 14, 18, 2, 3, 4, 7, 9, 14, 2, 5, 7, 8, 9, 11, 13, 2, 5, 7, 8, 9, 11, 13])
)
);
debugcol = dt << New Column("REL_T0_ROW", Numeric, Continuous);
delta1col = dt << New Column("delta1", Numeric, Continuous);
delta2col = dt << New Column("delta2", Numeric, Continuous);
For Each Row(dt,
// find REL_T0 row for current serial_number
start_row = Col Min(If(:rel_event == "REL_T0", Row(), .), :serial_number);
debugcol[Row()] = start_row;
delta1col[Row()] = :metric1 - :metric1[start_row];
delta2col[Row()] = :metric2 - :metric2[start_row];
);

Ri: Ottimizzazione di un codice JSL (lento) basato su cicli FOR()Grazie mille Jarmo!
Ho provato questa nuova versione in una tabella dati con 18000 righe e 2 metriche:
- Vecchio metodo: ~5min
- il tuo metodo: <2min
E' già un miglioramento strepitoso!!!
Grazie ancora!!
Predicatore
Ri: Ottimizzazione di un codice JSL (lento) basato su cicli FOR()Ciao Hogi,
Grazie per il tuo suggerimento, ho controllato il tuo post relativo al componente aggiuntivo Normalizzazione. Lo terrò sicuramente presente per i progetti futuri.
Predicatore
Ri: Ottimizzazione di un codice JSL (lento) basato su cicli FOR()Ulteriori miglioramenti della velocità possono essere ottenuti molto probabilmente abbastanza facilmente utilizzando matrici per eseguire tali calcoli. Anche aggiungendo
dt << begin data update;
prima del ciclo e
dt << end data update;
molto probabilmente fornirà anche alcuni miglioramenti della velocità, soprattutto se la tabella non viene aperta come invisibile/privata in quanto "ritarderà", quindi gli elementi visivi nella tabella verranno aggiornati.
Ri: Ottimizzazione di un codice JSL (lento) basato su cicli FOR()La normalizzazione dei dati di misurazione è un compito comune in Data Analysis.
La GUI di normalizzazione fornisce molte opzioni per farlo.
Nella GUI l'utente può specificare molte impostazioni diverse e l'AddIn genera il codice corrispondente.
Le formule generate sono basate su aggregazioni Col... , come Col Min, Col Max, Col Median ...
altre opzioni:

Per questo caso applicativo, potresti utilizzare "first" (basato sulla logica ColMin(row()) )
... oppure specificare il riferimento tramite "utilizza un sottoinsieme per la normalizzazione" [per i casi in cui i valori di riferimento non sono i "primi"]:

Re: Ottimizzazione di un codice JSL (lento) basato su cicli FOR()Una cosa che (generalmente) velocizzerà il processo è rimuovere tutte le stampe dai loop, ma in questo caso è più veloce riscriverlo senza quei loop e non usare il loop for quando si passa attraverso una tabella dati (l'opzione migliore è for each row).
Ecco un'opzione che si spera produca risultati più rapidi (può anche essere trasformata in una formula e dovrebbe comunque essere abbastanza veloce se necessario). Presuppone che i dati siano ordinati in modo tale che REL_T0 sia sempre la prima riga per ogni numero di serie, se non è così, richiederà una piccola modifica
Names Default To Here(1);
//Create dummy table
RawData = New Table("RawData",
Add Rows(20),
New Column("serial_number",
Character,
set values({"A", "A", "A", "A", "A", "A", "A", "B", "B", "B", "B", "B", "B", "C", "C", "C", "C", "C", "C", "C"})
),
New Column("rel_event",
Character,
set values(
{"REL_T0", "DROP1", "DROP2", "DROP3", "DROP4", "DROP5", "DROP6", "REL_T0", "DROP1", "DROP2", "DROP3", "DROP4", "DROP5", "REL_T0", "DROP1",
"DROP2", "DROP3", "DROP4", "DROP5", "DROP6"}
)
),
New Column("metric1", Continuous, set values({1, 2, 3, 5, 7, 10, 13, 2, 4, 5, 6, 8, 11, 1, 2, 4, 5, 5, 9, 12})),
New Column("metric2", Continuous, set values({2, 3, 4, 7, 9, 14, 18, 2, 3, 4, 7, 9, 14, 2, 5, 7, 8, 9, 11, 13}))
);
delta1col = RawData << New Column("delta1", Numeric, Continuous);
delta2col = RawData << New Column("delta2", Numeric, Continuous);
For Each Row(RawData,
// find REL_T0 row for current serial_number
start_row = Col Min(Row(), :serial_number);
delta1col[Row()] = :metric1 - :metric1[start_row];
delta2col[Row()] = :metric2 - :metric2[start_row];
);
