【问题标题】:(q/kdb+) Update rows using results from previous rows(q/kdb+) 使用前一行的结果更新行
【发布时间】:2018-09-05 23:38:26
【问题描述】:

使用表格

t:([]c1: 3 4 7 2 4.0;c2: 2 8 10 1 9.0;c3:5 8 13 2 11.0)

c1  c2  c3
3   2   5
4   8   8
7   10  13
2   1   2
4   9   11

我需要更新 3 个新列 (c1M,c2M,c3M) 其中:

  • 第一行:

    • c1M:avg(c1,c2,c3)
    • c2M:avg(c1,c2)
    • c3M:c3
  • 其他行:

    • c1M:avg(c1,c2,c3)
    • c2M:avg(prev c1M,prev c2M)
    • c3M:max(c3,c1M,c2M)

我可以使用第一行

t:update c1M:avg(c1,c2,c3),c2M:avg(c1,c2),c3M:c3 from t where i=0

c1  c2  c3  c1M c2M c3M
3   2   5   3.3 2.5 5
4   8   8   0n  0n  0N
7   10  13  0n  0n  0N
2   1   2   0n  0n  0N
4   9   11  0n  0n  0N

不知道如何艰难地前进。我试过类似的东西:

update c1M:avg(c1;c2;c3),c2M:avg(prev c1M;prev c2M),c3M:c3|c1M|c2M from t where i>0

但没有运气。

这个例子的结果应该是:

c1  c2  c3  c1M c2M c3M
3   2   5   3.3 2.5 5.0
4   8   8   6.7 2.9 8.0
7   10  13  10  4.8 13.0
2   1   2   1.7 7.4 7.4
4   9   11  8.0 4.5 11.0

有人可以帮我吗?

【问题讨论】:

    标签: kdb


    【解决方案1】:

    KDB+ 在矢量计算方面比在迭代方面要快得多。因此,一种可能更快的方法是使用副词仅遍历 c2M 列,因为它是唯一需要列中前一个值的方法。 我认为您可能正在寻找的是:

    update c3M:c3 from (update c3M:max(c3;c1M;c2M) from update c2M:{avg x,y}\[first 
    c2;first[c1],1_prev c1M] from update c1M:avg(c1;c2;c3) from t) where i=0
    

    这比在整个表上迭代和执行计算运行得更快,如下所示:

    q)\ts:1000 ({update c3M:max(c3;c1M;c2M),c2M:c2M^avg(prev c1M;prev 
    c2M),c1M:c1M^avg(c1;c2;c3) from x}/)[update 
    c1M:avg(c1,c2,c3),c2M:avg(c1,c2),c3M:c3 from t where i=0]
    53 7568
    
    q)\ts:1000 update c3M:c3 from (update c3M:max(c3;c1M;c2M) from update c2M: 
    {avg x,y}\[first c2;first[c1],1_prev c1M] from update c1M:avg(c1;c2;c3) from 
    t) where i=0
    11 6896
    

    【讨论】:

      【解决方案2】:

      我想你在这里寻找的已经结束了: http://code.kx.com/q/ref/adverbs/#over

      它将遍历表格的每一行

      q)({update c3M:max(c3;c1M;c2M),c2M:c2M^avg(prev c1M;prev c2M),c1M:c1M^avg(c1;c2;c3) from x}/)[update c1M:avg(c1,c2,c3),c2M:avg(c1,c2),c3M:c3 from t where i=0] 
      c1 c2 c3 c1M c2M c3M
      --------------------
      3  2  5  3.3 2.5 5  
      4  8  8  6.7 2.9 8  
      7  10 13 10  4.8 13 
      2  1  2  1.7 7.4 7.4
      4  9  11 8   4.5 11     
      

      【讨论】:

      • ^的使用是什么意思?是返回值本身吗?
      • ^ 是填充,它将用 c2M 替换空的 avg(prev c1M;prev c2M) 值,例如:code.kx.com/q/ref/lists/#fill
      【解决方案3】:
      q) nt:update c1m:avg(c1;c2;c3) from t 
      q) nt:update c2m:-1_({avg x,y}\[avg[c1[0],c2[0]],c1m]) from nt
      q) nt:update c3m:(c3[0],1_max(c3;c1m;c2m)) from nt
      

      【讨论】:

        【解决方案4】:

        另一种方法,可能不是最快的,但代码占用空间更小

        q){y,`c1M`c2M`c3M!a,max y[`c3],a:(avg y;avg y[`c1`c2]^x`c1M`c2M)}\[t@-1;t]
        c1 c2 c3 c1M      c2M      c3M
        -----------------------------------
        3  2  5  3.333333 2.5      5
        4  8  8  6.666667 2.916667 8
        7  10 13 10       4.791667 13
        2  1  2  1.666667 7.395833 7.395833
        4  9  11 8        4.53125  11
        

        【讨论】:

        • 你能快速解释一下结构吗?
        • 它将一个空白行作为种子 (t@-1) - 这允许修改第一次运行的行为,因为初始逻辑不同 - 并扫描 t 的每一行。函数内部x 表示之前创建的行(或第一次运行时的空白),y 表示 c1、c2 和 c3 的下一行。然后您可以执行必要的逻辑来获取平均值和最大值,并将 c1M、c2M 和 c3M 附加到 c1、c2 和 c3。这个结果作为新的x 传递回函数,直到处理所有y(即来自 t 的所有行)
        • 哦,值得一提的是,函数的输入和输出都是字典,所以由于所有输出字典都符合相同的形状,kdb 会自动转换为表(表是字典的列表)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多