Tempi sovrappostiDì che ho due tavoli. Tabella A e Tabella B. Entrambe le tabelle A e B hanno orari di inizio e fine evento per gli eventi. Voglio generare una nuova tabella che contenga solo gli eventi della tabella B che si verificano durante lo stesso intervallo di tempo degli eventi nella tabella A. C'è un modo semplice per farlo con JSL?
Ri: volte sovrapposteFunziona molto più velocemente e fa esattamente ciò di cui ho bisogno! Inoltre ho imparato molto su JMP nel processo. Molto apprezzato!!!Ri: volte sovrapposteÈ possibile utilizzare un gestore di stato riga (vedere sotto). Nella misura in cui le corrispondenze vengono mantenute nella "Tabella B", è necessario preoccuparsi di aggiornarle quando i dati nella "Tabella B" o nella "Tabella A" cambiano. Inoltre, anche se il collegamento è bidirezionale in base al concetto, se si tenta di aggiungere un corrispondente gestore di stato riga a "Tabella A", non sorprende che essi interferiscano l'uno con l'altro.
Usando questo codice, le selezioni in "Tabella B" si propagheranno in "Tabella A":

NamesDefaultToHere(1);
dtA = NewTable("A",
NewColumn("Start", Numeric, Ordinal, Formula(RandomInteger(1, 20))),
NewColumn("End", Numeric, Ordinal, Formula(:Start + RandomInteger(1, 10)))
);
dtA << addRows(4);
dtA << runFormulas;
dtA:Start << deleteFormula;
dtA:End << deleteFormula;
dtB = NewTable("B",
NewColumn("Start", Numeric, Ordinal, Formula(RandomInteger(1, 20))),
NewColumn("End", Numeric, Ordinal, Formula(:Start + RandomInteger(1, 10)))
);
dtB << addRows(6);
dtB << runFormulas;
dtB:Start << deleteFormula;
dtB:End << deleteFormula;
// Get values into matrices
matA = dtA << getAsMatrix;
matB = dtB << getAsMatrix;
// Loop over the events in 'B' and compare each with all those in 'A' at the same time
matchesBtoA = AssociativeArray();
for(e=1, e<=NRow(matB), e++,
startB = matB[e,1];
endB = matB[e,2];
matchesInA = Loc((matA[0,1] < endB) & (startB < matA[0,2]));
matchesBtoA << InsertItem(e, matchesInA);
);
// Persist the matches in 'B', which becomes the 'master table'
dtB << New Column( "Rows in A", Expression);
for (r=1, r<=NRow(matB), r++,
Column(dtB, "Rows in A")[r] = matchesBtoA << getValue(r);
);
// This row state handler detects row selections in 'B' and selects rows in 'A'
fB =
function({sourceRows}, {Default Local},
selectedSourceRows = dtB << getSelectedRows;
rows2select = [];
for(r=1, r<=NRow(selectedSourceRows), r++,
rows2select = VConcat(rows2select, Column(dtB, "Rows in A")[selectedSourceRows[r]]);
);
dtA << clearSelect;
dtA << selectRows(rows2select)
);
// Assign row state handler to 'B'
obB = dtB << MakeRowStateHandler(fB);
Ri: volte sovrapposteGrazie! Ora ho fatto funzionare l'array associativo, ed è MOLTO più veloce di quello che stavo facendo prima (cioè 2 minuti contro 2 ore).
C'è un modo per prendere l'array associativo e usarlo per selezionare automaticamente i numeri di riga corrispondenti nella Tabella B?
Ri: volte sovrapposteTBH, mi ci sono voluti alcuni tentativi (e una penna e un foglio) per ottenere la logica giusta. Basta disegnare due segmenti di linea in tutte le varie configurazioni (incluso quando A è contenuto in B o viceversa). In realtà, è per questo che ho aggiunto i grafici per essere sicuro di aver capito bene!
L'uso delle operazioni con le matrici ti permette di vettorizzare le cose, che è generalmente più veloce). In termini di sintassi, matA [0,1] (matA [0,2]) contiene tutti i punti di inizio (fine) per i segmenti di linea indicati come "A". La funzione 'Loc ()' restituisce un vettore di colonna che fornisce i numeri di riga in matA per cui è soddisfatta la condizione logica.
Come menzionato da Dan, potresti usare <= instaed of
Ri: volte sovrapposteGrazie per l'approccio interessante. Sto cercando di avvolgere la mia testa attorno alla seguente riga:
matchesInA = Loc((matA[0,1] < endB) & (startB < matA[0,2]));
Che cosa sta facendo e come funziona? Apprezzo il vostro aiuto!
Ri: volte sovrappostePenso che le condizioni di sovrapposizione nelle soluzioni siano leggermente diverse - La condizione della matrice non conta sovrapposizione se i due intervalli toccano solo (<=), e Select Where () non conta un intervallo B che contiene interamente un A intervallo. Ad ogni modo penso che l'approccio matrix sarà più veloce, ma entrambi imperversano per tavoli molto grandi. Per fare molto meglio richiederebbero alcune strutture di ordinamento e dati come il Interval Tree . Fare questo da JSL potrebbe essere più costoso dei metodi di forza bruta ..
Ri: volte sovrapposteQuesto potrebbe essere meglio. Utilizza valori di tempo interi, ma va bene.

.
NamesDefaultToHere(1);
dtA = NewTable("A",
NewColumn("Start", Numeric, Ordinal, Formula(RandomInteger(1, 20))),
NewColumn("End", Numeric, Ordinal, Formula(:Start + RandomInteger(1, 10)))
);
dtA << addRows(4);
dtA << runFormulas;
dtA:Start << deleteFormula;
dtA:End << deleteFormula;
dtB = NewTable("B",
NewColumn("Start", Numeric, Ordinal, Formula(RandomInteger(1, 20))),
NewColumn("End", Numeric, Ordinal, Formula(:Start + RandomInteger(1, 10)))
);
dtB << addRows(6);
dtB << runFormulas;
dtB:Start << deleteFormula;
dtB:End << deleteFormula;
// Get values into matrices
matA = dtA << getAsMatrix;
matB = dtB << getAsMatrix;
// Loop over the events in 'B' and compare each with all those in 'A' at the same time
matchesBtoA = AssociativeArray();
for(e=1, e<=NRow(matB), e++,
startB = matB[e,1];
endB = matB[e,2];
matchesInA = Loc((matA[0,1] < endB) & (startB < matA[0,2]));
matchesBtoA << InsertItem(e, matchesInA);
);
// Graphs
maxX = Maximum(Maximum(matA[0,2]), Maximum(matB[0,2]));
minX = Minimum(Minimum(matA[0,1]), Minimum(matB[0,1]));
NewWindow("Overlapping Intervals", << onClose(Close(dtA, NoSave); Close(dtB, NoSave)),
LineUpBox(NCol(2),
VListBox(
GraphBox(Title("Line Intervals in Table A"),
XScale(minX, maxX), YScale(0, NRow(matA)+1), YName("Row Number"), FrameSize(500, 210),
for(ii = 1, ii<=NRow(matA), ii++,
Line({matA[ii,1], ii}, {matA[ii,2], ii});
);
),
GraphBox(Title("Line Intervals in Table B"),
XScale(minX, maxX), YScale(0, NRow(matB)+1), YName("Row Number"), FrameSize(500, 210),
for(ii = 1, ii<=NRow(matB), ii++,
Line({matB[ii,1], ii}, {matB[ii,2], ii});
);
)
),
GraphBox(Title("Row numbers in Table B (in Table A) on the left (on the right)"),
XScale(0, 1), YScale(0, Maximum(NRow(matA), NRow(matB))+1), YName("Row Number"), FrameSize(500, 500),
for(ii = 1, ii<=NRow(matB), ii++,
lines = matchesBtoA << getValue(ii);
for(jj=1, jj<=NRow(lines), jj++,
Line({0, ii}, {1, lines[jj]});
);
);
)
)
);
Ri: volte sovrapposteCordiali saluti, ecco come lo sto facendo ora.
OverlappingEvents = Function( {PrimaryTableName, PrimaryTableStartTime, PrimaryTableEndTime, SecondaryTableName, SecondaryTableStartTime, SecondaryTableEndTime}, {},
SecondaryTableName << Clear Selection;
For(i = 1, i <= nrows(PrimaryTableName), i++,
::PrimaryEndTime = Column( PrimaryTableName, PrimaryTableEndTime )[i];
::PrimaryStartTime = Column( PrimaryTableName, PrimaryTableStartTime )[i];
SecondaryTableName << select where( ::PrimaryStartTime <= as column(SecondaryTableStartTime) & as column(SecondaryTableEndTime) <= ::PrimaryEndTime | ::PrimaryStartTime <= as column(SecondaryTableEndTime) <= ::PrimaryEndTime | ::PrimaryStartTime <= as column(SecondaryTableStartTime) <= ::PrimaryEndTime, Current selection("Extend") ); //select all events in secondary table that overlap or are within events on primary table
);
);Sfortunatamente, la funzione impiega molto tempo quando si lavora con grandi datatables. Esiste un modo migliore?
Ri: volte sovrapposteSì, entrambe le tabelle hanno un orario di inizio e di fine per ciascun evento. Quindi ho bisogno di una soluzione che trovi gli eventi nella tabella B che sono all'interno o sovrapposti da eventi nella tabella A.
Ri: volte sovrapposteEdit: Probabilmente ho risolto un problema diverso da quello che descrivi. Nel tuo esempio, ogni riga ha un (inizio, fine) e vuoi intersecare le righe nella tabella B con tutte le righe nella tabella A? Nel mio esempio c'è solo un collettivo (inizio, fine) per il tavolo ..
Risposta originale:
Ecco un modo per creare la nuova tabella:
seriesP = Open("$SAMPLE_DATA/Time Series/SeriesP.jmp");
seriesP_years = seriesP:Year << Get Values;
seriesP_min = Min(seriesP_years);
seriesP_max = Max(seriesP_years);
seriesR = Open("$SAMPLE_DATA/Time Series/SeriesR.jmp");
seriesR << Select Where(:Year >= seriesP_min & :Year <= seriesP_max);
seriesRsubset = seriesR << Subset("Selected Rows");