Was um alles in der Welt macht die Funktion?
Wisst Ihr was? Ich arbeite mit (und lehre) Tableau seit über 5 Jahren, und ratet mal, wann ich diese Funktion endlich verstanden habe… Das war gestern. Und lasst uns eine Sache direkt aus der Welt schaffen: Wenn Ihr die vorigen Werte anzeigen wollt, ignoriert PREVIOUS_VALUE, denn das ist die eine Sache, die sie nicht kann. (Um die jeweilig vorigen Werte zu zeigen, benutzt lieber die LOOKUP Funktion, mit einem Offset von -1, das reicht schon aus.)
Also, was macht die Funktion dann? Es gibt keinen besseren Weg etwas zu lernen, als es zu lehren, drum gibt es hier einen neuen Blog-Artikel, der den 5-Jahre-Lernpfad auf 15 Minuten reduziert.
Drei fundamentale Prinzipien
Bereit? Tauchen wir direkt ein und machen die langweilige Theorie am Anfang (so dass wir sie nicht später hervorkramen müssen, wenn es spannend wird):
Lektion #1: Selbst-bezogen
PREVIOUS_VALUE ist eine selbst-bezogene Funktion (self-referring im Englischen). Und als sie vor langer Zeit eingeführt wurde, war sie vermutlich der feuchte Tableau-Traum von allen, die sich in rekursive Funktionen und Loops in anderen Tools oder Sprachen verliebt hatten.
Selbst-bezogen? Rekursiv? Wovon redest Du da?
Es klingt weitaus komplizierter als es ist. Und weil ein Bild mehr als tausend Worte sagt, schauen wir uns einmal diese vier kleinen Tabellen an, in denen die ersten zwei Spalten in einer dritten berechnet werden. Daneben sehen wir die Berechnung. Und während die blauen zur Linken einfach geradeaus für jede Zeile separat berechnet werden, sind die roten zur Rechten etwas anders:
Auf der rechten Seite addieren wir die vorigen Ergebnisse zu jeder Zeile hinzu. Das gibt uns die laufende Summe und ist bereits ziemlich nah an dem dran, was wir mit Tableau machen wollen.
Euch fallen vielleicht die zwei grauen Nullen in den rechten Charts auf. Behaltet diese im Gedächtnis!
Lektion #2: Es ist eine Tabellenberechnung
Das ist sehr wichtig, da die PREVIOUS_VALUE-Funktion weder eine aggregierte Funktion noch eine Row-Level-Funktion ist.
Wenn wir diese Funktion in Excel replizieren, brauchen wir nicht weit zu denken. In dem unteren rechten Chart (im Bild oben) enthält die Zelle C5 zum Beispiel folgende einfache Formel: =C4+A5*B5. In Excel ziehen wir diese Formel einfach runter oder hoch und wir bekommen, was wir wollen, ohne komplexe Funktionen.
Aber denkt daran: Tableau ist kein zellen-basiertes Tool wie Excel, es ist tabellen-basiert. Was auch immer wir mit einer Zelle einer Spalte machen, machen wir mit allen Zellen dieser Spalte. Natürlich, Berechnungen, Filter, Gruppen, Sätze (Sets) und all die anderen geliebten Gimmicks in Tableau versorgen uns mit den Möglichkeiten, die wir brauchen. Dennoch, Tableau arbeitet mit der kompletten Spalte in der Berechnung, nicht nur mit einzelnen Zellen. Das heißt, wir müssen den Umfang und die Richtung unserer Tabellenberechnung bedenken, wenn wir sie in unsere Ansicht einbauen.
Das heißt auch, dass wir ein Problem haben, wenn Tableau versucht die allererste Zeile unserer Partition zu berechnen, denn die hat keinen vorigen Wert. Das wiederum bringt uns zu:
Lektion #3: Zwei Syntax-Mysterien
Die Syntax unserer Funktion ist ziemlich einfach:
PREVIOUS_VALUE(Ausdruck)
Zwei Dinge: Zunächst etwas Wichtiges, das uns die Syntax vorenthält, und dann der Ausdruck ( expression im Englischen).
Was enthält sie uns vor?
Die Funktion PREVIOUS_VALUE alleine mit sich selbst ist mehr oder weniger sinnlos, solange wir keine Mathematik betreiben wollen (was natürlich in Ordnung wäre). Sie funktioniert – strenggenommen – aber es gibt keinen Wert in den Daten, ziemlich wörtlich sogar. Wie wir bereits klargestellt haben, ist diese Funktion selbst-bezogen, wenn wir ihr also Arbeit geben möchten, müssen wir sie mehr wie ihre eigene Metrik behandeln, als wie eine Funktion, und sie in der Berechnung, die wir vor unserem geistigen Auge sehen, mit den üblichen Operatoren mit den Daten verbinden, für die wir die Funktion verwenden wollen.
Ahm… bitte was?
Okay, okay, das war kryptisch, aber im Grunde heißt das nur: Schiebt eine Kennzahl in Euer berechnetes Feld, so dass die Funktion etwas zum Arbeiten hat. Ihr wollt die laufende Summe für die [Sales]-Metrik? Lasst die Funktion damit arbeiten:
PREVIOUS_VALUE(0) + SUM([Sales])
Das heißt übersetzt: Liebe Funktion, bitte summiere [Sales] für diese Zeile und addiere, was Du in der vorigen Zeile berechnet hast.
Okay, aber ich kriegs noch nicht ganz zusammen. Was ist dieser Ausdruck genau? Warum steht da eine 0 und nicht die Summe von Sales?
Dieser Ausdruck trieb mich in den Wahnsinn über so viele Jahre. Kurz und knapp: Er ist kein Argument. Wenn wir die vorigen Werte für die Summe von Sales haben wollen, funktioniert PREVIOUS_VALUE(SUM([Sales])) nicht, obwohl das ziemlich intuitiv aussieht. Versteht mich nicht falsch – die Syntax ist okay, es wird keine Fehlermeldung geben. Aber wir kriegen nicht, was wir wollen. Also, was ist dieser Ausdruck?
Er ist der Startpunkt unserer PREVIOUS_VALUE Funktion – in Anbetracht der Tatsache, dass es für die allererste Zeile keinen vorigen Wert geben kann. Das ist all die Magie, die es hier gibt. Nicht mehr, nicht weniger. Er berechnet nichts, Er holt sich keine Kennzahlen oder Dimensionen um damit zu arbeiten, er definiert bloß, mit was die Funktion ihre Reise antritt. Der initiale Wert. Erinnert Ihr Euch an die grauen Nullen in unserem Chart oben?
In Excel oder Google Spreadsheets lösen wir das ziemlich einfach. Wir löschen einfach den Bezug zu der unmöglichen Zeile 0, die vor Zeile 1 kommen müsste. In C2 steht zum Beispiel die Formel =C1+A2+B2. Aber für C1 wurde sie einfach zu =A1+B1 und alles ist in Ordnung.
In Tableau sind wir tabellen-basiert unterwegs und können eine spezielle Zelle nicht verändern. Glücklicherweise ist der Ausdruck unser Ausweg. Die Null ist unser Startpunkt. (Zumindest, wenn wir laufende Summen bauen.) Wenn die Funktion ihre Arbeit aufnimmt, startet sie bei 0.
Oder in anderen Worten: Liebe Funktion, bitte summiere [Sales] für diese Zeile und addiere, was Du in der vorigen Zeile berechnet hast. Oh, und wenn Du gerade erst anfängst, tu bitte so, als hättest Du in der vorigen Zeile eine 0 berechnet.
Übungszeit!
Wenn sich das alles noch etwas abstrakt anhört, keine Sorge, gleich wird alles etwas klarer. Behalte nur diese 3 Dinge im Kopf, die wir eben gelernt haben:
- #1: PREVIOUS_VALUE ist selbst-bezogen.
- #2: Es ist eine Tabellenberechnung.
- #3: Wir müssen der Funktion Arbeit geben und der Ausdruck ist der Startpunkt dieser Arbeit.
Nun, Ärmel hochgekrempelt: Zunächst, kopiert die folgende Tabelle und fügt sie in ein leeres Tableau-Sheet ein:
Year , Ones , Sequential , Currency ($)
2009 , 1 , 1 , 100
2010 , 1 , 2 , 250
2011 , 1 , 3 , 1100
2012 , 1 , 4 , 55
2013 , 1 , 5 , 2010
2014 , 1 , 6 , 1500
2015 , 1 , 7 , 125
2016 , 1 , 8 , 246
2017 , 1 , 9 , 2123
2018 , 1 , 10 , 1234
2019 , 1 , 11 , 500
2020 , 1 , 12 , 500
2021 , 1 , 13 , 600
2022 , 1 , 14 , 860
2023 , 1 , 15 , 440
Dann, rechtsklickt auf den Sheet-Reiter und dupliziert es als Kreuztabelle. Filtert die NULL-Werte heraus.
Schließlich: Erstellt ein berechnetes Feld (“previous value”) das Folgendes enthält und zieht dieses neue Feld in den Container Kennzahlwerte:
PREVIOUS_VALUE(0) + SUM([Ones])
Spielt ein bisschen damit herum, ändert den Ausdruck der Funktion, nutzt sie in anderen berechneten Feldern – es gibt kein richtig und falsch, nur schlauer werden.
Und jetzt, Fragestunde!
Ich habe eine 200 in die Funktion als Ausdruck eingetragen. Das beeinflusst nur den allerersten Wert der Funktion, richtig?
Der Ausdruck definiert, wo PREVIOUS_VALUE ihre Arbeit aufnimmt, ja. Oder in anderen Worten: Tu so, als gäbe es eine geheime Zeile in unserer Tabelle für das Jahr 2008, und das dieses Feld dort einen Wert von 200 hat. Für die tatsächliche erste Zeile nimmer PREVIOUS_VALUE dann diese 200 und addiert eine 1 (die aus dem Feld [Ones] kommt.)
Was genau passiert, wenn ich verschiedene Kennzahlen in die Berechnung einfüge? Denn das scheint zu funktionieren…
Das tut es! Die Berechnung folgt den üblichen Regeln von berechneten Feldern. Innerhalb Deines Felds (das eine Tabellenberechnung ist), behandle die PREVIOUS_VALUE-Funktion wie ein anderes Feld in Deinem Kopf. Im Grunde tut sie nichts anderes als die vorigen Ergebnisse des ganzen berechneten Felds zu holen und dann damit zu rechnen, ganz so, wie Du das definierst.
In Deinem Fall holt sie sich die 0 aus dem Ausdruck, addiert eine 1 aus dem Feld [Ones] und zieht eine 1 aus dem Feld [Sequential] in der ersten Zeile ab. Für das Jahr 2020 zum Beispiel holt sie sich -55 aus dem Vorjahr, addiert eine 1 und subtrahiert eine 12, womit sie bei -66 ankommt.
Ich habe ein Feld als Ausdruck eingefügt – was passiert hier?
Wenn Du die Summe von [Currency ($)] als Ausdruck in die Funktion einfügst, sagst Du PREVIOUS_VALUE, dass sie in die erste Zeile des Felds Currency ($) schauen und dessen Wert als Startpunkt nehmen soll. Sie nimmt 100 von dort, addiert eine 1 von [Ones] und gibt 101 als Ergebnis für die erste Zeile aus. Da es der Startwert ist, kann er nicht aus mehreren Werten bestehen. Nur der allererste Wert der Partition ist der eine, den PREVIOUS_VALUE nimmt. Fühlt sich etwas beliebig an, aber so ist es nun mal.
Heißt das, ich kann sogar Berechnungen als Ausdruck vorgeben? Ich probiere das mal…
… Sieht so aus!
Ja! Perfekt. So lang diese Berechnung nur einen Wert ausgibt, ist alles in Ordnung.
Nur so aus Neugierde: Warum ZEIGT PREVIOUS_VALUE die vorigen Werte nicht in der Spalte?
Gute Frage! Irgendwie ist der Name dieser Funktion etwas irreführend. Sie arbeitet mit all diesen vorigen Werten, aber sie zeigt sie nicht. Ein akkuraterer Name wäre ALL_PREVIOUS_VALUES. Der einfachste Weg die vorigen Werte zu zeigen wäre ein LOOKUP-Konstrukt: LOOKUP(SUM([Currency ($)]), -1) (Das ist auch eine Tabellenberechnung, also achtet darauf, in welche Richtung sie sich berechnet.)
Die allererste Zeile wird einen NULL-Wert zurückgeben, da es keine 2008-Zeile gibt, aus der die Funktion einen Wert ziehen könnte.
Du sagtest, PREVIOUS_VALUE ohne eine Kennzahl ist sinnlos, solange ich kein Mathe damit machen möchte. Was meintest Du damit?
Die Funktion selbst ist selbst-bezogen. Deshalb arbeitet sie ohne einen externen Wert (wie die Currency-Kennzahl vorhin) nur mit sich selbst und allem, was die Mathematik zu bieten hat (was eine Menge ist). In diesem Bezug unterscheidet sie sich nicht von anderen Funktionen. SUM(5 + 6) ergibt 11. Das ist korrekt, aber da ist kein wirklicher Datenwert drin.
Aber während andere Funktionen Argumente brauchen, die sie berechnen können, ist PREVIOUS_VALUE mehr oder weniger ihr eigenes Argument, und einfach nur Kennzahlen in die Funktion einzufügen (auch berechnete) führt zu keinem neuen Datenwert, außer, dass der Startwert für jede Zeile repliziert wird (hier mit 5 multipliziert):
Warum macht sie das?
Nun, ich habe der Funktion nicht gesagt, dass sie überhaupt etwas tun soll, außer, welchen Startwert sie nutzen soll. Heißt, sie holt sich stets den vorigen Wert, der jedes Mal 5 ist.
Aber in dem Moment, in dem wir buchstäblich irgendetwas mit PREVIOUS_VALUE berechnen, wird die Mathematik dahinter sehr mächtig und das sehr schnell. Zum Beispiel:
Hm…, wenn ich das versuche, bekomme ich eine 2 für jede Zeile.
Klingt, als ob horizontal berechnet wird statt vertikal. Prüfe die Richtung Deiner Tabellenberechnung. Wir haben alle anderen Felder aus der Berechnung entfernt, drum weiß Tableau möglicherweise nicht, wie berechnet werden soll. Stell sicher, dass die Berechnung auf Tabelle (vertikal) oder Year gestellt ist. Das sollte funktionieren.
Oh, also kann ich auch Produkte hier nutzen?
Ja. Im Sinne von mathematischen Operationen könnt Ihr nutzen, was immer Ihr mögt, solang es sich an die Regeln der Mathematik hält. Vergesst nicht, trotz unserer Lektionen am Anfang ist diese Funktion im Grunde recht simpel: Sie nimmt nur den Wert der vorigen Zeile und macht damit, was immer wir Ihr auftragen. Produkte nutzen führt zu laufenden Produkten statt laufenden Summen. Das ist ziemlich mächtig, mit oder ohne Datenfelder, da es keine RUNNING_PRODUCT Funktion in Tableau gibt (Stand: Tableau 2020.4). Übrigens: Das gilt auch für Differenzen und Divisionen.
Moment, heißt das, ich könnte hier auch Zinsen damit berechnen, richtig?
Du meinst, wie viel Geld zu hättest, nachdem Du es seit 2009 in einem Banktresor aufbewahrst? Logo!
Angefangen bei 1.000 $ in 2009, nachdem Du einen Zinssatz von 1,5% ausgehandelt hast. Spiel einfach ein wenig mit diesem Konstrukt herum.
Das ist echt cool. Und ich habe damit herumgespielt. Ich denke, ich würde gerne nur die Zinsen sehen, nicht den ganzen Geldbetrag. Aber die 1.000 $ abzuziehen funktioniert nicht. Wie mache ich das?
Ja, hier kommen wir an eine Grenze von PREVIOUS_VALUE. Das können wir nicht innerhalb unseres berechneten Feldes erledigen. Du wirst vermutlich sowas bekommen haben:
Das sieht sehr falsch aus, denn die 1.000 wird nicht einmal, sondern von jeder einzelnen Zeile abgezogen, wieder und wieder (das haben wir dem Feld auch so befohlen). Um zu bekommen, was wir wollen, bräuchten wir ein weiteres berechnetes Feld, in dem wir die 1.000 von unserem ersten Feld abziehen. (Einfach so: [previous value] – 1000)
Funktioniert PREVIOUS_VALUE auch mit Text? Komische Frage, ich weiß…
Berechtigte Frage. Und die Antwort ist ja. Der Wert muss nicht numerisch sein, Integers sind lediglich der voreingestellte Datentyp der Funktion. Wie auch immer, mit Text sind wir einer Menge Einschränkungen unterworfen, denn all der coole Mathe-Kram ist nicht möglich. Nichtsdestotrotz, die Syntax ändert sich nicht. Lasst uns ein Textfeld heraufbeschwören, indem wir die Jahreszahlen in unserer Tabelle in Buchstaben umwandeln. Dafür brauchen wir nur ein weiteres berechnetes Feld mit dem Inhalt: CHAR(INT(RIGHT(STR([Year]), 2)) + 88)
Jetzt können wir dieses neue Textfeld auf Zeilen ziehen und wir sollten die Buchstaben a, b, c bis o neben unseren Jahren finden.
Und lasst uns noch ein weiteres berechnetes Feld für unsere PREVIOUS_VALUE Funktion erstellen, diesmal mit Text:
Es funktioniert! Wie Ihr vielleicht seht, gibt es 2 Unterschiede: Erstens: Ich habe keine Zahl als Startwert (oder Ausdruck) unserer Funktion genutzt, sondern Anführungsstriche, die der Funktion erklären, dass sie mit Text arbeitet. Und zweitens: Ich habe das Textfeld in eine ATTR-Funktion eingerahmt. Das ist notwendig, da die Tabellenberechnung aggregierte Werte braucht und die Attribut-Funktion das für Textfelder emuliert.
Ein weiteres Beispiel:
Und funktioniert sie auch mit Datumsfeldern?
Probierts aus! Jetzt wisst Ihr, wie die Funktion arbeitet, wie der Startwert festgelegt wird und wie alles in einem berechneten Feld aussieht. Der Rest ist Trial-&-Error.
Großartig! Das wars für heute!
Wir sind in die Theorie hinter PREVIOUS_VALUE eingetaucht, haben 3 wertvolle Lektionen über die Funktion gelernt und haben eine Menge Praxisbeispiele durchgemacht. Wenn Ihr noch weitere Fragen habt oder noch immer mit der Funktion kämpft, schreibt mir gern.