在KDB中如何计算列表中每个元素的前3个(或n个)元素之和?大内存受限列表的优雅实现方案
KDB+ 列表求和问题解决方案
来,咱们一个个拆解你提出的两个KDB+需求:
问题1:对列表中的前3个数字求和
这个需求很直接,有两种常用写法,取决于你对“不足3个元素”场景的处理逻辑:
如果列表长度不足3时,只对现有元素求和:用
first取前3个元素再求和,或者用take函数,效果完全一致:// 示例列表 myList: 1 2 3 4 5 sum first 3 myList // 结果:6(1+2+3) sum take[3; myList] // 和上面等价要是列表只有2个元素,比如
myList:10 20,这两个写法都会返回30,不会额外补值。如果要求必须凑够3个元素,不足补默认值:用
#(take的简写)操作符,KDB+会自动用对应类型的默认值补全(整数补0,浮点数补0n等):sum 3#10 20 // 结果:30(10+20+0)
问题2:滚动计算每个元素对应的前n个元素之和(适配大列表内存受限场景)
这个需求的核心是滚动窗口求和,要兼顾优雅和内存效率,首推用KDB+内置的wsum(加权求和)函数——它是底层优化的向量操作,不会生成中间嵌套列表,内存占用极低,完美适配大列表场景。
核心思路
wsum的原理是用权重向量和目标列表做卷积,我们只需要把权重向量设为n#1f(n个1的浮点数列表),就能实现每个位置的前n个元素(包括当前元素)的滚动求和。
代码示例
针对你给出的列表j,计算每个元素对应的前3个元素之和:
j: (til 40)*9 0 9 18 27 36 45 54 63 72 81 90 99 108 117 126 135 144 153 162 171 180 189 198 207 216 225 234 243 252 261 270 279 288 297 306 315 324 333 342 351 // 前3个元素滚动求和 rollingSum3: wsum[3#1f; j]
如果要适配任意n值,直接替换权重向量的长度即可:
n:5 rollingSumN: wsum[n#1f; j]
为什么这个方法最优?
对比直观但内存低效的写法sum each 0N 3#j:
0N 3#j会生成一个嵌套列表,每个子列表是窗口内的元素,内存占用是O(n*k)(n是列表长度,k是窗口大小),大列表下会直接吃满内存;wsum是向量级别的操作,全程只生成一个结果列表,内存占用是O(n),而且底层用C实现,速度快得多。
特殊场景:前n个元素不包含当前元素
如果你的需求是“每个元素的前n个之前的元素之和”(比如第i个元素的和是i-n到i-1的元素),可以通过给原列表补前缀的方式实现:
// 前3个元素(不包含当前)的滚动求和 rollingSumPrev3: 1_ wsum[3#1f; 0,0,j] // 补两个0前缀,然后去掉第一个结果
内容的提问来源于stack exchange,提问作者cjm2671
相关产品推荐
相关产品推荐

