Hallo zusammen,
Seit meinem letzten Beitrag ist eine Weile vergangen, und ich glaube, ich bin in dieser Zeit etwas besser mit JMP geworden. Die Nutzung der boomenden KI-LLMs zum Selbstlernen von JSL hat sich schamlos bewährt. Allerdings stoße ich auf ein Problem, das mich bei JMP schon lange plagt.
Wie der Titel schon sagt, entsteht es durch die Verkettung großer Tabellen ohne Duplizierung von Werten. Ich verwende JMP 18. Ich habe zwei Testdatentabellen angehängt (mit offensichtlich sehr begrenztem und bereinigtem Datensatz; die echten Tabellen enthalten >100.000 Zeilen und >30 Spalten). Diese sollten wahrscheinlich einem Projekt angehängt werden, ups.
Lassen Sie mich den Hintergrund erklären (viel Kontext für eine letztlich sehr direkte Frage, entschuldigen Sie):
Ich verfüge über einen gut ausgearbeiteten Workflow für die regelmäßige Datenanalyse. Ich verfüge über eine Probenverfolgungstabelle mit Proben-IDs und den zugehörigen Informationen. Ich habe eine allgemeine Datentabelle, die ich mit Informationen aus meinen Tests fülle. Die beiden Tabellen sind über einen virtuellen Join verknüpft, wobei die Proben-ID als Schlüssel dient. In der Probeninformationstabelle ist jede Proben-ID eindeutig. In der Zyklusdatentabelle enthält jede Proben-ID mehrere Datenzeilen mit jeweils (idealerweise) einer eindeutigen Zyklus-ID. Jede eindeutige Kombination aus Proben-ID und Zyklus-ID verfügt über zugehörige Daten (verschiedene Leistungskennzahlen).
Ein Test umfasst mehrere Zyklen. Tatsächlich ist ein Test live, und die Zyklusnummer sowie die zugehörigen Daten werden ständig aktualisiert. Regelmäßig exportiere ich die Zyklusdaten für jede Probe, importiere sie in JMP und verbinde dann die beiden Tabellen – den neuesten Snapshot und die Massendatentabelle. Dieser Prozess erzeugt zahlreiche Duplikate. Nehmen wir beispielsweise Probe A. A in der Massendatentabelle hat bereits die Zyklus-ID 1 -> 1000. Im neuesten Snapshot enthält A Daten für die Zyklus-ID 1 -> 1200. Ich verbinde meine Tabellen, und die Massendatentabelle enthält für Probe A die Zyklus-ID 1 -> 1000 *2 und 1001 -> 1200 *1.
Für meinen persönlichen Arbeitsablauf ist das nicht ideal, aber es ist in Ordnung. Ich wähle alle Spalten aus, wähle alle doppelten Zeilen aus und lösche sie. Nicht optimal, aber egal.
Das Problem liegt eigentlich an meiner jüngsten Arbeit. Die Art und Weise, wie ich meine Massendaten aufbaue und die Kombination mit virtuellen Verknüpfungen ist eine sehr effektive Strategie zur Datenfilterung. Mein Team hat das bemerkt, und mit einigem Aufwand konnte ich andere davon überzeugen, ähnliche Strategien zu übernehmen. Allerdings bin ich der fortgeschrittenste JMP-Anwender in unserer Gruppe. Die anderen haben nicht so viel Zeit und Engagement, sich mit den Feinheiten von JMP/JSL vertraut zu machen. Das ist in Ordnung, es ist eine Verantwortung, die ich gerne übernehme.
Aber ich möchte, dass sie Zugriff auf meine Fähigkeit zur Datenverarbeitung haben.
Ich habe eine Lösung gefunden. Die Idee ist, die Massendatentabelle als externe Tabelle zu verwalten und sie mithilfe eines Administratorprojekts zu aktualisieren. Ich habe Skripte geschrieben, die sich in ihren Projekten automatisch initialisieren und Funktionen definieren, um eine lokal eingebettete Kopie der Masterdatei automatisch in ihre Projekte zu aktualisieren. Diese funktionieren einwandfrei – ich kann erfolgreich auf einen Snapshot der Masterdatentabelle in den Projekten anderer Benutzer zugreifen! Super, damit bin ich sehr zufrieden. Das Problem ist, dass es am logischsten ist, ihnen die Arbeit an diesem Snapshot zu verbieten. Das Skript, das ich geschrieben habe, löscht die Tabelle bei jeder Aktualisierung und generiert stattdessen eine neue identische Tabelle mit demselben Namen. Das möchte ich unbedingt beibehalten – so verhindern wir, dass Benutzer zu verschiedenen Snapshot-Zeitpunkten 30 Kopien der Mastertabelle mit unterschiedlichen Namen haben. Im nächsten Schritt wird die eigene Arbeitsdatentabelle des Benutzers mit den neuen Daten aus der Masterkopie aktualisiert.
Ich versuche, ein Skript zu schreiben, um dies zu erreichen. Ich brauche es, um die Arbeitstabelle zu aktualisieren und gleichzeitig alles beizubehalten, was die Benutzer selbst hinzugefügt haben.
Ich habe versucht, die Update-Funktion () zu verwenden, aber soweit ich weiß, ersetzt sie nur vorhandene Daten durch neue. Ich kann einfach nicht herausfinden, wie ich damit neue Zeilen hinzufügen kann. Join fügt zwar neue Zeilen hinzu, erstellt aber auch eine neue Tabelle. Keine der Lösungen funktioniert bei mir. Die einzige Möglichkeit, die ich kenne, ist die Verkettung. Ich möchte aber nicht, dass die Benutzer mit doppelten Zeilen zu kämpfen haben. Die Duplikate können auch sehr schwerwiegend sein – die Datentabellen bestehen aus Hunderttausenden von Zeilen, und es können bis zu 50.000 Duplikate gleichzeitig vorhanden sein.
Mein aktueller Ansatz (einschließlich JSL) besteht darin, temporäre Spalten in der Master- und der Arbeitstabelle zu erstellen. Diese verknüpfen die Beispiel-ID || Zyklus-ID und erstellen einen eindeutigen einzelnen Spaltenschlüssel, nennen wir ihn „keyKey“. Dann möchte ich eine zweite Spalte in der Mastertabelle erstellen. Diese Spalte soll den „keyKey“ in Tabelle 1 und Tabelle 2 vergleichen, nennen wir sie die „Selector“-Spalte. Wenn der „keyKey“ in beiden Tabellen vorhanden ist, soll der Wert in der „Selector“-Spalte 0 sein. Wenn er nur in der Mastertabelle vorhanden ist, soll der Wert 1 sein. Dann möchte ich, dass das Skript alle Zeilen mit dem Wert 1 auswählt, eine temporäre Teiltabelle basierend auf dieser Auswahl erstellt und diese Teilmenge dann mit der Arbeitstabelle verknüpft. Boom. Duplikatsfreie Verkettung. ABER. Ich kann beim besten Willen nicht herausfinden, wie ich den „keyKey“ zwischen zwei Tabellen vergleiche und diesen Vergleich zum Generieren eines Spaltenwerts verwende.
Ich versuche verzweifelt, die Verwendung von For Each Row()-Schleifen zu vermeiden. Ich möchte diese Speicherbelastung bei Datentabellen mit mehr als 100.000 Zeilen vermeiden.
<
Namen werden standardmäßig hier verwendet(1);
// --- Konfiguration ---
workingTableName = "Arbeitsdatentest";
readOnlyMasterName = "Master_Data_Test";
keyColA = "Zellen-ID";
keyColB = "Zyklus-ID";
// --- Handles abrufen und Fehlerprüfungen durchführen ---
dtWorking = Datentabelle (Arbeitstabellenname);
dtMaster = Datentabelle (readOnlyMasterName);
Wenn (Ist leer (dtWorking) | Ist leer (dtMaster), Throw("Stellen Sie sicher, dass beide Tabellen geöffnet sind."));
// --- SCHRITT 1: Vorhandene Zeilen aktualisieren---
//Print( "Schritt 1: Vorhandene Zeilen aktualisieren..." );
//dtWorking << Update(
// Mit( dtMaster ),
// Spalten abgleichen( :Name(keyCols[1]) = :Name(keyCols[1]), :Name(keyCols[2]) = :Name(keyCols[2]) )
//);
// --- SCHRITT 2: Neue Zeilen mithilfe eines temporären verknüpften Schlüssels finden ---
Drucken( "Schritt 2: Suchen neuer Zeilen mit einer expliziten For Each Row-Schleife …" );
// Fügen Sie zuerst beiden Tabellen die leeren temporären Schlüsselspalten hinzu.
dtWorking << Neue Spalte( "~temp_key~", Zeichen );
dtMaster << Neue Spalte( "~temp_key~", Zeichen );
// Den Schlüssel für die Arbeitstabelle auffüllen
Für jede Zeile (dtWorking,
:Name("~temp_key~") = :Name("Zellen-ID") || "|" || Char(:Name("Zyklus-ID"));
);
// Den Schlüssel für die Mastertabelle auffüllen
Für jede Zeile (dtMaster,
:Name("~temp_key~") = :Name("Zellen-ID") || "|" || Char(:Name("Zyklus-ID"));
);
// Erstellen Sie eine schnelle Nachschlageliste aller temporären Schlüssel in der Arbeitstabelle.
workingKeys = Assoziatives Array( dtWorking:Name("~temp_key~") );
//Fügen Sie der Mastertabelle eine neue „Flag“-Spalte hinzu.
dtMaster << Neue Spalte( "~is_match~", Numerisch
//Legen Sie den Wert mithilfe einer Formel fest. Die Formel gibt 0 zurück, wenn der Schlüssel neu ist, und 1, wenn er übereinstimmt.
Spalte( dtMaster, "~is_match~" ) << Formel festlegen(
Wenn (fehlt (workingKeys [: Name ("~temp_key~")]),
0, // Nicht in workingKeys gefunden -> Es ist eine neue Zeile
1 // Gefunden in workingKeys -> Es ist eine vorhandene Zeile
)
);
// --- SCHRITT 3: Erstellen Sie eine neue temporäre Tabelle aus den ausgewählten Zeilen ---
Wenn (N Zeilen (dtMaster << Ausgewählte Zeilen abrufen) > 0,
Print( "Gefunden " || Char( N Rows( dtMaster << Get Selected Rows ) ) || " neue Zeilen. Temporäre Tabelle wird erstellt..." );
dtTempNewRows = dtMaster << Teilmenge(
Ausgewählte Zeilen (1),
Name der Ausgabetabelle ("Temp New Rows")
);
dtTempNewRows << Fenster anzeigen(1);
,
Drucken("Keine neuen Zeilen zum Hinzufügen gefunden.");
);
// --- SCHRITT 4: Temporäre Spalten bereinigen ---
//Versuchen Sie (dtWorking << Spalten löschen ("~temp_key~"));
//Versuchen Sie (dtMaster << Spalten löschen ("~temp_key~"));
//dtMaster << Auswahl löschen;
Drucken( "Test abgeschlossen." );>
Außerdem wäre es großartig, wenn mir jemand dabei helfen könnte, herauszufinden, wie ich Zeichenfolgenvariablen zur Identifizierung von Spaltennamen verwenden kann (Schritt 1, auskommentiert, weil ich auch nicht herausfinden konnte, wie ich das beheben kann).
Wie dem auch sei, danke fürs Lesen dieses gigantischen Beitrags.
Spät