再次突破!
幾週前我和我爸爸聊天。 沒有和他約會,但他一直在使用聯合管理計劃從1.0版本開始。 我記得當我第一次學習使用鼠標時,看到 3.5 英寸光盤放在我們的 Mac II-se 旁邊。 同一台機器還在亞利桑那州圖森舉行的 2019 年探索峰會上展出。 這是它的圖片:

不管怎樣,我和我爸爸正在討論我的第一個五件事博客系列。 他提到他希望有人寫一個關於如何開始在 JMP 中編寫腳本的系列文章。 當時,我已經在寫一些其他文章了,所以我把它收起來以供將來的項目使用。 然而,生活卻另有計劃。 一周後,我被要求幫助進行客戶演示,令我驚訝的是,他們希望我介紹的主題之一是腳本編寫簡介! 顯然,宇宙喜歡笑話。
無論如何,我們又來了! 按照我的第一個五件事系列的格式,以下是我認為每個人在開始編寫腳本時都應該知道的五件事。 首先,一個概念性的想法。
看到需求,滿足需求
在開始編寫腳本之前,您需要考慮需求。 如果你想編寫腳本,很可能是有某種原因的。 也許您這樣做是為了讓自己的工作更有效率。 也許您正在尋求標準化團隊的分析方法。 或者事實上,您可能是那些少數決定因為笑容和咯咯笑而選擇它的人之一。 這些都不是壞原因,儘管最後一個可能會讓事情變得更加困難(我稍後會解釋原因)。 關鍵是你的腦海中應該有一個理由和你的第一個腳本的具體目的。
有腳本,然後有腳本
無論如何,在我看來,有兩種不同類型的腳本:作用於現有數據的腳本和創建數據的腳本。 用於處理現有數據的腳本與 JMP 中的數據表和現有平台進行交互,以創建新的用戶定義的輸出。 這些可以像在多個報表周圍包裹一個窗口一樣簡單,也可以像在“App 開發器”中自定義構建的報表一樣複雜。 關鍵的共同點是像這樣的腳本修改現有內容。
第二組是創建數據的腳本。 創建數據的腳本可以是模擬工具、自定義圖形、管理 JMP 文件中元數據的工具等。這組腳本有點模糊,但共同的主題是腳本以超出豐富現有數據或分析的方式擴展 JMP。 大多數時候,這些腳本將創建新內容從頭開始。
當人們考慮學習 JMP 腳本語言 (JSL) 時,通常會從修改現有內容的腳本開始。 這也是我們要開始討論的地方。 那麼,讓我們退後一步思考一下您為什麼對學習 JSL 感興趣。
給我一句話,瓦西里。 請只說一句話。
花點時間想想你的需要。 您希望通過 JSL 解決哪個痛點? 您現在明白為什麼編寫笑容和咯咯笑的腳本(至少一開始是這樣)會很棘手嗎? 如果你有理由達到頂峰,你就更有可能克服學習曲線。 我並不是說你不能選擇 JSL,只是說如果沒有額外的動力,戰鬥會更加困難。
下一步,也是我們將在本集中介紹的最後一步,就是您如何滿足這一需求。 簡單的答案是您要做兩件事。 首先,您將把驅使您學習 JSL 的想法(可能是模糊的)寫成一個句子——一個問題陳述。 而且,我的意思只是一句話。 確保你能夠將這個想法具體化為你可以構建的有形的東西。 它還將有助於控制範圍蔓延。 這裡有些例子:
- 我想將每週報告的所有圖表生成自動化到一個腳本中。
- 我想自動化客戶提供的數據表的格式化工作。
- 我想從工廠計算機系統提供的數據文件生成一組控製圖。
請注意,我不是在談論細節;而是在談論細節。我只是簡單地闡述一下讓我關注 JSL 的痛點。 然後我就不再寫作了。
列出你的待辦事項清單
有你的問題陳述嗎? 好的! 現在我們將為您的腳本編寫一系列具體的可交付成果。 它將成為我們的遺留問題清單,幫助我們找到 SAS 為學習 JSL 提供的資源。 不要專門列出任何圖形用戶界面 (GUI) 或用戶界面 (UI)。 列出腳本需要執行的操作。 以下是上述問題陳述的示例:
問題陳述1:我想將每週報告的所有圖表生成自動化到一個腳本中。
遺留問題清單:
- 從我們的生產數據庫中提取包含過去三週數據的數據集。
- 為我的產品製作時間與溫度的圖表。
- 使用多項式模型運行時間與溫度的分析。
- 將圖表和報告導出到 PowerPoint 文件。
問題陳述2:我想自動化客戶提供的數據表的格式化工作。
遺留問題清單:
- 根據內部標準重命名列(使用規範中的表)。
- 將單位分配給所需的列(使用規格中的表格)。
- 將緯度和經度轉換為地理坐標。
- 改變有缺陷的單位專欄來自連續的到序數。
問題陳述3:我想從工廠計算機系統提供的數據文件生成一組控製圖。
遺留問題清單:
- 從網絡位置導入數據。
- 指定規格限制。
- 構建控製圖。
請注意,我並沒有過多地限制自己。 我只是在列出我需要腳本完成的事情的清單。 由於我假設您以前從未使用過 JSL,因此我還假設您不知道將如何解決這些問題。 通過寫下來,您就知道需要在幫助和資源中尋找什麼。 這就是我將在本系列的下一部分中討論的內容。
本週的總結
由於這個系列將持續幾週的時間,我決定讓它更像是一個合作系列,而不是你剛剛讀過的東西。 因此,請將我提出的最後幾點作為家庭作業。 如果您想要一些責任或反饋,請將它們放在下面的評論中。 如果我能提供幫助,我會插話,或者讓你知道,如果你以後可能會給自己帶來一些麻煩。
要獲得獎勵積分,請在 JMP 中打開腳本窗口(文件>新建>腳本)並將問題陳述和項目符號點放入腳本窗口中,每行一個,並在行首添加一個雙正斜杠(“//”)。 您可能會在 JSL 腳本編輯器中看到這些行的文本顏色變為綠色。 我們將在下一集中介紹您剛剛所做的事情。
哦,如果你想知道瓦西里是誰以及為什麼他應該給你一個單一的句子,請看看這裡。
好主意;心存善念;睿智哲思。用於學習 JMP,新版本跳轉到 JMP 腳本編寫,墨菲和盧卡斯對我很有幫助。
我主要的程式語言是SAS。資料步、巨集語言、proc sql、proc iml,所以它實際上並非一種單一的語言——但我偶然看到一個使用JMP的短期課程,立刻就被它吸引了。為什麼呢?這些年來,我逐漸意識到真正重要的只有兩件事。
1. 我最初問的是你的軟體能否給出正確答案,但我後來改成了你的軟體能否給出一個在受到質疑或批評時可以辯護的答案。
2. 你能多快得到問題 1 的答案?
我最初只使用了 JMP 的點擊式功能,但我發現我需要學習一些 JSL 才能更有效地使用 JMP。
例如,我正在向學生示範如何使用 k 近鄰演算法預測連續型結果變數。假設有 12 個可能的預測變數(連續型和名目型混合),結果變數為連續型,並有一個驗證變數。我想展示隨著預測變數的減少, R² 、RASE 和 AAE 的變化。這需要先用 12 個預測變數運行一次,然後用 11 個,以此類推,直到最後用兩個預測變數運行一次。我從您部落格系列的第三篇文章中了解到了「新視窗」功能。
New Window("My Window",
// Launch platform: K Nearest Neighbors 12 Variables
Data Table( "Boston Housing Plus Validation Column" ) <<
K Nearest Neighbors(
Validation( :Validation ),
Y( :MEDV ),
X(:CRIM, :ZN, :INDUS, :CHAS, :NOX, :RM, :AGE, :DIS, :RAD, :TAX, :PTRATIO, :LSTAT),
K( 20 )
);
additional analyses with 10 predictors down to last run with 2. So, a total of 11 analyses.
);
「新視窗」會將結果輸出到一個視窗中,而不是像使用 11 個不同的預測變數清單來執行 k-nn 演算法那樣輸出到 11 個視窗。然後,我可以右鍵單擊結果表格,選擇“建立合併資料表”,這樣就能在一個表格中看到所有 11 個分析的結果。
顯然,我需要將包含 11 種不同分析(從 12 個預測變數減少到 2 個)的程式碼轉換成循環。這是我學習 JSL 的下一步。
JMP jsl 入門。
感謝您的回覆。我使用的是Windows系統上的JMP學生版19。
約翰
@jkeighley ,謝謝你的讚揚!很高興你覺得這個系列有用。雖然有點深入,但你可以看看這個例子…它或許能給你一些關於如何建立新報告的想法(腳本索引應該可以幫你解決一些細節問題):
Names Default To Here( 1 );
Clear Log();
// data table goes here
dt = Open( "$Sample_Data/penguins.jmp" );
// report names go here (this is what the tabs will be named)
reportNames = {"report 1", "report 2", "report 3", "report 4", "report 5"};
// jsl for each tab's contents go here. One tab per Expr() call. They
// should be in the same order as the report names.
reportScripts = {Expr(
dt << Scatterplot 3D(
Y( :Culmen Length, :Culmen Depth, :Flipper Length ),
Coloring( :Species ),
Normal Contour Ellipsoids( 1, :Species ),
Nonpar Density Contour( 1, :Species ),
Legend( 1 ),
Frame3D(
Set Graph Size( 655, 672 ),
Legend( 1 ),
Set Grab Handles( 0 ),
Set Rotation( -72.1900689453449, -1.75327107936844, 34.4563606108469 )
),
SendToReport( Dispatch( {}, "Density Contour Controls", OutlineBox, {Close( 1 )} ) )
)
), Expr(
dt << Hierarchical Cluster(
Y( :Culmen Length, :Culmen Depth, :Flipper Length, :Body Mass, :Delta 15 N, :Delta 13 C ),
Label( :Species ),
Method( "Centroid" ),
Standardize By( "Columns" ),
Color Clusters( 1 ),
Show Dendrogram( 0 ),
Dendrogram Scale( "Distance Scale" ),
Number of Clusters( 4 ),
Constellation Plot( 1 ),
Cluster Summary( 1 )
)
), Expr(
dt << Graph Builder(
Size( 662, 560 ),
Show Control Panel( 0 ),
Variables( X( :Species ), Y( :Culmen Length ) ),
Elements( Points( X, Y, Legend( 3 ) ) )
)
), Expr(
dt << Graph Builder(
Size( 662, 552 ),
Show Control Panel( 0 ),
Variables( X( :Body Mass ), Y( :Flipper Length ), Overlay( :Species ) ),
Elements( Points( X, Y, Legend( 13 ) ), Contour( X, Y, Legend( 16 ), Contour Type 2D( "HDR" ) ) ),
SendToReport(
Dispatch( {}, "Graph Builder", FrameBox,
{DispatchSeg( Contour Seg( "Contour (Adelie penguin (Pygoscelis adeliae))" ), {Line Color( {230, 159, 0} )} ),
DispatchSeg( Contour Seg( "Contour (Chinstrap penguin (Pygoscelis antarctica))" ), {Line Color( {86, 180, 233} )} ),
DispatchSeg( Contour Seg( "Contour (Gentoo penguin (Pygoscelis papua))" ), {Line Color( {0, 158, 115} )} )}
)
)
)
), Expr(
dt << Fit Group(
Bivariate( Y( :Flipper Length ), X( :Culmen Length ), Nonpar Density( {Contour Fill( 1 ), Color Theme( "Spectral" )} ) ),
Bivariate( Y( :Flipper Length ), X( :Culmen Depth ), Nonpar Density( {Contour Fill( 1 ), Color Theme( "Spectral" )} ) ),
Bivariate( Y( :Body Mass ), X( :Culmen Length ), Nonpar Density( {Contour Fill( 1 ), Color Theme( "Spectral" )} ) ),
Bivariate( Y( :Body Mass ), X( :Culmen Depth ), Nonpar Density( {Contour Fill( 1 ), Color Theme( "Spectral" )} ) ),
<<{Arrange in Rows( 2 )}
)
)};
// I'm creatng an Associative array to manage the looping for me
reports = Associative Array( reportNames, reportScripts );
// build the window wrapper
nw = New Window( "Example Report", tb = Tab Box() );
// loop through the AA and append each tab page box to the tab box in the report
For Each( {{k, v}, i}, reports, tb << Append( Tab Page Box( Title( k ), Eval( v ) ) ) );
// set the view back to the first report.
tb << Set Selected( 1 );