KDB中前N天的总和值?

时间:2019-07-15 06:19:55

标签: kdb

我有一个包含以下两列的表:

初始表

Date        Value
-------------------
2019.01.01 | 150  
2019.01.02 | 100  
2019.01.04 | 200  
2019.01.07 | 300  
2019.01.08 | 100  
2019.01.10 | 150  
2019.01.14 | 200  
2019.01.15 | 100  

对于每行,我想对前N天的值求和。在这种情况下,N = 5。

结果表

Date        Value  Sum
------------------------
2019.01.01 | 150 | 150 (01 -> ..)
2019.01.02 | 100 | 250 (02 -> 01)
2019.01.04 | 200 | 450 (04 -> 01)
2019.01.07 | 300 | 600 (07 -> 02)
2019.01.08 | 100 | 600 (08 -> 04)
2019.01.10 | 150 | 550 (10 -> 07)
2019.01.14 | 200 | 350 (14 -> 10)
2019.01.15 | 100 | 450 (15 -> 10)

查询

t:([] Date: 2019.01.01 2019.01.02 2019.01.04 2019.01.07 2019.01.08 2019.01.10 2019.01.14 2019.01.15; Value: 150 100 200 300 100 150 200 100)

我该怎么做?

4 个答案:

答案 0 :(得分:8)

一种解决方法是使用如下所示的更新语句:

q)N:5
q)update Sum:sum each Value where each Date within/:flip(Date-N;Date)from t
Date       Value Sum
--------------------
2019.01.01 150   150
2019.01.02 100   250
2019.01.04 200   450
2019.01.07 300   600
2019.01.08 100   600
2019.01.10 150   550
2019.01.14 200   350
2019.01.15 100   450

inside关键字检查“日期”列中的每个日期是否在当前日期和当前日期-N的窗口之内,而每个权利都可以。

q)flip(-5+t`Date;t`Date)
2018.12.27 2019.01.01
2018.12.28 2019.01.02
2018.12.30 2019.01.04
2019.01.02 2019.01.07
2019.01.03 2019.01.08
2019.01.05 2019.01.10
2019.01.09 2019.01.14
2019.01.10 2019.01.15
q)t[`Date]within/:flip(-5+t`Date;t`Date)
10000000b
11000000b
11100000b
01110000b
00111000b
00011100b
00000110b
00000111b

这将返回一个布尔列表的列表,可以使用where each将其转换为索引(每个自其列表列表以来),然后再索引回Value。

q)where each t[`Date]within/:flip(-5+t`Date;t`Date)
,0
0 1
0 1 2
1 2 3
2 3 4
3 4 5
5 6
5 6 7
q)t[`Value]where each t[`Date]within/:flip(-5+t`Date;t`Date)
,150
150 100
150 100 200
100 200 300
200 300 100
300 100 150
150 200
150 200 100

然后使用sum each可以对每个数字列表求和以获得所需的结果。

q)sum each t[`Value]where each t[`Date]within/:flip(-5+t`Date;t`Date)
150 250 450 600 600 550 350 450

答案 1 :(得分:3)

您也可以使用以下更新语句来实现此目的。它不需要翻转,因此执行速度应该更快。

q)N:5
q)delete s from update runningSum:s-0^s[Date bin neg[1]+Date-N] from update s:sums Value from t
Date       Value runningSum
---------------------------
2019.01.01 150   150
2019.01.02 100   250
2019.01.04 200   450
2019.01.07 300   600
2019.01.08 100   600
2019.01.10 150   550
2019.01.14 200   350
2019.01.15 100   450

使用“值”列上的sums,然后使用bin查找N天前的运行计数。 然后,delete关键字会删除“求和值”列以获得所需的结果

q)\t:1000 delete s from update runningSum:s-0^s[Date bin neg[1]+Date-N] from update s:sums Value from t
7

尽管对于较小的N值,对于较大的值(例如,N),此答案与Elliot的时间差可以忽略不计。 1000,速度更快

q)\t:1000 update Sum:sum each Value where each Date within/:flip(Date-1000;Date)from t
11
q)\t:1000 delete s from update runningSum:s-0^s[Date bin neg[1]+Date-1000] from update s:sums Value from t
7

应该注意,此答案要求对日期字段进行排序,而Elliot则不需要。

另一种稍慢的方法是为介于最小日期和最大日期之间的所有日期生成0值。 然后可以使用移动总和msums来获取过去5天的值。

它首先从表中获取minmax日期,并列出它们之间的日期列表。

q)update t: 0^Value from ([]Date:{[x]  x[0]+til 1+x[1]-x[0]} exec (min[Date], max Date) from t) lj `Date xkey t
Date       Value t
--------------------
2019.01.01 150   150
2019.01.02 100   100
2019.01.03       0
2019.01.04 200   200
2019.01.05       0
2019.01.06       0
2019.01.07 300   300
2019.01.08 100   100
2019.01.09       0
2019.01.10 150   150

然后将它们添加到表中并填写空值。考虑到所有丢失的数据,这将仅在前N天有效

q){[x] select from x where not null Value } update t: 5 msum 0^Value from ([]Date:{[x]  x[0]+til 1+x[1]-x[0]} exec (min[Date], max Date) from t) lj `Date xkey t
Date       Value t
--------------------
2019.01.01 150   150
2019.01.02 100   250
2019.01.04 200   450
2019.01.07 300   500
2019.01.08 100   600
2019.01.10 150   550
2019.01.14 200   350
2019.01.15 100   300

在将“值”用作列名时,我也要小心,因为您可能会遇到value关键字的问题

我希望这能回答您的问题

答案 2 :(得分:2)

在这里很自然地适合使用窗口连接。参见:https://code.kx.com/v2/ref/wj/

q)wj1[-5 0+\:t`Date;`Date;t;(t;(sum;`Value))]
Date       Value
----------------
2019.01.01 150
2019.01.02 250
2019.01.04 450
2019.01.07 600
2019.01.08 600
2019.01.10 550
2019.01.14 350
2019.01.15 450

要返回5个观察结果而不是5个日历日,您可以这样做:

q)wj1[{(4 xprev x;x)}t`Date;`Date;t;(t;(sum;`Value))]
Date       Value
----------------
2019.01.01 150
2019.01.02 250
2019.01.04 450
2019.01.07 750
2019.01.08 850
2019.01.10 850
2019.01.14 950
2019.01.15 850

答案 3 :(得分:1)

您可以使用移动窗口mwin函数来实现此目的:

mwin:{[f;w;l] f each {1_x,y}\[w#0n;`float$l]}

然后您可以将函数f设置为sum,并在过去w:5天内获得所需的值l列表(此处为{{1 }}):

l:exec Value from t