データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますか最近のコミュニティ ディスカッションRe: テーブル全体で数値を見つけて欠損値に置き換えるスクリプトによって提供された非常に素晴らしいエントリがありました@SDF1解決策として選ばれた
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] = .
)
)
);
ソリューションを見たとき、「データ テーブルをループしてはいけません。ループが遅い。 JMP 組み込み機能を使用してください」
だから私は修正し始めました@SDF1コード。
「Get Rows Where()」のフォールバック標準の方が高速であると判断しました。結局のところ、「非常に高速な」Get Rows Where() が行を見つけた後、見つかったすべての行を 1 つの割り当てステートメントで設定できます。
私が見た別の解決策押されたコミュニティが推奨するのは、JMP の Recode 機能です。
そう:
仮説: Get Rows Where および Recode の組み込み JMP 関数は、ループ ダウンおよびデータ テーブル全体にわたるよりも高速です。
132 列、1455 行の適切なサイズの表として、半導体能力データ表を選択しました。
各列の 10 個のランダム値を 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;
)
));
これは、上記のディスカッションで変更される元の値です。999 は、スクリプトによって欠落 (.) に変更されます。
方法:
- JMP 16 を起動します。
- 半導体能力データ テーブルを読み込む
- スクリプトを実行して、各列に 999 の値を設定します
- 3 つの方法のそれぞれについて上記の 2 つの手順を繰り返し、時間をミリ秒単位で再コード化します。
- JMP15について上記の手順を繰り返します
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)
Get Rows Where のコード
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>
そして、ここにあるのは驚くべき結果

For ループが圧勝です。結果から、Get Rows Where は慎重に使用する必要があります。
コメントや訂正は大歓迎です......
データ表スクリプティングRe: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかはい、わかりました@ブレイディ_ブレイディ. ただし、これを行うこともできます。
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];
しかし、特に要素ごとの乗算のために、これが既に持っているものよりも高速になるとは思えません。
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかここで比較が少し間違っています。「Get Rows Where」機能は各行の式を評価するため、ループを実行する前に余分なルックアップを最小限に抑える必要があります。特に、イテレータは外部であり、各行でそれを見つけるには、スコープ ウォーキングを行う必要があります。また、各行で AsColumn 関数を評価し、毎回 'dt' と 'i' の両方を検索します。これは_非常に_高価です。これに対する適切な方法は次のとおりです。
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>
これは 3000 倍の速さで実行されることに気付くでしょう。
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかはい...ハードルは、単一のインデックス(行優先のレイアウトを想定)でマトリックスにアクセスできますが、データテーブルにはアクセスできないことです。 したがって、悲しいことにアナログはありません
m[loc(m, 9999)] = .
ここで、m はデータ テーブルの世界の pxq 行列です。したがって、上記のコードのこの行の前後にある行です。 コードは依然として高速ですが、テーブルに対して単一インデックス アクセスが利用可能であれば、非常に高速になります。
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかのために 'マトリックスを作成する際のオーバーヘッド'私はそれを疑うデータ テーブルの添え字付け役立つかもしれません。@Craige_Hales知っているはず。
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかループを回避する方法は次のとおりですが、マトリックスを作成して後でテーブルに代入する際のオーバーヘッドがあります。 このアプローチは、loc_2d とほぼ同じように、このデータに対して迅速に実行されますが、テーブルが巨大になると、相対的なパフォーマンスが低下すると予想されますが、これは確認していません。
expr_mat = expr(
m = dt[0, 5 :: N Col( dt )];
m[Loc( m, 999 )] = .;
dt[0, 5 :: N Col( dt )] = m;
);
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかこれについては少し深みがありすぎたかもしれません (ただし、必要に応じて後でこの種のテストを行う方法については、少なくとも何らかのアイデアが得られました)。
999 を行方不明に置き換えるさまざまな方法をテストするために、さまざまな表現を使用して何らかのテスト スクリプトを作成しました。 2 つのデータセット (Semiconductor Capability.jmp と Probe.jmp) でテストし、列の欠損値の量を変更しました。
Loc() は、値の置換で最速です (驚くことではありません)。 Missing Value Codes() は「常に」高速ですが、Loc() と比較するとユースケースが少し制限されており、置換する値が複数ある場合に使用するのが少し面倒です。

最速は loc_2d になりました(変数名を次から変更する必要はありませんでした: 2D 行列での Loc の使用)。 値を設定するためにループする必要があります (少なくとも私の知る限り)。そのため、これが単に Loc() よりも高速である理由は、おそらくいくつかの列をスキップするためです。 以下は expr_loc2d と 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]] = .;
);
);
また、 AsColumn(Column(dt, i)) のように使用することも重要なようです@ライアン_ギルモアと言いました(非常に遅くなるため、 << get rows where it をテストすることさえ気にしませんでした)が、Column() を使用した場合と使用しない場合の再コード化をテストしました。 また、recode から Column() を 1 つ見逃していることに気付きました。そのため、いくつかの簡単なテストを実行します (データまたはスクリプトに添付されていません)。
これら3つのかなり大きな違い:
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)))
)
);
);

テスト スクリプトといくつかの結果データが添付されています。 ほとんどの場合、スクリプトにはいくつかの間違いがあります。 誰かがそうしたい場合、新しい式を追加するのはかなり簡単なはずです。 私がまったくテストしなかったことの 1 つは、<< Begin/End データ更新の使用です。
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますか興味深い議論! JMP 13 で最初に登場したと思われるデータ テーブル マトリックス表記法は、代入に対して非常に効率的です。
この特定の問題については、for ループよりもほぼ 500 倍高速です (0.003 対 1.5 秒、JMP 15 Mac ラップトップ)。
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
Try( dt[Loc( dt[0, i], 999 ), i] = . )
);
Show( HP Time() - start);
「999」のない列のエラーを回避するには、try() が必要です。
列全体のループはまだ必要です。これは、マトリックス全体の直接割り当てが機能しないためです。 エラー: 「複数の添え字には、アクセスまたは評価の各内部レベルで単一の添え字が必要です...」、これはよく考えれば理にかなっています。
// 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 )] = .;
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかある時点でループを使用することに警戒していたかもしれませんが、アルゴリズムコースを1つ受講した後(私は決して終了しませんでした..)、少しそうではありませんでした. それらを効率的に使用する必要があるだけで、多くの場合、ループが多すぎます (時間の複雑さと Big O 記法)。 また、ループを使用することは、純粋な数学で問題を解決しようとするよりもはるかに簡単です。
JMPでは、速度が問題になることはめったにないので、ある時点で学んだ安全なオプションを使用するだけです。 しかし、時間が問題になると (1 つのアプリケーションが職場で開くのに 6 分以上かかりました)、それを高速化する方法を探し始めます (2 分以内に開始することができました)。 この場合、他の関数 (行の削除、行の状態の設定) のさまざまな組み合わせで Loc() を使用することで、なんとか高速化することができました。
Loc() に加えて、Summarize() を使用すると、列内の一意の値を取得するための私の長年のお気に入りのオプション (連想配列 () << キーを取得) と比較すると、「はるかに」高速なようです。 行数が増えると、Associative array() << get keys がますます遅くなり、 Summarize() は同じ問題に悩まされていないようです。少なくともそれほど速くはありません。 そのため、Summarize() をもっと使い始めようとしました (データテーブルの高さがわかりません)。
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかしたがって、AsColumn() を次のようにスキップします (直感でさらに進んでください。これがすべての正しい値を置き換えるかどうかはテストしていません)。
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);
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかLoc() が最良の方法であることに同意します。
私にとっては、As Column が原因でスローダウンが発生しているようです。 私は、
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
As Column( column(dt, i) );
);
Show( HP Time() - start );
と
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
As Column( dt, i );
);
Show( HP Time() - start );
コード内の As Column 構文の変更@txnelson元の質問、For ループは依然として最速ですが、他のループはより同等です。
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますかやあ@txnelson 、
非常に興味深い比較であり、私が期待した結果でもありません。 大学で初めてプログラミングを学び始めたとき、似たようなことを教えられたのを覚えています。ループは遅いので注意してください。
確かに、いくつかの計算といくつかのプログラムでは、For ループが非常に遅く、他の方法よりも遅いことがわかりました。 とはいえ、それほど優れたプログラマーというわけではないので、自分が知っているやり方に頼る傾向があり、それは常に迅速でエレガントであるとは限りません。 私にとっては、ループのロジックにより、実行したいことを実行する機能するコードを記述できるようになり、次のステップに進むことができる場合があります。
For Loop と Recode オプションが JMP 16 と 15 で少し遅いのは興味深いと思いますが、Get Rows Where は時間をほぼ半分に短縮することで改善されました。これは大幅な変更です。
ありがとう!、
DS
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますか多分@Craige_Halesさらに迅速な解決策が得られる可能性があります。 彼のコミュニティの投稿/ブログから、マトリックス計算 (特に Loc()) を使用するというアイデアを得ました。
データセットを開いて古いデータを削除する (ユーザーの選択に基づく) 作業を高速化するツールを 1 つ作成しました。 元々は << Select Where と Delete rows を使用していました。 これをいくつかの Loc() マジックに置き換えたところ、速度も大幅に向上しました。 最近、Loc() がとても気に入っています。
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますか@jthi 、
あなたのマトリックスベースのコードが最速でした。
0.299795 秒........
Re: データ テーブルをループするか、Recode を使用するか、Get Rows Where を使用してデータ テーブルの値を変更する必要がありますか私は、私たちが持っているいくつかの古いスクリプトに対して、職場でいくつかの最適化を行ってきました。 私が変更しなければならなかったもののいくつかは、行の取得に関連していました。 高速なJSLコードが必要な場合は、ますます多くの行列演算(主にLoc())を使用するようになりました。
たとえば、get rows where を次のように変更できます (正しい値またはすべての値を置き換えるかどうかはテストしていません)。
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);
場合によっては、列プロパティの値ラベルと欠落値コードを使用するオプションもあります。 データを変更しないので、可能な限りそれらを使用するのが好きです。