大家好,
距離上次發文已經有一段時間了,這段時間裡,我覺得我的 JMP 使用能力提升了一些。坦白說,利用蓬勃發展的 AI-LLM 自學 JSL 確實很有效。然而,我遇到了一個困擾我很久的 JMP 使用問題。
如標題所述,它源自於大型表格的連接,且不包含重複值。我使用的是 JMP 18 版本。我附加了兩個測試資料表(顯然資料集非常有限且經過了清理,實際資料集包含超過 10 萬行,超過 30 列)。這些應該附加到項目中,哎呀。
讓我解釋一下背景(很多背景資訊最終都指向一個非常直接的問題,抱歉):
我有一個合理開發的常規數據分析工作流程。我有一個樣本追蹤表,其中包含樣本 ID 及其相關資訊。我還有一個通用數據表,我會用我的測試資訊填充它。這兩個表使用虛擬連接進行關聯,以樣本 ID 為鍵。在樣本資訊表中,每個樣本 ID 都是唯一的。在周期數據表中,每個樣本 ID 包含多行數據,每行(理想情況下)都有一個唯一的周期 ID。樣本 ID 和週期 ID 的每個唯一組合都包含相關資料(各種效能指標)。
一個測試有多個循環——實際上,一個測試處於即時狀態,其循環編號及其相關資料會不斷更新。我會定期匯出每個樣本的循環數據,將其匯入 JMP,然後連接兩個表——最新快照和批次數據表。這個過程會產生很多重複數據。例如,以樣本 A 為例。批次資料表中 A 的循環 ID 已經是 1 -> 1000。在最新快照中,A 將包含循環 ID 1 -> 1200 的資料。我連接這些表,批量資料表將包含樣本 A 的循環 ID 1 -> 1000 *2 和 1001 -> 1200 *1。
就我個人的工作流程而言,這並不理想,但還好。我選擇所有列,選擇所有重複的行,然後刪除它們。雖然不是最優方案,但沒關係。
這個問題其實源自於我最近的工作。我建立大量資料的方式以及與虛擬連線的結合是一種非常有效的資料過濾策略。我的團隊注意到了這一點,我透過一些努力說服大家採取類似的策略。然而,我是我們團隊中 JMP 等級最高的用戶。其他人沒有我那麼多的時間或精力去學習處理 JMP/JSL 的複雜細節。這沒關係,我樂於承擔這份責任。
但是,我希望他們能夠存取我處理資料的能力。
我想到了一個解決方案。我的想法是,將批量資料表維護為外部表。我將使用類似管理員的專案來更新它。我編寫了一些腳本,可以在他們的專案中自動初始化,並定義一些函數來自動將主文件的本地嵌入副本刷新到他們的專案中。這些腳本運作良好——我可以成功調用其他人專案中主資料表的快照!太好了,我對此非常滿意。問題在於,最合理的方法是實際上不允許他們處理該快照。我編寫的腳本會在每次刷新時刪除該表,並在其位置產生一個名稱相同的新表。我希望保持這種情況——這樣可以防止用戶在不同的快照時刻擁有 30 個名稱不同的主表副本。下一步是用主副本中的新資料更新使用者自己的工作資料表。
我正在嘗試編寫一個腳本來實現這一點。我需要它更新工作表,同時保留用戶自己添加的內容。
我試過使用 Update () 函數,但據我所知,它只會用新資料取代現有資料。我怎麼也想不出怎麼讓它新增新行。 Join 函數會新增一行,但也會建立一個新表。這兩種方法對我來說都行不通。我能想到的唯一方法是連接。但我不想讓使用者處理重複的行。重複的行也可能非常嚴重——資料表有數十萬行,一次可能有多達 50,000 個重複項。
我現在的方法(包括 JSL)是在主表和工作表中建立臨時列。這些列連接樣本 ID || 週期 ID,創建一個唯一的單列鍵,我們稱之為 keyKey。然後,我想在主表中建立第二列。我希望此列比較表 1 和表 2 中的 keyKey,我們稱之為 Selector 欄位。如果 keyKey 存在於兩個表中,我希望 Selector 列中的值為 0;如果它只存在於主表中,我希望該值為 1。然後,我希望腳本選擇值為 1 的所有行,基於該選擇建立臨時子集表,然後將該子集連接到工作表。 Boom。無重複連線。但是。我終其一生都無法弄清楚如何在兩個表之間比較 keyKey 並使用該比較來產生列值。
我拼命避免使用 For Each Row() 迴圈。我不希望超過 100,000 行的資料表佔用太多記憶體。
<
名稱預設為此處(1);
// - - 配置 - -
workingTableName = "工作資料測試";
readOnlyMasterName = “Master_Data_Test”;
keyColA = "小區ID";
keyColB = "循環ID";
// --- 取得句柄並執行錯誤檢查 ---
dtWorking = 資料表(工作表名稱);
dtMaster = 資料表( readOnlyMasterName );
如果(為空(dtWorking)|為空(dtMaster),則拋出(“確保兩個表都已打開。”));
// --- 步驟 1:更新現有行---
//Print( "步驟 1:更新現有行..." );
//dtWorking<<更新(
// 使用(dtMaster),
// 符合欄位(:名稱(keyCols[1])=:名稱(keyCols[1]),:名稱(keyCols[2])=:名稱(keyCols[2]))
//);
// --- 步驟 2:使用臨時連線鍵尋找新行 ---
Print(“步驟 2:使用明確 For Each Row 迴圈尋找新行…”);
// 首先在兩個表格中新增空白臨時鍵列。
dtWorking << 新列( “~temp_key~”, 字元 );
dtMaster << 新列( “~temp_key~”, 字元 );
// 填滿工作表的鍵
對於每一行(dtWorking,
:名稱(“〜temp_key〜”)=:名稱(“單元ID”)||“|”|| Char(:名稱(“週期ID”));
(此處似有缺失,請提供更正的文字)。
// 填滿主表的鍵
對於每一行(dtMaster,
:名稱(“〜temp_key〜”)=:名稱(“單元ID”)||“|”|| Char(:名稱(“週期ID”));
(此處似有缺失,請提供更正的文字)。
// 建立工作表中所有臨時鍵的快速尋找清單。
workingKeys = 關聯陣列(dtWorking:名稱("~temp_key~"));
//向主表新增一個新的「標誌」欄位。
dtMaster << 新列(“~is_match~”,數字
//使用公式設定其值。如果鍵是新的,則公式傳回 0;如果匹配,則傳回 1。
列(dtMaster,“~is_match~”)<<設定公式(
如果(缺少(workingKeys[:Name("~temp_key~")]),
0, // 在 workingKeys 中找不到 -> 這是一個新行
1 // 在 workingKeys 中找到 -> 這是一個現有行
)
(此處似有缺失,請提供更正的文字)。
// --- 步驟 3:從選定的行建立一個新的臨時表 ---
如果(N 行(dtMaster << 取得選定行)> 0,
列印(“找到”|| Char(N Rows(dtMaster << 取得選定的行))||“新行。建立臨時表...”);
dtTempNewRows = dtMaster << 子集(
選定行( 1 ),
輸出表名稱(“臨時新行”)
(此處似有缺失,請提供更正的文字)。
dtTempNewRows << 顯示視窗(1);
,
Print("未找到要新增的新行。");
(此處似有缺失,請提供更正的文字)。
// --- 步驟 4:清理臨時列 ---
//嘗試(dtWorking << 刪除列( “~temp_key~” ) );
//嘗試(dtMaster << 刪除列( “~temp_key~” ) );
//dtMaster << 清除選擇;
列印(“測試完成。”);>
此外,如果有人能幫助我弄清楚如何使用字串變數來識別列名(步驟 1,已註解掉,因為我也不知道如何解決這個問題),那就太好了。
無論如何,感謝你閱讀這篇巨著,
晚的