Ich versuche, einen effizienten Weg zur Berechnung der gleitenden 3-Tage-KUMULATIVSUMME zu finden.
Ich habe einige for-Schleifen, die funktionieren, aber die Datensätze, mit denen ich arbeite, umfassen etwa 500.000 Zeilen mit viel mehr GRUPPEN-, UNTERGRUPPEN- und VALUE-Spalten, sodass die Berechnung etwa 30 Minuten dauert. Der Beispieldatensatz ist sehr reduziert und einfach.
Ich habe die Werte in eine Matrix verschoben und das beschleunigt es ein wenig, aber nicht genug.
Es gibt eine GROUP- und eine SUBGROUP-Spalte, die getrennt voneinander KUMULATIV SUMMEN sollen. Außerdem kann die CUMULATIVESUM für jede Zeile nur für DATUM – 3 Tage gelten. Alles vor :DATE[]-3 Tagen und nach :DATE[] wird nicht für die KUMULATIVSUMME dieser Zeile verwendet.
Ich habe das Gefühl, dass eine Spaltenformel mit LAG wahrscheinlich am schnellsten ist, aber ich kann sie nicht richtig zum Laufen bringen.
Geschwindigkeit ist sehr wichtig.
Ich habe versucht, die Tabellen in Teilmengen aufzuteilen, aber das hat es nur langsamer gemacht.
Siehe Tabelle und JSL. Die beiden oberen JSL-Methoden funktionieren einwandfrei, die dritte JSL-Methode funktioniert nicht richtig.
Danke schön!
[Bearbeiten] JMP Pro 12.2.0

dt = Current Data Table();
For( i = 1, i <= N Rows( dt ), i = i + 1,
:CUMULATIVE_SUM_VALUE[i] = :VALUE[i];
For( c = i - 1, c > 0, c = c - 1,
If( :SUBGROUP[c] == :SUBGROUP[i] & :GROUP[c] == :GROUP[i] & (:DATE[i] - :DATE[c]) <= In Days( 3 ),
:CUMULATIVE_SUM_VALUE[i] = :CUMULATIVE_SUM_VALUE[i] + :VALUE[c],
c = -1
)
);
);
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
//1=GROUP, 2=SUBGROUP, 3=DATE, 4=VALUE, 5=CUMULATIVE_SUM_VALUE
TT = dt << Get All Columns As Matrix;
For( i = 1, i <= N Rows( TT ), i = i + 1,
TT[i, 5] = TT[i, 4];
For( c = i - 1, c > 0, c = c - 1,
If( TT[c, 2] == TT[i, 2] & TT[c, 1] == TT[i, 1] & (TT[i, 3] - TT[c, 3]) <= In Days( 3 ),
TT[i, 5] = TT[i, 5] + TT[c, 4],
c = -1
)
);
);
For Each Row( :CUMULATIVE_SUM_VALUE = TT[Row(), 5] );
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
dt << New Column( "CUMULATIVE_SUM_VALUE_2",
Formula(
//:VALUE;
If(
Row() == 1, :VALUE,
:GROUP == Lag( :GROUP, 1 ) & :SUBGROUP == Lag( :SUBGROUP, 1 ) & :DATE - Lag( :DATE, 1 ) <= In Days( 3 ), :VALUE + Lag( :CUMULATIVE_SUM_VALUE, 1 )
,
:GROUP != Lag( :GROUP, 1 ) & :SUBGROUP != Lag( :SUBGROUP, 1 ) & :DATE - Lag( :DATE, 1 ) <= In Days( 3 ), :VALUE
,
:GROUP == Lag( :GROUP, 1 ) & :SUBGROUP == Lag( :SUBGROUP, 1 ) & :DATE - Lag( :DATE, 1 ) > In Days( 3 ), :VALUE
,
:GROUP != Lag( :GROUP, 1 ) | :SUBGROUP != Lag( :SUBGROUP, 1 ), :VALUE
)
),
Eval Formula
);
Guter Fang. Ich habe einen Anfängerfehler gemacht, indem ich den Eckfall für eine einreihige Untergruppe nicht erwischt habe. Ich bin so froh, dass JMP eine 1x1-Matrix nicht mehr in einen Skalar umwandelt.
<SPAN class="token comment">//JMP12 converted a 1x1 matrix to a scalar</SPAN>
Das funktioniert großartig. Mit dieser Methode erkenne ich bei meinem Datensatz eine Geschwindigkeitssteigerung von >200 %.
Es gab einen kleinen Fehler, wenn es nur eine Zeile für eine Untergruppe gab (Sie hatten einen JSL-Kommentar zu einer 1x1-Matrix in einen Skalar konvertiert). Ich habe keine Ahnung, warum das passieren würde.
Ich habe dafür gesorgt, dass diese wie folgt eine Matrix bleiben:
dsub = Matrix(dmat[b :: e]);
vsub = Matrix(vmat[b :: e]);
Das dürfte etwas schneller gehen. Es handelt sich um eine einfache Offset-Zählroutine, die von der Leistungsfähigkeit der Loc()- und Matrixfunktionen abhängt.
Zu beachtende Punkte:
- Ändern Sie den Pfad oder die Benutzer-ID oder setzen Sie dt = current data table();
- Erstellen eines konstanten Likes drng findet In Tagen (3) Einmal möglicherweise 500.000 Mal sparen.Dies hängt davon ab, wie JMP JSL-Code optimiert/analysiert.
- In Zeile 30 des Skripts habe ich verwendet <= drng damit die Ergebnisse dieses Skripts mit Ihren Ergebnissen übereinstimmen.Überlegen Sie jedoch, ob dies ein strikter Kleiner-als-Wert (<) sein sollte. Zeile 37 in Ihrer Tabelle summiert die Zeilen 33–37 vom 19. Januar bis 22. Januar, also 4 Tage. Es gibt noch andere Fälle. Angenommen, Sie möchten die letzten 30 Tage im Januar, das müsste der 2. Januar bis 31. Januar sein.
- :Datum ist im Format m/d/y formatiert, der Datumswert enthält jedoch auch die Uhrzeit. Wenn Sie nach Kalendertag (nicht nach Uhrzeit) scrollen möchten, kommentieren Sie Zeile 30 aus und kommentieren Sie Zeile 31 aus.Der Wert 86400 = 24*60*60 oder In Tagen (1)
Names Default to Here(1);
dt = Open("c:\users\<USER_ID>\downloads\cumulative_sum_test_table.jmp");
//This assumes the data table is soted by Group and SubGroup and Date
scol = dt << new column("Sequence", numeric, continuous);
scol << set each value(Row());
ccol = dt << new Column("CUMULATIVE_SUM_VALUE_2", numeric, continuous);
summarize(Data Table(dt), _ttt = By(:GROUP, :SUBGROUP), _ibeg=Min(scol), _iend=Max(scol) );
dt << delete column(scol); //no longer needed
dmat = :DATE << get as matrix;
vmat = :VALUE << get as matrix;
//for each group
drng = In Days(3); //259200
For(i=1, i<=nitems(_ttt[1]), i++,
b = _ibeg[i];
e = _iend[i];
dsub = dmat[ b::e ];
vsub = vmat[ b::e ];
For(j = b, j <= e, j++,
//j=37
k= j-b+1;
//JMP12 converted a 1x1 matrix to a scalar
if(k==1,
ccol[j] = vsub[1]
, //else
idx = loc( 0<= -1 * dsub[1::k] + dmat[j] <= drng ); //should this be < not <=<BR /> //idx = loc( 0<= Floor( (-1 * dsub[1::k] + dmat[j])/86400) <= 3 ); // < ??
ccol[j] = sum(vsub[idx])
); //end if
); // end for j
);
</USER_ID>Ich habe keine Ahnung, ob das schneller oder langsamer wäre, aber für mich als unerfahrenen Skripter war es viel einfacher zu konzipieren.
Unter der Annahme, dass die Tabelle nach GRUPPE, UNTERGRUPPE und Datum sortiert ist und dass Sie in einem 3-Tage-Zeitraum nie mehr als 10 Datenpunkte haben (dies können Sie ändern), würde diese Formel den gewünschten Effekt erzielen.
Summation( i = 0, 10,
Wenn( :GROUP == Lag( :GROUP, i ) & :SUBGROUP == Lag( :SUBGROUP, i ) & Date Difference( Lag( :DATE, i ), :DATE, "Day" ) <= 3,
Lag( :VALUE, i ),
0
)
)
Prost