A Frage aus aandw über Spaltenformeln hat diesen Beitrag begonnen. Wenn Sie den Formeleditor nur zum Erstellen von Spaltenformeln verwenden, können Sie davon fast alles ignorieren. In diesem Beitrag geht es um die Verwendung von JSL zum Erstellen einer Spaltenformel.
Zunächst ein wenig zum Formelbefehl. Hier ist eine ganz einfache:
The formula for column C adds columns A and BThe formula for column C adds columns A and BThe formula for column C adds columns A and BThe formula for column C adds columns A and BDie Formel für Spalte C fügt die Spalten A und B hinzu
Das Tabellenskript (oberes linkes Dreieck -> Tabellenskript kopieren, in einen Editor einfügen) sieht folgendermaßen aus:
New Table( "abc", Add Rows( 2 ),
New Column( "a", Numeric, "Continuous",Format( "Best", 12 ),Set Values( [1, 7] )),
New Column( "b",Numeric,"Continuous",Format( "Best", 12 ),Set Values( [2, 9] )),
New Column( "c", Numeric, "Continuous", Format( "Best", 12 ),
Formula( :a + :p</img> )
)
)
Zeile 5 legt die Formel fest; Die Formel ist ein Ausdruck, der die Spalten a und b hinzufügt. Der Ausdruck wird erst viel später ausgeführt. Der Ausdruck wird als Ausdruck als Teil der Spalte gespeichert. Wenn der Tabelle eine weitere Zeile hinzugefügt wird oder die Werte in den Spalten a oder b geändert werden, kann der Ausdruck erneut ausgewertet werden, um einen Wert für Spalte c zu erhalten.
Das ist sowohl freundliches als auch ungewöhnliches Verhalten. Ungewöhnlich, da die meisten Funktionen ihre Argumente auswerten: sqrt( 4 + 5 ) gibt 3 zurück. Freundlich, weil Sie fast nie möchten, dass JMP die Formel einer Spalte auswertet, bevor sie der Spalte zugewiesen wird.
Manchmal kann ein Formelausdruck sehr kompliziert sein. So kompliziert, dass es einfacher wäre, ein Programm zum Schreiben des Ausdrucks zu schreiben. Um dies im Formelbefehl zu tun, benötigen Sie eine Möglichkeit, den Formelbefehl anzuweisen, das Argument vorab auszuwerten und den resultierenden Ausdruck als Formel zu verwenden. Sie tun dies, indem Sie einen eval( )-Wrapper um den Code herum hinzufügen, um ihn vorab auszuwerten. Wenn der Formelbefehl „eval“ um den Ausdruck sieht, führt er den Code aus und verwendet das Ergebnis.
lookup = function({t,u}, expr(a+b) );
New Table( "abc",
Add Rows( 2 ),
New Column( "a",Numeric,"Continuous",Format( "Best", 12 ),Set Values( [1, 7] )),
New Column( "b",Numeric,"Continuous",Format( "Best", 12 ),Set Values( [2, 9] )),
New Column( "c", Numeric, "Continuous", Format( "Best", 12 ),
Formula( eval( lookup(1,2) ) )
)
)
Die benutzerdefinierte „Lookup“-Funktion (Zeile 1) ist nicht sehr intelligent, muss aber ausgeführt werden, um expr(a+b) als Rückgabewert abzurufen. In Zeile 7 bedeutet der eval()-Wrapper, dass die Spaltenformel nicht auf „lookup(1,2)“ gesetzt wird, sondern auf den von „lookup(1,2)“ zurückgegebenen Ausdruck.Dieselbe Tabelle wie zuvor, mit derselben Spaltenformel.
Was wäre, wenn Sie möchten, dass die Spaltenformel auf einen Ausdruck festgelegt wird, der mit eval( ) beginnt?Wie könnte der Formelbefehl das tun, da der Beginn mit eval( ) bedeutet, das Argument auszuwerten und das Ergebnis zu verwenden? (Es wäre mir schwer gefallen, ein interessantes Beispiel zu finden, aber MS hat eine in der Antwort auf die Frage.) Die Antwort ist Name Expr( ). Name Expr ist eine JSL-Funktion, die normalerweise verwendet wird, um einen Ausdruck aus einer JSL-Variablen abzurufen, ohne ihn auszuwerten. Als äußerster Wrapper in einem Formelbefehl gibt er lediglich das Argument zurück, ohne es auszuwerten. Das erste Beispiel könnte es ohne guten Grund außer dieser Erklärung wie folgt verwenden, um genau dieselbe Tabelle zurückzugeben:
New Table( "abc", Add Rows( 2 ),
New Column( "a", Numeric, "Continuous",Format( "Best", 12 ),Set Values( [1, 7] )),
New Column( "b",Numeric,"Continuous",Format( "Best", 12 ),Set Values( [2, 9] )),
New Column( "c", Numeric, "Continuous", Format( "Best", 12 ),
Formula( Name Expr( :a + :p</img> ) )
)
)
Aber für MS Es wird beispielsweise wegen der cleveren Verwendung von eval benötigt (was wahrscheinlich einen anderen Blog-Beitrag benötigt, um zu erklären, was es tut). Hier ist die Abschlusstabelle der ursprünglichen Frage. Ich habe meine eigene Idee als zweite Formelspalte hinzugefügt.
New Table( "final?",Add Rows( 9 ),
New Column( "color",Character,"Nominal",
Set Values({"green", "green", "blue", "yellow", "red", "red", "yellow", "green", "green"})),
New Column( "count",Numeric,"Continuous",Format( "Best", 12 ),
Formula( Name Expr( Eval( Eval Expr( Col Sum( Row() <= Expr( Row() ), :color ) ) ) ) )),
New Column( "another count",Numeric,"Continuous",Format( "Best", 12 ),
Formula(
n = 0;
For( i = 1, i <= Row(), i++,
If( :color == :color[i], n++ )
);
n;
)
)
);
Die Formel der dritten Spalte könnte auf Kosten der Klarheit schneller sein, indem sie auf die letzte Übereinstimmung zurückblickt und dieser Zahl eins hinzufügt. Klarheit vs. Effizienz ist ein Kompromiss.

Also mache ich mich daran, den in diesem Prozess entdeckten Fehler zu beheben: Wenn eine Datentabelle ein Skript erstellt, um sich selbst zu reproduzieren (wie im oberen Beispiel), muss sie JSL erstellen, um auch die Spaltenformeln zu reproduzieren. Wenn die Spaltenformel mit dem speziellen eval( )-Wrapper beginnt und die Auswertung Teil der Formel sein soll, muss JMP den Namensausdruck hinzufügen.
Update 21. April 2018: Reparieren Sie die automatische Konvertierung aus dem vorherigen Blog.