こんにちは、みんな、
前回の投稿から少し時間が経ちましたが、その間にJMPの使い方が少し上達したと思います。恥ずかしげもなく、今話題のAI-LLM(法学修士)コースを使って日本語(JSL)を独学で学ぶのは、なかなかうまくいっています。しかし、JMPに関して、長年悩まされてきた問題に遭遇しました。
タイトルの通り、重複した値のない大きなテーブルを連結した際に発生します。JMP 18を使用しています。テスト用のデータテーブルを2つ添付しました(明らかに非常に限定的で整理されたデータセットですが、実際のデータは10万行以上、30列以上です)。これらはプロジェクトに添付した方が良いかもしれません。おっと。
背景を説明させてください(結局のところ非常に直接的な質問のため、多くの背景があり、申し訳ありません)。
定期的なデータ分析のためのワークフローは、ある程度整備されています。サンプルIDと関連情報を含むサンプル追跡テーブルと、テストから得た情報を入力する一般データテーブルがあります。これら2つは、サンプルIDをキーとする仮想結合を使用してリンクされています。サンプル情報テーブルでは、各サンプルIDは一意です。サイクルデータテーブルでは、各サンプルIDに複数のデータ行があり、それぞれに(理想的には)一意のサイクルIDが割り当てられています。サンプルIDとサイクルIDの一意の組み合わせには、それぞれ関連データ(さまざまなパフォーマンス指標)があります。
テストには複数のサイクルが含まれます。実際、テストはライブであり、サイクル番号と関連データは常に更新されます。私は定期的に各サンプルのサイクルデータをエクスポートし、JMPにインポートして、最新のスナップショットとバルクデータテーブルの2つのテーブルを連結します。このプロセスにより、多数の重複データが作成されます。例えば、サンプルAを例に挙げましょう。バルクデータテーブルのAには、既にサイクルID 1 -> 1000が設定されています。最新のスナップショットでは、AにはサイクルID 1 -> 1200のデータが含まれます。テーブルを連結すると、バルクデータテーブルには、サンプルAのサイクルID 1 -> 1000 *2と、1001 -> 1200 *1が含まれます。
私の個人的なワークフローとしては、これは理想的ではありませんが、問題ありません。すべての列を選択し、重複する行をすべて選択して削除します。最適ではありませんが、まあいいでしょう。
実は、この問題は最近私が取り組んでいることに起因しています。私がバルクデータを構築する方法と仮想結合の組み合わせは、データフィルタリングに非常に効果的な戦略です。チームメンバーもこの戦略に気づき、私も少し努力して、他のメンバーにも同様の戦略を採用するよう説得しました。しかし、私はグループ内で最も熟練したJMPユーザーです。他のメンバーは、JMP/JSLの複雑な機能を扱うための学習に、私ほどの時間と労力を費やす余裕がありません。これは問題ありません。喜んで引き受けたい責任です。
しかし、私は彼らに私のデータ処理能力にアクセスしてもらいたいのです。
解決策を思いつきました。バルクデータテーブルを外部テーブルとして管理し、管理者のようなプロジェクトを使って更新するというものです。各自のプロジェクトで自動初期化するスクリプトを作成し、マスターファイルのローカル埋め込みコピーを各自のプロジェクトに自動更新する関数を定義しました。これらは問題なく動作し、他のユーザーのプロジェクトでマスターデータテーブルのスナップショットを呼び出すことができます!素晴らしい、とても満足しています。問題は、最も論理的なアプローチは、実際にそのスナップショットを操作できないようにすることです。私が作成したスクリプトは、更新のたびにそのテーブルを削除し、同じ名前の新しい同一のテーブルを生成します。この動作を厳密に維持したいのです。これにより、ユーザーが異なるスナップショットの時点で、異なる名前のマスターテーブルのコピーを30個も持つことがなくなります。次のステップは、マスターコピーから取得した新しいデータで、ユーザー自身の作業データテーブルを更新することです。
それを実現するためのスクリプトを書こうとしています。ユーザーが追加した内容を保持したまま、作業テーブルを更新する必要があります。
Update() 関数を使ってみましたが、私の知る限り、既存のデータが新しいデータに置き換えられるだけです。新しい行を追加する方法がどうしても分かりません。Join 関数は新しい行を追加しますが、同時に新しいテーブルも作成します。どちらの解決策も私にはうまくいきません。唯一考えられるのは連結する方法です。しかし、ユーザーに重複行の処理をさせたくありません。重複は深刻な問題になることもあります。データテーブルは数十万行あり、一度に5万行もの重複が存在する可能性があります。
私が現在行っているアプローチ (JSL を含む) は、マスター テーブルと作業テーブルに一時的な列を作成することです。これらはサンプル ID || サイクル ID を連結して、一意の単一列キーを作成します。これを keyKey と呼びます。次に、マスター テーブルに 2 つ目の列を作成します。この列でテーブル 1 とテーブル 2 の keyKey を比較します。これをセレクター列と呼びます。keyKey が両方のテーブルに存在する場合はセレクター列の値を 0 にし、マスターにのみ存在する場合は値を 1 にします。次に、スクリプトで値が 1 のすべての行を選択し、その選択に基づいて一時的なサブセット テーブルを作成し、そのサブセットを作業テーブルに連結します。これで完了です。重複のない連結です。しかし、どうしても 2 つのテーブル間で keyKey を比較し、その比較を使用して列の値を生成する方法がわかりません。
For Each Row() ループの使用を極力避けようとしています。100,000行を超えるデータテーブルでは、メモリ負荷が大きくなるのは避けたいのです。
<
名前はデフォルトでここに設定されます(1);
// - - 構成 - -
workingTableName = "Working_Data_Test";
readOnlyMasterName = "Master_Data_Test";
keyColA = "セルID";
keyColB = "サイクルID";
// --- ハンドルを取得してエラーチェックを実行する ---
dtWorking = データ テーブル ( workingTableName ) ;
dtMaster = データ テーブル ( readOnlyMasterName ) ;
If( Is Empty( dtWorking ) | Is Empty( dtMaster ), Throw("両方のテーブルが開いていることを確認してください。") );
// --- ステップ 1: 既存の行を更新する---
//Print( "ステップ 1: 既存の行を更新しています..." );
//dtWorking << 更新(
// With(dtMaster)、
// 列を一致させる( :Name(keyCols[1]) = :Name(keyCols[1]), :Name(keyCols[2]) = :Name(keyCols[2]) )
//);
// --- ステップ 2: 一時的な連結キーを使用して新しい行を検索する ---
Print( "ステップ 2: 明示的な For Each Row ループを使用して新しい行を検索します..." );
// 最初に両方のテーブルに空の一時キー列を追加します。
dtWorking << 新しい列 ( "~temp_key~", 文字 );
dtMaster << 新しい列( "~temp_key~", 文字);
// 作業テーブルのキーを設定する
各行について(dtWorking,
:Name("~temp_key~") = :Name("セルID") || "|" || Char(:Name("サイクルID"));
);
// マスターテーブルのキーを入力します
各行(dtMaster,
:Name("~temp_key~") = :Name("セルID") || "|" || Char(:Name("サイクルID"));
);
// 作業テーブル内のすべての一時キーの高速検索リストを作成します。
workingKeys = 連想配列 ( dtWorking:Name ("~temp_key~") );
//マスター テーブルに新しい「フラグ」列を追加します。
dtMaster << 新しい列( "~is_match~", 数値
// 数式を使って値を設定します。数式は、キーが新規の場合は0を、一致する場合は1を返します。
列(dtMaster, "~is_match~") << 数式を設定(
If( Is Missing( workingKeys[ :Name("~temp_key~") ] ),
0, // workingKeysに見つからない -> 新しい行です
1 // workingKeys で見つかりました -> 既存の行です
)
);
// --- ステップ 3: 選択した行から新しい一時テーブルを作成する ---
If( N Rows( dtMaster << 選択された行を取得 ) > 0,
Print( "新しい行が見つかりました " || Char( N Rows( dtMaster << Get Selected Rows ) ) || " 。一時テーブルを作成しています..." );
dtTempNewRows = dtMaster << サブセット(
選択された行(1)
出力テーブル名(「Temp New Rows」)
);
dtTempNewRows << ウィンドウを表示(1);
、
Print("追加する新しい行が見つかりません。");
);
// --- ステップ 4: 一時列をクリーンアップする ---
//Try( dtWorking << Delete Columns( "~temp_key~" ) );
//Try( dtMaster << Delete Columns( "~temp_key~" ) );
//dtMaster << 選択をクリア;
Print( "テストが完了しました。" );>
また、列名の識別に文字列変数を使用する方法 (手順 1、これを修正する方法もわからなかったためコメント アウトしました) を誰かが教えてくれると助かります。
とにかく、この巨大な投稿を読んでくれてありがとう。
遅い