重複時間テーブルが2つあるとします。表Aと表B表Aと表Bの両方に、イベントの開始時刻と終了時刻があります。テーブルAのイベントと同じ時間枠内に発生したテーブルBのイベントのみを含む新しいテーブルを生成したいのですが、これをJSLで行う簡単な方法はありますか?
日時の重複これはとても速く走ります、そして、私がそれを必要とするまさにその通りにします!また、私はその過程でJMPについて多くのことを学びました。とても有難い!!!日時の重複行状態ハンドラを使用することができます(下記参照)。一致が 'Table B'に保持されている限り、'Table B'または 'Table A'のいずれかのデータが変更されたときにこれらを更新することを考慮する必要があります。また、リンクが概念的に双方向であるとしても、対応する行状態ハンドラを 'Table A'に追加しようとすると、驚くことではないが、それらは互いに干渉します。
このコードを使用して、'Table B'の選択は 'Table 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);
日時の重複ありがとうございました!私は今連想配列を動作させました、そしてそれは私が前にしていたものよりはるかに速いです(すなわち2分vs 2時間)。
連想配列を取り、それを使用して表Bの対応する行番号を自動的に選択する方法はありますか?
日時の重複TBH、論理を正しくするためにいくつかの試み(およびペンと紙)が必要でした。(AがBに完全に含まれる場合、またはその逆の場合も含めて)すべてのさまざまな構成で2本の線分を描くだけです。実のところ、それが正しいことを確認するためにグラフを追加した理由です。
行列演算を使用すると、物事をベクトル化することができます(これは一般的に高速です)。構文に関しては、matA [0,1](matA [0,2])は 'A'で示される線分のすべての始点(終点)を含みます。'Loc()'関数は、論理条件が満たされるmatAの行番号を示す列ベクトルを返します。
Danが述べたように、結果をどうしたいかに応じて<= instaed of <を使うことができます。
日時の重複興味深いアプローチをありがとう。私は頭を次のように折り返します。
matchesInA = Loc((matA[0,1] < endB) & (startB < matA[0,2]));
それは何をしていますか、そしてそれはどのように動作しますか?私はあなたの助けに感謝します!
日時の重複2つの区間が接しているだけで(<=)、行列の条件が重なりを数えない、そしてSelect Where()が完全にAを含むB区間を数えないならば、マトリックス条件は重なりを数えない間隔。いずれにせよ、私はマトリックスアプローチがより速くなると思いますが、両方とも非常に大きなテーブルのために駄目になります。 もっとうまくやるには、次のようなソートとデータ構造が必要です。区間ツリー 。 JSLからそれを行うのは、ブルートフォース方式よりもコストがかかる可能性があります。
日時の重複これはもっといいかもしれません。整数の時間値を使用しますが、それで問題ありません。

.
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]});
);
);
)
)
);
日時の重複ちなみに、ここで私は今それをやっているのです。
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
);
);残念ながら、大きなデータテーブルを扱う場合、この関数は非常に時間がかかります。もっと良い方法はありますか?
日時の重複はい、両方のテーブルには各イベントの開始時間と終了時間があります。そのため、テーブルAのイベントの内側にあるイベント、またはテーブルAのイベントと重複しているテーブルBのイベントを検出するソリューションが必要です。
日時の重複編集:私はおそらくあなたが説明したものとは異なる問題を解決した。 あなたの例では、各行は(開始、終了)を持ち、あなたはテーブルAのすべての行とテーブルBの行を交差させたいですか?この例では、テーブルには1つの集合(開始、終了)しかありません。
元の回答:
これは新しいテーブルを作成する1つの方法です。
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");