KDB - 时态函数结果成为后续行函数的输入
KDB - Temporal function results become input for function on subsequent row
我一直在与 KDB 合作,从一组表示模型分段函数的输入中创建时态数据。我面临的挑战是,对于一个特定的 ID,有几个片段,其中第一个片段的时间结果的最后一个值成为(但不总是)后续片段的输入。
//Create sample table
t:([id:`AAA`AAA`AAA`BBB`CCC`CCC;seg:1 2 3 1 1 2];aa: 1500 0n 0n 40 900 0N;bb:150 200 30 40 10 15;cc: .40 .25 .35 .5 .35 .45; Fname:`Fx`Fy`Fy`Fy`Fz`Fz);
下面的简单虚拟函数return5个数据周期但实际上每个函数可以return几千个数据点
//Dummy functions to generate temporal data
Fx:{[aa;bb;cc] (aa%bb)*(1-exp(neg cc*1+til 5))*100};
Fy:{[aa;bb;cc] (aa%cc)*(1*(1-exp(neg cc*1+til 5)))};
Fz:{[aa;bb;cc] (aa%bb)*(1-exp(neg cc*1+til 5))};
当我 运行 每个函数的结果时,我们可以看到我们在几个片段上缺少 aa 的地方。 aa 应该是前一段(即 aa = 864.6647 for AAA seg 2
和 aa= 74.36035f for CCC seg 2)
的前一个(最后一个 t[result])
show update result:first[Call_Function]'[aa;bb;cc] by Call_Function from t
id seg| aa bb cc Fname result
-------| ----------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 200 0.25 Fy
AAA 3 | 30 0.35 Fy
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 15 0.45 Fz
我试过尝试引用之前的片段 prev(last(t[result])
但列表结果没有参考意义。同样,我知道 / (over)
迭代器会很有用,但我一直没有成功实现它。
我考虑将其分解为几个步骤(所有片段 1,然后是片段 2,依此类推),然后将它们全部附加到最后的 table。同样,我想跟踪每个段的累积值和时间计数(时间)以作为限制器传递给函数,因此成功引用前一行有多种用途。
最终,一旦填充,我将取消 table 的分组,将其放入类似于下面的输出中,然后我可以根据需要重新排序。
q)show ungroup t
id seg aa bb cc Fname result
------------------------------------
AAA 1 1500 150 0.4 Fx 329.68
AAA 1 1500 150 0.4 Fx 550.671
AAA 1 1500 150 0.4 Fx 698.8058
AAA 1 1500 150 0.4 Fx 798.1035
AAA 1 1500 150 0.4 Fx 864.6647
AAA 2 200 0.25 Fy
AAA 2 200 0.25 Fy
AAA 2 200 0.25 Fy
AAA 2 200 0.25 Fy
AAA 2 200 0.25 Fy
AAA 3 30 0.35 Fy
AAA 3 30 0.35 Fy
AAA 3 30 0.35 Fy
AAA 3 30 0.35 Fy
AAA 3 30 0.35 Fy
BBB 1 40 40 0.5 Fy 31.47755
BBB 1 40 40 0.5 Fy 50.56964
BBB 1 40 40 0.5 Fy 62.14959
BBB 1 40 40 0.5 Fy 69.17318
BBB 1 40 40 0.5 Fy 73.4332
TL;DR 我认为以下是您想要的:
q)t:update result:count[t]#enlist`float$() from t; // table extended to already contain a results column
q)applyF:{[t] update result:first[Fname]'[aa;bb;cc] by Fname from t where not null aa, 0=count each result} //applies each Fname function when needed
q)updateA:{[t]update aa:prev[last each result]^aa by id from t}; // updates column aa based on previous results
q)myUpd:updateA applyF ::; // helper function applying the two above
q)ungroup myUpd over t;
id seg aa bb cc Fname result
----------------------------------------
AAA 1 1500 150 0.4 Fx 329.68
AAA 1 1500 150 0.4 Fx 550.671
AAA 1 1500 150 0.4 Fx 698.8058
AAA 1 1500 150 0.4 Fx 798.1035
AAA 1 1500 150 0.4 Fx 864.6647
AAA 2 864.6647 200 0.25 Fy 765.0526
AAA 2 864.6647 200 0.25 Fy 1360.876
AAA 2 864.6647 200 0.25 Fy 1824.904
AAA 2 864.6647 200 0.25 Fy 2186.289
AAA 2 864.6647 200 0.25 Fy 2467.737
AAA 3 2467.737 30 0.35 Fy 2082.149
AAA 3 2467.737 30 0.35 Fy 3549.414
AAA 3 2467.737 30 0.35 Fy 4583.378
AAA 3 2467.737 30 0.35 Fy 5312.001
AAA 3 2467.737 30 0.35 Fy 5825.452
BBB 1 40 40 0.5 Fy 31.47755
BBB 1 40 40 0.5 Fy 50.56964
BBB 1 40 40 0.5 Fy 62.14959
BBB 1 40 40 0.5 Fy 69.17318
BBB 1 40 40 0.5 Fy 73.4332
CCC 1 900 10 0.35 Fz 26.57807
CCC 1 900 10 0.35 Fz 45.30732
CCC 1 900 10 0.35 Fz 58.5056
CCC 1 900 10 0.35 Fz 67.80627
CCC 1 900 10 0.35 Fz 74.36035
CCC 2 74.36035 15 0.45 Fz 1.796406
CCC 2 74.36035 15 0.45 Fz 2.941846
CCC 2 74.36035 15 0.45 Fz 3.67221
CCC 2 74.36035 15 0.45 Fz 4.137911
CCC 2 74.36035 15 0.45 Fz 4.434855
现在进行解释,希望不要太冗长。
我将在这里做几个假设:
- 只有第
aa
列会有空值
- 对于尚未定义
aa
的行,我们可以推迟评估 result
为了方便起见,我启动 t
以便它有一个空的 result
列
q)t:update result:count[t]#enlist`float$() from t;
id seg| aa bb cc Fname result
-------| --------------------------
AAA 1 | 1500 150 0.4 Fx
AAA 2 | 200 0.25 Fy
AAA 3 | 30 0.35 Fy
BBB 1 | 40 40 0.5 Fy
CCC 1 | 900 10 0.35 Fz
CCC 2 | 15 0.45 Fz
并定义一个函数,该函数将为任何已定义 aa
且尚未计算
的行计算 result
q)applyF:{[t] update result:first[Fname]'[aa;bb;cc] by Fname from t where not null aa};
现在生成结果就像调用函数一样简单
q)applyF t;
id seg| aa bb cc Fname result
-------| ---------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 200 0.25 Fy `float$()
AAA 3 | 30 0.35 Fy `float$()
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 15 0.45 Fz `float$()
要从 result
中获取下一个 aa
值,您可以执行类似
的操作
q)update aa:prev[last each result]^aa by id from applyF t;
id seg| aa bb cc Fname result
-------| -------------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 864.6647 200 0.25 Fy `float$()
AAA 3 | 30 0.35 Fy `float$()
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 74.36035 15 0.45 Fz `float$()
我们可以通过编写另一个更新函数来简化 aa
q)updateA:{[t]update aa:prev[last each result]^aa by id from t};
q)updateA applyF t
id seg| aa bb cc Fname result
-------| -------------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 864.6647 200 0.25 Fy `float$()
AAA 3 | 30 0.35 Fy `float$()
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 74.36035 15 0.45 Fz `float$()
现在,为了获得您想要的结果,我们需要一遍又一遍地应用这些更新。您对 over
迭代器的直觉在这里是正确的。此处的用法应用更新,直到 table 停止更改(又名 converge)
q)myUpd:updateA applyF ::; // both update functions combined into one or convenience
q)myUpd over t
id seg| aa bb cc Fname result
-------| --------------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 864.6647 200 0.25 Fy 765.0526 1360.876 1824.904 2186.289 2467.737
AAA 3 | 2467.737 30 0.35 Fy 2082.149 3549.414 4583.378 5312.001 5825.452
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 74.36035 15 0.45 Fz 1.796406 2.941846 3.67221 4.137911 4.434855
q)(myUpd myUpd myUpd t) ~ (myUpd over t)
1b
您可以将 ungroup
应用于上面的结果以获得您想要的输出。
另一种使用 over 的方法:
q)update res:{z .@[y;0;{y^x};last x]}\[0n;flip(aa;bb;cc);Fname] from t
id seg| aa bb cc Fname res
-------| ----------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 200 0.25 Fy 765.0526 1360.876 1824.904 2186.289 2467.737
AAA 3 | 30 0.35 Fy 2082.149 3549.414 4583.378 5312.001 5825.452
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 15 0.45 Fz 1.796406 2.941846 3.67221 4.137911 4.434855
我从你的问题中不清楚的是,是否允许“最后一个值”从一个 ID 溢出到另一个 ID。如果不应该,您可以简单地在我的解决方案中添加一个“by id”
我一直在与 KDB 合作,从一组表示模型分段函数的输入中创建时态数据。我面临的挑战是,对于一个特定的 ID,有几个片段,其中第一个片段的时间结果的最后一个值成为(但不总是)后续片段的输入。
//Create sample table
t:([id:`AAA`AAA`AAA`BBB`CCC`CCC;seg:1 2 3 1 1 2];aa: 1500 0n 0n 40 900 0N;bb:150 200 30 40 10 15;cc: .40 .25 .35 .5 .35 .45; Fname:`Fx`Fy`Fy`Fy`Fz`Fz);
下面的简单虚拟函数return5个数据周期但实际上每个函数可以return几千个数据点
//Dummy functions to generate temporal data
Fx:{[aa;bb;cc] (aa%bb)*(1-exp(neg cc*1+til 5))*100};
Fy:{[aa;bb;cc] (aa%cc)*(1*(1-exp(neg cc*1+til 5)))};
Fz:{[aa;bb;cc] (aa%bb)*(1-exp(neg cc*1+til 5))};
当我 运行 每个函数的结果时,我们可以看到我们在几个片段上缺少 aa 的地方。 aa 应该是前一段(即 aa = 864.6647 for AAA seg 2
和 aa= 74.36035f for CCC seg 2)
show update result:first[Call_Function]'[aa;bb;cc] by Call_Function from t
id seg| aa bb cc Fname result
-------| ----------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 200 0.25 Fy
AAA 3 | 30 0.35 Fy
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 15 0.45 Fz
我试过尝试引用之前的片段 prev(last(t[result])
但列表结果没有参考意义。同样,我知道 / (over)
迭代器会很有用,但我一直没有成功实现它。
我考虑将其分解为几个步骤(所有片段 1,然后是片段 2,依此类推),然后将它们全部附加到最后的 table。同样,我想跟踪每个段的累积值和时间计数(时间)以作为限制器传递给函数,因此成功引用前一行有多种用途。
最终,一旦填充,我将取消 table 的分组,将其放入类似于下面的输出中,然后我可以根据需要重新排序。
q)show ungroup t
id seg aa bb cc Fname result
------------------------------------
AAA 1 1500 150 0.4 Fx 329.68
AAA 1 1500 150 0.4 Fx 550.671
AAA 1 1500 150 0.4 Fx 698.8058
AAA 1 1500 150 0.4 Fx 798.1035
AAA 1 1500 150 0.4 Fx 864.6647
AAA 2 200 0.25 Fy
AAA 2 200 0.25 Fy
AAA 2 200 0.25 Fy
AAA 2 200 0.25 Fy
AAA 2 200 0.25 Fy
AAA 3 30 0.35 Fy
AAA 3 30 0.35 Fy
AAA 3 30 0.35 Fy
AAA 3 30 0.35 Fy
AAA 3 30 0.35 Fy
BBB 1 40 40 0.5 Fy 31.47755
BBB 1 40 40 0.5 Fy 50.56964
BBB 1 40 40 0.5 Fy 62.14959
BBB 1 40 40 0.5 Fy 69.17318
BBB 1 40 40 0.5 Fy 73.4332
TL;DR 我认为以下是您想要的:
q)t:update result:count[t]#enlist`float$() from t; // table extended to already contain a results column
q)applyF:{[t] update result:first[Fname]'[aa;bb;cc] by Fname from t where not null aa, 0=count each result} //applies each Fname function when needed
q)updateA:{[t]update aa:prev[last each result]^aa by id from t}; // updates column aa based on previous results
q)myUpd:updateA applyF ::; // helper function applying the two above
q)ungroup myUpd over t;
id seg aa bb cc Fname result
----------------------------------------
AAA 1 1500 150 0.4 Fx 329.68
AAA 1 1500 150 0.4 Fx 550.671
AAA 1 1500 150 0.4 Fx 698.8058
AAA 1 1500 150 0.4 Fx 798.1035
AAA 1 1500 150 0.4 Fx 864.6647
AAA 2 864.6647 200 0.25 Fy 765.0526
AAA 2 864.6647 200 0.25 Fy 1360.876
AAA 2 864.6647 200 0.25 Fy 1824.904
AAA 2 864.6647 200 0.25 Fy 2186.289
AAA 2 864.6647 200 0.25 Fy 2467.737
AAA 3 2467.737 30 0.35 Fy 2082.149
AAA 3 2467.737 30 0.35 Fy 3549.414
AAA 3 2467.737 30 0.35 Fy 4583.378
AAA 3 2467.737 30 0.35 Fy 5312.001
AAA 3 2467.737 30 0.35 Fy 5825.452
BBB 1 40 40 0.5 Fy 31.47755
BBB 1 40 40 0.5 Fy 50.56964
BBB 1 40 40 0.5 Fy 62.14959
BBB 1 40 40 0.5 Fy 69.17318
BBB 1 40 40 0.5 Fy 73.4332
CCC 1 900 10 0.35 Fz 26.57807
CCC 1 900 10 0.35 Fz 45.30732
CCC 1 900 10 0.35 Fz 58.5056
CCC 1 900 10 0.35 Fz 67.80627
CCC 1 900 10 0.35 Fz 74.36035
CCC 2 74.36035 15 0.45 Fz 1.796406
CCC 2 74.36035 15 0.45 Fz 2.941846
CCC 2 74.36035 15 0.45 Fz 3.67221
CCC 2 74.36035 15 0.45 Fz 4.137911
CCC 2 74.36035 15 0.45 Fz 4.434855
现在进行解释,希望不要太冗长。
我将在这里做几个假设:
- 只有第
aa
列会有空值 - 对于尚未定义
aa
的行,我们可以推迟评估result
为了方便起见,我启动 t
以便它有一个空的 result
列
q)t:update result:count[t]#enlist`float$() from t;
id seg| aa bb cc Fname result
-------| --------------------------
AAA 1 | 1500 150 0.4 Fx
AAA 2 | 200 0.25 Fy
AAA 3 | 30 0.35 Fy
BBB 1 | 40 40 0.5 Fy
CCC 1 | 900 10 0.35 Fz
CCC 2 | 15 0.45 Fz
并定义一个函数,该函数将为任何已定义 aa
且尚未计算
result
q)applyF:{[t] update result:first[Fname]'[aa;bb;cc] by Fname from t where not null aa};
现在生成结果就像调用函数一样简单
q)applyF t;
id seg| aa bb cc Fname result
-------| ---------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 200 0.25 Fy `float$()
AAA 3 | 30 0.35 Fy `float$()
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 15 0.45 Fz `float$()
要从 result
中获取下一个 aa
值,您可以执行类似
q)update aa:prev[last each result]^aa by id from applyF t;
id seg| aa bb cc Fname result
-------| -------------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 864.6647 200 0.25 Fy `float$()
AAA 3 | 30 0.35 Fy `float$()
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 74.36035 15 0.45 Fz `float$()
我们可以通过编写另一个更新函数来简化 aa
q)updateA:{[t]update aa:prev[last each result]^aa by id from t};
q)updateA applyF t
id seg| aa bb cc Fname result
-------| -------------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 864.6647 200 0.25 Fy `float$()
AAA 3 | 30 0.35 Fy `float$()
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 74.36035 15 0.45 Fz `float$()
现在,为了获得您想要的结果,我们需要一遍又一遍地应用这些更新。您对 over
迭代器的直觉在这里是正确的。此处的用法应用更新,直到 table 停止更改(又名 converge)
q)myUpd:updateA applyF ::; // both update functions combined into one or convenience
q)myUpd over t
id seg| aa bb cc Fname result
-------| --------------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 864.6647 200 0.25 Fy 765.0526 1360.876 1824.904 2186.289 2467.737
AAA 3 | 2467.737 30 0.35 Fy 2082.149 3549.414 4583.378 5312.001 5825.452
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 74.36035 15 0.45 Fz 1.796406 2.941846 3.67221 4.137911 4.434855
q)(myUpd myUpd myUpd t) ~ (myUpd over t)
1b
您可以将 ungroup
应用于上面的结果以获得您想要的输出。
另一种使用 over 的方法:
q)update res:{z .@[y;0;{y^x};last x]}\[0n;flip(aa;bb;cc);Fname] from t
id seg| aa bb cc Fname res
-------| ----------------------------------------------------------------
AAA 1 | 1500 150 0.4 Fx 329.68 550.671 698.8058 798.1035 864.6647
AAA 2 | 200 0.25 Fy 765.0526 1360.876 1824.904 2186.289 2467.737
AAA 3 | 30 0.35 Fy 2082.149 3549.414 4583.378 5312.001 5825.452
BBB 1 | 40 40 0.5 Fy 31.47755 50.56964 62.14959 69.17318 73.4332
CCC 1 | 900 10 0.35 Fz 26.57807 45.30732 58.5056 67.80627 74.36035
CCC 2 | 15 0.45 Fz 1.796406 2.941846 3.67221 4.137911 4.434855
我从你的问题中不清楚的是,是否允许“最后一个值”从一个 ID 溢出到另一个 ID。如果不应该,您可以简单地在我的解决方案中添加一个“by id”