您是否應該循環遍歷資料表或使用重新編碼,或使用獲取行位置來更改資料表中的值最近的社群討論用於在整個表中查找數值並將其替換為缺失值的腳本提供了一個非常好的條目@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 RowsWhere()」的後備標準會更快。畢竟,在「非常快速」的 Get RowsWhere() 找到行之後,它允許使用一個賦值語句來設定所有找到的行。
我見過的另一個解決方案推社群推薦的是 JMP 中的 Recode 工具。
所以:
假設:Get RowsWhere 和 Recode 的內建 JMP 函數將比向下循環並遍歷整個資料表更快。
我選擇了 Semiconductor Capability 資料表,該表大小合適,有 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;
)
));
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 將被腳本更改為缺失 (.)。
方法:
- 啟動 JMP 16。
- 讀入半導體能力資料表
- 運行腳本以設定每列中的 999 個值
- 對 3 種方法中的每一種重複上述 2 個步驟,並將時間重新編碼為毫秒。
- 對 JMP15 重複上述步驟
這是重新編碼的腳本
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)
取得行的程式碼
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 RowsWhere。
歡迎大家批評指正.....
資料混合與清理品質和工藝工程回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值
@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 的系統 - 可以直接比較?
*)儘管子集是「不可見」開啟的。

回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值@hogi寫道:
……
如果用戶意識到問題,一個非常便宜的解決方案是添加一個評估()
便宜的關於 JSL 程式碼的複雜度與時間損失。
但對於較長的桌子評估(i)再次大幅損失替換(...,NameExpr(作為列()))) 。
所以:仍然相當快(與原始版本相比:),但沒有我預期的那麼快。
為什麼? 根本的差別是什麼?
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值嗯,也許可以將 JSL 切換到用戶友好模式(如果這會帶來更好的效能,則會預先評估變數)?
希望:取得行其中:速度問題
如果用戶意識到這個問題,便宜的解決方案是添加一個評估():
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 );
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值你好@ron_horne ,問題在於取得行,其中,所以速度應該/獨立於這些設定。
另一方面,如果列索引是明確的或它是一個變數(即使該變數具有指定的值),則會產生巨大的差異。
這對我來說並不清楚——我發現這次談話真是太好了!
我不知道有多少 jsl 程式碼可以比 ~ N(資料表行)更快...
這個問題可以透過 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();
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值謝謝@tx尼爾森
您能估計一下在不同方法上使用不可見和私有表的效果嗎?它們必須是修改任何腳本以提高效能的最快方法。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值哇,多棒的把戲啊:)
我擔心出現問題缺失值程式碼一旦您嘗試,就會開始:
Col Maximum(:NPN3)
[據我們所知排除行必須是排除在 Col 中手動聚合(或者更好:透過透過...分組爭論)。]
但令人驚訝的是:上校聚合尊重缺失值程式碼
挑剔一點: OP問題原帖的內容相當含蓄:
並且從結果來看,取得行的位置應謹慎使用。
歡迎大家批評指正.....
譯為──我的肚子裡有一種不安的感覺──為: “到底為什麼?!?”
謝謝@ErraticAttack為了解決這個難題:)
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值這是一次非常有趣且內容豐富的討論! 精彩的答案。 我確實沒有資格在這裡添加任何有價值的東西,所以我將訴諸“作弊”。
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 秒。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值啊,我不知道:
:姓名()行為就像作為列() ?
從腳本索引中不太清楚:)
所以,與代替和作為列()代替Eval(解析(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>
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值是的我明白@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];
但我非常懷疑這會比你已經擁有的更快,尤其是因為元素明智的乘法。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值這裡的比較有點錯誤——“獲取行位置”功能將評估每一行的表達式,因此您需要在運行循環之前最大限度地減少任何多餘的查找——特別是,您的迭代器是外部的,並且它必須進行一些範圍步行才能在每一行找到它。此外,它將評估每行的 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 倍,這應該可以與您擁有的其他方法相媲美(如果不是更好的話)
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值是的......障礙是,雖然可以使用單一索引存取矩陣(假定行主佈局),但資料表不能。 因此,遺憾的是沒有類似的
m[loc(m, 9999)] = .
其中 m 是資料表世界中的 pxq 矩陣...因此上面的程式碼中這一行之前和之後的行。 雖然程式碼仍然很快,但如果表可以使用單一索引訪問,那麼速度會非常快。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值為了 '創建矩陣的開銷'我懷疑數據表下標可能有幫助。@Craige_Hales會知道。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值這是一種避免循環的方法,儘管創建矩陣並在之後分配回表會產生開銷。 這種方法對此數據的執行速度很快,與 loc_2d 大致相同,但隨著表變得巨大,我預計其相對性能會受到影響,但我尚未驗證這一點。
expr_mat = expr(
m = dt[0, 5 :: N Col( dt )];
m[Loc( m, 999 )] = .;
dt[0, 5 :: N Col( dt )] = m;
);
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值在這方面可能有點太深入了(但至少有了一些想法,如果我必須的話,以後如何進行這種類型的測試)。
我用不同的表達式編寫了某種測試腳本來測試用缺失取代 999 的不同方法。 我使用兩個資料集(Semiconductor Capability.jmp 和 Probe.jmp)進行了測試,並更改了列中缺失值的數量。
Loc() 替換值的速度最快(這並不奇怪)。 Missing Value Codes()「總是」很快,但與 Loc() 相比,它的用例更有限,如果需要替換多個值,則使用起來會更麻煩。

最快的最終結果是 loc_2d (不必費心更改變數名稱:將 Loc 與 2D 矩陣結合使用)。 仍然需要循環來獲取值集(至少據我所知),所以最有可能比 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 without it,因為它會非常慢),但我確實測試了使用和不使用 Column() 的重新編碼。 我還注意到我在重新編碼中錯過了一個 Column() ,因此運行幾個快速測試(未附加在資料或腳本中):
這三者之間的差異相當大:
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)))
)
);
);

附上測試腳本和一些結果數據。 腳本很可能會出現一些錯誤。 如果有人願意的話,加入新的表達式應該相當容易。 我根本沒有測試的一件事是使用 << Begin/End 資料更新。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值有趣的討論! 我認為資料表矩陣表示法首次出現在 JMP 13 中,對於賦值來說非常有效。
對於這個特定問題,它幾乎比 for 循環快 500 倍(0,003 秒 vs 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」的欄位出現錯誤。
循環列仍然是必要的,因為對整個矩陣的直接分配(我一度認為這會更快)不起作用。 錯誤:“多個下標在訪問或評估的每個內部級別都需要單一下標......”,仔細想想,這是有道理的。
// 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 )] = .;
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值我可能在某些時候對使用循環持謹慎態度,但在學習了一門演算法課程(我從未完成...)之後,我的警覺性有所降低。 你只需要有效率地使用它們,通常你會循環太多(時間複雜度和 Big O 表示法)。 此外,使用循環比嘗試用純數學解決問題要容易得多。
對於 JMP,我通常只使用我在某些時候學到的安全選項,因為速度很少是問題。 但當時間成為問題時(一個應用程式在工作中打開需要 6 分鐘以上),我將開始尋找使其更快的方法(設法使其在不到 2 分鐘內啟動)。 在本例中,我透過將 Loc() 與其他函數的不同組合(刪除行、設定行狀態)結合使用,設法使其更快。
除了 Loc() 之外,與我長期以來最喜歡的獲取列中唯一值的選項(關聯數組() << 獲取鍵)相比,使用 Summarize() 似乎“方式”更快。 當行數增加時,Associative array() << get keys 變得越來越慢,而 Summarize() 似乎沒有遇到同樣的問題,至少沒有那麼快。 所以我嘗試開始更多地使用 Summarize() (永遠不知道數據表有多高)。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值因此,我們跳過 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);
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值我同意 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 語法@tx尼爾森原來的問題,For 循環仍然是最快的,但其他循環更具可比性。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值你好@tx尼爾森,
非常有趣的比較,但結果也不是我所期望的。 我記得當我第一次在大學學習程式設計時,也被教導了類似的東西:要警惕循環,因為它們很慢。
當然,透過一些計算和一些程序,我發現 For 循環非常慢——比其他循環慢。 然而,我並不是一個多麼優秀的程式設計師,我傾向於依靠我知道如何做的事情,這並不總是快速或優雅的。 有時對我來說,循環的邏輯允許我編寫一個功能程式碼來完成我想要它做的事情,這允許我繼續下一步。
我發現有趣的是,JMP 16 的 For Loop 和 Recode 選項比 15 稍慢,但 Get Rows 的改進之處在於將時間幾乎減少了一半,這是一個重大變化。
謝謝!,
DS
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值或許@Craige_Hales可以為我們提供更快的解決方案。 我從他的社群貼文/部落格中得到了使用矩陣計算(尤其是 Loc())的想法。
我製作了一種工作速度更快的工具,它可以打開資料集,然後刪除舊資料(基於使用者選擇)。 最初它使用 << 選擇位置並刪除行。 我用一些 Loc() 魔法替換了它,它也變得更快了。 我最近非常喜歡 Loc() 。
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值@jthi ,
您的基於矩陣的程式碼是最快的。
0.299795秒........
回覆:您是否應該循環遍歷資料表或使用重新編碼,或使用取得行在何處更改資料表中的值我在工作中一直在對我們擁有的一些舊腳本進行一些優化。 我必須更改的一些內容與獲取行的位置有關。 如果我需要快速的 JSL 程式碼,我已經開始使用越來越多的矩陣運算(主要是 Loc())。
例如,您可以將獲取行更改為以下位置(未測試它是否替換正確的值或全部值):
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);
還可以選擇使用列屬性值標籤和缺失值代碼,這在某些情況下可能有效。 我喜歡盡可能使用它們,因為這樣您就不會更改資料。