「どこで行を取得する」に時間がかかりすぎる各列がメイン データ テーブルの列の名前であり、行の値がメイン テーブルのその列に不正なデータを持つ部品番号である参照テーブルがあります。たとえば、メイン テーブルの列 1 は部品番号、列 2 は「Temp」です。行番号が部品番号と等しいため、行 1 が部品「1」であり、「Temp」列の値が 65 であるとします。パート 2 の温度は -100 であるため、悪いデータです。したがって、「Temp」という名前の列の下の参照テーブルの行 1 の値は「2」になります。これは、メイン テーブルに不正なデータがあるすべての部品番号に対して繰り返され、各列に対しても同様に繰り返されます。
これにより、不正なデータ参照テーブルが作成され、メイン テーブルの最新データを取り込むたびに、ループスルーして不正なデータを自動的に削除できます。次の行でも機能するコードがあります:
(ここで、vlist には参照テーブルのすべての部品番号が含まれ、dt2 はメイン データ テーブルです)
try(rowindex=dt2 << Get Rows Where(contains(vlist,:WORKORDERNO )));
超遅いです。完了するまでに 22 秒かかります。196 列を処理する必要があるため、これには非常に時間がかかります。これを高速化する方法についての提案をいただければ幸いです。
完全なコードはここにあります:
names default to here(1);
dt=open("J:\Public\Ti Process Control\Dashboard Files\JMP data for CC's\Limits\master_data_table_clean_up.jmp", invisible(1)); //this is the reference table
dt<<BEGIN data="https://community.jmp.com/" update=""></BEGIN>自動化とスクリプト作成ウィンドウズRe: 「どこで行を取得する」に時間がかかりすぎるJMP が名前解決をどのように行うかを検討してください。を実行すると、行を取得する場所()関数を使用すると、テーブルを行ごとに調べて、どこ表現。各評価では、定義されているすべての変数の名前解決が必要です。 vリストvairable が実行ループの外側で定義されている場合、反復ごとにスコープウォーキングを行う必要があり、多くの無駄な作業が発生します。
これを回避するには、次のように、検索全体で一定になる名前を事前評価することを検討してください。
Names Default To Here( 1 );
dt = Open(
"J:\Public\Ti Process Control\Dashboard Files\JMP data for CC's\Limits\master_data_table_clean_up.jmp",
invisible( 1 )
); //this is the reference table
dt << begin data update;
cols = dt << get column names();
dt2 = Data Table( "Master data pull daily download" ); //this is the main table
dt2 << begin data update;
dt2 << Clear Select();
cols2 = dt2 << get column names();
vlist = {};
For( i = 1, i <= 2 /*N items(cols)*/, i++,
Try( vlist = Column( dt, cols[i] ) << get values );
starttime = Tick Seconds();
Eval( Eval Expr(
Try( rowindex = dt2 << Get Rows Where( Contains( Expr( vlist ), :WORKORDERNO ) ) );
) );
endtime = Tick Seconds();
Print( "run time", Eval Insert( "Analysis took ^round(endtime - starttime)^ seconds" ) );
Try( Column( dt2, cols[i] )[rowindex] = . );
);
dt2 << end data update;
dt << end data update;
Close( dt, nosave );注目してくださいEval( Eval Expr( ... Expr( vlist ) ... ) )式 -- それは事前評価ですvリストこれはループ全体で定数になるためです。
Re: 「どこで行を取得する」に時間がかかりすぎるAsConstant(vList) を使用して同じ効果を達成できると思います。「vlist」という名前は、GetRowsWhere 呼び出しごとに 1 回だけ評価される必要があります。
Re: 「どこで行を取得する」に時間がかかりすぎる返信いただきありがとうございます@Erratic Attack , コードの変更をポップしたところ、コードは 21 秒対 22 秒で実行されました。それで、少しは良くなりましたが、私が必要としているところにはいません。他のアイデアも大歓迎です。
Re: 「どこで行を取得する」に時間がかかりすぎるまた、Loc を使用する方法があれば、このようなほとんどの状況で Loc を使用した方が速いこともわかります。 これよりも良い方法があるかもしれませんが、GetRowsWhere 呼び出しを置き換える次のような方法を試すことができます。
dt = New Table( "BadTable",
Add Rows( 100 ),
New Column( "BadPartNumbers",
Formula( Random Integer( 1000 ) ),
),
);
dt2 = New Table( "FullTable",
Add Rows( 10000 ),
New Column( "NewPartNumbers",
Formula( Random Integer( 1000 ) ),
),
);
newPNumbers = dt2:NewPartNumbers<< GetValues;
badPNumbers = AssociativeArray(dt:BadPartNumbers << GetValues);
rowIndex = Loc(Matrix(badPNumbers << GetValues(AsList(newPNumbers))));
テーブルがどのように設定されているかは正確にはわかりませんが、基本的には不良部品番号を連想配列に変換し、不良部品番号は 1 を返し、それ以外は 0 を返します。 すべての部品番号のリストを GetValues に渡すと、各行の 1 と 0 のリストが返されます。 これに対して Loc を呼び出すと、1 が見つかったインデックスが返されます。これは、不正な部品番号を持つ行に対応する必要があります。
Re: 「どこで行を取得する」に時間がかかりすぎる@Erratic Attackそこで、テスト用のマスター データ テーブルと参照テーブルを作成して、みんなで一緒に遊べるように共有できるようにしました。そうすると、スクリプトは 1 秒未満と非常に高速に実行されます。そこで、実際のデータテーブルと関係があるのではないかと考えています。
こちらがテストテーブルです

Re: 「どこで行を取得する」に時間がかかりすぎるデータに応じて、これらのチェックを実行するために使用できるさまざまな方法があります (結合/更新、loc、行の取得 where、連想配列、集計テーブルなど)。 テーブルには何行ありますか? 参照テーブルの列には最大何個の異なる値が含まれますか? ほとんどの値は空ですか (比較を実行する前に空の値を削除してリストを小さくするか、リストに 1 回だけ含めます)。
Re: 「どこで行を取得する」に時間がかかりすぎるおい@jthi 、
メインテーブルの概要は次のとおりです。

そしてこれが参照テーブルです:

ref テーブルの各列に含まれるデータの量は次のとおりです:(欠損データ スクリーナーの出力から)
番号がありません
0
0
0
0
3115
6075
12237
16591
16591
16591
16591
16772
17038
17093
17095
17095
17099
17099
17109
17110
17113
21542
22781
23634
24792
24792
25058
25172
25280
25341
25356
25376
25376
25827
25863
25875
25893
25894
25897
25905
25942
25957
25963
25963
25963
25965
25968
25968
25968
25968
26367
26564
27190
27404
27414
27420
27437
27453
27465
27474
27478
27493
27503
27522
27547
27553
27573
27592
27597
27597
27597
27597
27619
27626
27628
27628
27629
27629
27629
27629
したがって、大量の不良データが含まれる少数の列が原因で、ほとんどの列が「欠落データ」/空白でいっぱいになります。
vlist にこれらすべての空白があることが速度低下の原因になっているのではないかと疑問に思います。

Re: 「どこで行を取得する」に時間がかかりすぎるすべての空白があるとコードが遅くなるのではないかと思います。ここではその回避策を紹介します。vlist の作成を次のように置き換えるだけです。
Try( vlist = Associative Array( As Column( cols[i] ) ) << get keys );
If( vlist[1] == "",
Remove From( vlist, 1, 1 )
);
Re: 「どこで行を取得する」に時間がかかりすぎる特にリストに値が見つからない場合、速度低下の原因となる可能性が高くなります。
Names Default To Here(1);
test = {"a", "b", "c", "d", "e", "f"};
test2 = test || Repeat({""}, 27629);
lookup_val = "a";
repeats = 200;
tests = {};
For(i = 1, i <= repeats, i++,
start = HP Time();
Contains(test, lookup_val);
wait(0);
end = HP Time();
Insert Into(tests, (end-start)/1e6);
);
tests2 = {};
For(i = 1, i <= repeats, i++,
start = HP Time();
Contains(test2, lookup_val);
wait(0);
end = HP Time();
Insert Into(tests2, (end-start)/1e6);
);
Show(Mean(tests), Std Dev(tests), Mean(tests2), Std Dev(tests2));
Show(Median(tests2)/Median(tests));
編集:
これらのテスト スクリプトは両方ともかなり短時間で作成されるため、いくつかの間違いがある可能性があります。
Names Default To Here(1);
Random Reset(1);
dt_data = New Table("Data",
Add Rows(30000),
New Column("first", Numeric, Nominal, << Set Each Value(Row())),
New Column("second", Numeric, Nominal, << Set Each Value(Row())),
invisible
);
Column(dt_data, "first") << Set Data Type("Character");
Column(dt_data, "second") << Set Data Type("Character");
dt_lookup = New Table("Lookup",
Add Rows(5000),
New Column("first", Numeric, Nominal, Values(Random Shuffle(1::1000)[1::10])),
New Column("second", Numeric, Nominal, Values(Random Shuffle(1::1000)[1::500])),
invisible
);
Column(dt_lookup, "first") << Set Data Type("Character");
Column(dt_lookup, "second") << Set Data Type("Character");
start = HP Time();
dt_data << Get Rows Where(Contains(As Constant(dt_lookup[0, "first"]), :first));
dt_data << Get Rows Where(Contains(As Constant(dt_lookup[0, "second"]), :second));
end = HP Time();
show((end - start)/1e6);
wait(0);
start = HP Time();
dt_data << Get Rows Where(Contains(As Constant(Associative Array(dt_lookup[0, "first"]) << get keys), :first));
dt_data << Get Rows Where(Contains(As Constant(Associative Array(dt_lookup[0, "second"]) << get keys), :second));
end = HP Time();
show((end - start) / 1e6);
Close(dt_data, no save);
Close(dt_lookup, no save);
持っている値の数と、それらが文字であるかどうか(あなたの場合はそうだと思います)に応じて、Associative Array() の代わりに Summarize() を使用して一意の値を取得する方が高速になりますが、これはおそらくそれほど大きな値ではありませんこの場合の効果
Names Default To Here(1);
dt_lookup = New Table("Lookup",
Add Rows(5000),
New Column("test", Numeric, Nominal, Values(Random Shuffle(1::1000)[1::500])),
invisible
);
Column(dt_lookup, "test") << Set Data Type("Character");
start = HP Time();
Summarize(dt_lookup, uniq_vals = by(Column(dt_lookup, "test")));
end = HP Time();
show((end - start) / 1e6);
start = HP Time();
uniq_vals2 = Associative Array(Column(dt_lookup, "test")) << get keys;
end = HP Time();
show((end - start) / 1e6);
Show(N Items(uniq_vals), N Items(uniq_vals2));
Close(dt_lookup, no save);Re: 「どこで行を取得する」に時間がかかりすぎるこれはおそらく時期尚早な最適化のカテゴリに当てはまりますが、JMP の更新は非常に高速である場合があり、列の名前を変更し、空の値でいっぱいのルックアップ テーブルに新しい列を追加することでここで使用できる可能性が最も高くなります。
Names Default To Here(1);
dt_data = New Table("Data",
Add Rows(30000),
New Column("first", Numeric, Nominal, << Set Each Value(Row())),
New Column("second", Numeric, Nominal, << Set Each Value(Row())),
invisible
);
Column(dt_data, "first") << Set Data Type("Character");
Column(dt_data, "second") << Set Data Type("Character");
dt_lookup = New Table("Lookup",
Add Rows(5000),
New Column("first", Numeric, Nominal, Values(Random Shuffle(1::30000)[1::500])),
invisible
);
Column(dt_lookup, "first") << Set Data Type("Character");
/*
start = HP Time();
Summarize(dt_lookup, uniq_vals = by(:first));
r = dt_data << Get Rows Where(Contains(As Constant(uniq_vals), :first));
dt_data[r, "second"] = "";
end = HP Time();
Show((end-start)/1e6);
*/
missing_col = dt_lookup << New Column("missing_vals", Numeric, Nominal);
start = HP Time();
i = 1;
Column(dt_lookup, "first") << Set Name(Char(i));
missing_col << Set Name("second");
dt_data << Update(With(dt_lookup), Match Columns(:first = Eval(Char(i))), Replace Columns in Main Table(:second));
end = HP Time();
Show((end-start)/1e6);
Close(dt_data, no save);
Close(dt_lookup, no save);Re: 「どこで行を取得する」に時間がかかりすぎるこれはうまくいきました、ありがとう!
おかげで@jthi同じように!txnelson コードのコピー&ペーストは完璧に機能したため、彼が上に投稿したコードについては詳しく説明しませんでしたが、時間を割いて作成してくれた彼に感謝します。