我正在嘗試找到一種有效的方法來計算滾動 3 天累積總和。
我有一些有效的 for 循環,但我正在處理的數據集大約有 500k 行,其中有更多的 GROUPS、SUBGROUPS 和 VALUE 列,因此計算需要大約 30 分鐘。 示例數據集非常精簡且基礎。
我將這些值移入矩陣中,這加快了速度,但還不夠。
有一個 GROUP 和 SUBGROUP 列,它們是彼此分開的 CUMULATIVE SUM。 此外,對於每一行,CUMULATIVESUM 只能是 DATE - 3 天。 :DATE[]-3 天之前和 :DATE[] 之後的任何內容都不會用於該行的 CUMULATIVE SUM。
我有一種感覺,使用 LAG 的列公式可能是最快的,但我無法讓它正常工作。
速度非常重要。
我嘗試過對錶進行子集化,但這只會使其速度變慢。
參見表和 JSL。 前兩個 JSL 方法工作正常,第三個 JSL 方法無法正常工作。
謝謝你!
[編輯] 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
);
接得好。 我犯了一個菜鳥錯誤,沒有抓住 1 行子組的極端情況。 我很高興 JMP 不再將 1x1 矩陣轉換為標量。
<SPAN class="token comment">//JMP12 converted a 1x1 matrix to a scalar</SPAN>
這很好用。 我發現在我的數據集上使用此方法速度提高了 200% 以上。
如果子組只有一行(您有關於將 1x1 矩陣轉換為標量的 JSL 註釋),則會出現一個小錯誤。 我不知道為什麼會發生這種情況。
我確保這些將保持矩陣:
dsub = Matrix(dmat[b :: e]);
vsub = Matrix(vmat[b :: e]);
這應該會快一點。 這是一個簡單的偏移計數例程,它取決於 Loc() 和矩陣函數的強大功能。
注意事項:
- 更改路徑或user_id或set dt =當前數據表();
- 創建一個常量,例如博士發現幾天內(3)一次可能節省查找50萬次。這取決於 JMP 如何優化/解析 JSL 代碼。
- 在腳本的第 30 行,我使用了<= 博士以便該腳本的結果與您的結果相匹配。但是,請考慮這是否應該是嚴格小於 (<)。 表中的第 37 行匯總了 1 月 19 日到 1 月 22 日的第 33-37 行,即 4 天。 還有其他例子。 假設您想要 1 月的最後 30 天,即 1 月 2 日到 1 月 31 日。
- :日期格式為 m/d/y,但日期值包含時間。 如果您想按日曆日(而不是時間)滾動,請註釋掉第 30 行並取消註釋第 31 行。值 86400 = 24*60*60 或幾天內(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>不知道這樣速度是更快還是更慢,但對於我這個缺乏經驗的腳本編寫者來說,這種方法比較容易理解。
假設表格按 GROUP、SUBGROUP 和日期排序,並且 3 天內資料點永遠不會超過 10 個(您可以更改此值),則此公式可以解決問題。
求和(i = 0, 10,
如果( :GROUP == Lag( :GROUP, i ) & :SUBGROUP == Lag( :SUBGROUP, i ) & Date Difference( Lag( :DATE, i ), :DATE, "Day" ) <= 3,
Lag( :VALUE, i ),
0
)
)
乾杯