データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?最近のコミュニティのディスカッションテーブル全体で数値を検索し、欠落している値と置換するスクリプトから提供された非常に素晴らしいエントリがありました@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 行という適切なサイズのテーブルとして、Semiconductor Capability データ テーブルを選択しました。
各列の 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;
)
));
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)
これは、上記のディスカッションで変更される元の値です。999 はスクリプトによって欠落 (.) に変更されます。
方法:
- JMP16を起動します。
- 半導体能力データテーブルを読み取る
- スクリプトを実行して各列に 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 を使用する必要がありますか?
@jthi書きました:
これについては少し深すぎたかもしれません(ただし、後で必要になった場合にこの種のテストを行う方法については、少なくともある程度のアイデアは得られました)。
欠落している 999 を置き換えるさまざまな方法をテストするために、さまざまな式を含むある種のテスト スクリプトを作成しました。
....
ちょうど使ったばかりです@jthiのスクリプト:
https://community.jmp.com/t5/Discussions/Should-you-Loop-through-a-data-table-or-use-Recode-or-use-Get/mp/381766/highlight/true#M63232
Jmp (16.2 & ) 17.1 を備えたシステムでさまざまなアプローチのパフォーマンスを再現します。
いくつかのアプローチを強調しました(ロック)今日では屋内にある必要がありますデータ更新の開始/終了 *)
999 秒の割合を増やすことで大幅な時間の増加を解消します。
係数 2 による違いは、コンピューターの違いによって引き起こされる可能性があります。
直接比較するために、Jmp 15 と 17 を備えたシステムを持っている人は誰ですか?
*) サブセットは「非表示」で開かれていましたが。

Re: データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?@ほぎ書きました:
...
ユーザーが問題を認識している場合は、とても安い解決策は、 Eval()
安いJSL コードの複雑さと時間ペナルティについて。
ただし、長いテーブルの場合評価(i)また大きく負けるSubstitute(... ,NameExpr(As Column()))) 。
つまり、(元のバージョンと比較して:) それでもかなり高速ですが、期待していたほど高速ではありません。
なぜ? 根本的な違いは何でしょうか?
Re: データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?うーん、おそらく JSL をユーザーフレンドリーなモード (パフォーマンス向上につながる場合は変数を事前評価する) に切り替えることは可能でしょうか?
願い:行を取得します。ここで: 速度の問題
ユーザーが問題に気づいている場合は、非常に安い解決策は、 Eval():
start = HP Time();<BR />for(i=5,i<= ncols(dt),i++,<BR />dt << get rows where( As Column( dt, Eval(i) ) == 999 );<BR />);<BR />Show( (HP Time() - start) / 1000000 );start = HP Time();
i = 5;
dt << get rows where( As Column( dt, Eval(i) ) == 999 );
Show( (HP Time() - start) / 1000000 );
Re: データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?こんにちは@ron_horne 、問題は行を取得します。したがって、速度はそのような設定から独立している必要があります/独立しています。
一方、列インデックスが明示的であるか、それが変数であるか (変数に値が割り当てられている場合でも) は、大きな違いになります。
これは私にはよくわかりませんでしたが、この会話を見つけられて本当に良かったです。
約 N (データ テーブルの行) 倍高速化できる JSL コードがどれだけあるのかわかりません...
この問題は、JSL のバックグラウンドで何が起こっているかによって解決できますか?
それとも、JSL アーキテクチャには、そのような動作が意図されており、変更できないことを指定する根本的な何かがあるのでしょうか?
その場合: 警告メッセージは、プログラマーがこの問題に巻き込まれないようにするのに役立ちます...
Names Default To Here( 1 );
dt = Open( "$SAMPLE_DATA/Semiconductor Capability.jmp" );
For( k = 1, k <= 4, k++,
dt << Concatenate( dt, dt, dt, Append to first table )
);
nuke = Function( {},
For( k = 1, k <= 10, k++,
Column( dt, 5 )[Random Integer( 1, 1455 )] = 999
)
);
//dt << show window(0);
//dt<< Begin Data Update();
nuke();
start = HP Time();
i = 5;
dt << get rows where( As Column( dt, i ) == 999 );
Show( (HP Time() - start) / 1000000 );
nuke();
start = HP Time();
dt << get rows where( As Column( dt, 5 ) == 999 );
Show( (HP Time() - start) / 1000000 );
//dt << End Data Update();
Re: データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?ありがとう@txnelson
さまざまな方法で非表示テーブルとプライベート テーブルを使用した場合の影響を見積もっていただけますか?これは、パフォーマンスを向上させるためにスクリプトを修正する最速の方法でなければなりません。
Re: データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?うわー、なんと素晴らしいトリックでしょう:)
問題が起こるのではないかと心配していました欠損値コード試してみるとすぐに開始されます:
Col Maximum(:NPN3)
[我々が知っているように、除外される行は次のようにする必要があります除外されるCol の集計を手動で行う (またはより良い方法: GroupBy口論)。]
しかし、驚きは:コル集計の尊重欠損値コード
厳選して言うと、 OPの質問元の投稿の内容は非常に暗黙的でした。
そしてその結果から、どこで行を取得するか慎重に使用する必要があります。
コメントや修正は大歓迎です....
腹の中で不安を感じながら、次のように翻訳しました。 "なぜ地球上で?!?"
おかげで@Erratic Attackパズルを解くために:)
Re: データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?とても楽しくて有益なディスカッションでした! 素晴らしい答えです。 私には本当にここで価値のあるものを追加する資格がないので、「不正行為」に頼るつもりです。
OPの質問は、999は欠損値コードであり、計算に含めたくないため、データ内の999の値を欠損値に置き換えることに関するものでした。 この非常に興味深い一連の質問の趣旨とはまったく異なりますが、欠損値コード列プロパティを利用する方がデータの置換を行うよりも速く、*ほとんど*の目的で同じことを達成できるという点で私の貢献はあります 
start = HP Time();
For( i = 5, i <= N Cols( dt ), i++,
Column(dt,i) << Set Property( "Missing Value Codes", {999} )
);
Show( HP Time() - start);
私のm1 Macでは~0.007秒。
Re: データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?ああ、知りませんでした:
:名前()のように動作します列として() ?
スクリプトインデックスからはそれほど明確ではありません:)
それで、代わりのそして列()としての代わりにEval(Parse(Eval Insert(JSL Quote(name("^names[i]^")それは:
start=hptime();
for(i=5,i<= ncols(dt),i++,
Eval(Substitute(Expr(column(dt,i)[dt<<GET rows="" where=""></GET>
以降この驚くべき発見ここで私はほとんど驚いたのですが、行を取得します。数値比較を文字比較に置き換えても高速です:)
start=hptime();
for(i=5,i<= ncols(dt),i++,
Eval(Substitute(Expr(column(dt,i)[dt<<GET rows="" where=""></GET>
Re: データ テーブルの値を変更するには、データ テーブルをループするか、Recode を使用するか、または Get Rows Where を使用する必要がありますか?はい、わかりました@brady_brady 。 ただし、次のようにすることもできます。
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)) を使用することが重要のようです@Ryan_Gilmoreと言いました(それがないと非常に遅くなるため、<< get rows where をテストすることさえしませんでした)、しかし私はColumn()を使用した場合と使用しない場合の再コードをテストしました。 また、再コードで 1 つの Column() を見逃していることに気づきました。そのため、いくつかの簡単なテストを実行します (データまたはスクリプトには添付されていません)。
これら 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 つは、<< データ更新の開始/終了を使用することです。
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);
try() は、「999」のない列のエラーを回避するために必要です。
行列全体への直接代入 (一瞬、もっと高速になるだろうと思ったのですが) が機能しないため、列のループ処理が依然として必要です。 エラー: 「複数の添字には、アクセスまたは評価の各内部レベルで 1 つの添字が必要です...」。よく考えれば、これは理にかなっています。
// 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 key) と比較すると、「はるかに」速いようです。 行数が増加すると、Associative array() << getkeys はますます遅くなり、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 ループが非常に遅い、つまり他のループよりも遅いことがわかりました。 しかし、私はそれほど優れたプログラマではないので、自分が知っているやり方に頼る傾向があり、それは必ずしも速くもエレガントでもない。 私にとって、ループのロジックを使用すると、やりたいことを実行する機能的なコードを作成でき、次のステップに進むことができることがあります。
JMP 16 では JMP 15 に比べて For Loop と Recode オプションがわずかに遅いのは興味深いことですが、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);
列プロパティの値ラベルと欠損値コードを使用するオプションもあり、場合によっては機能する可能性があります。 データを変更する必要がないので、可能な限りそれらを使用することを好みます。