kdb - KDB 在列存在的地方应用逻辑 - 数据验证

kdb - KDB Apply logic where column exists - data validation

我正在尝试对 table 执行一些简单的逻辑,但我想在执行此操作之前验证列是否存在作为验证步骤。我的数据由标准 table 名称组成,尽管它们并不总是出现在每个数据源中。

虽然以下内容似乎有效(目前只是验证 AAA),但我需要扩展以确保 PRI_AAA(以及最终许多其他变量)也存在。

t: $[`AAA in cols `t; temp: update AAA_VAL: AAA*AAA_PRICE from t;()]

两部分问题

  1. 这对于每个变量来说似乎都很乏味(想象一下 AAA-ZZZ 输入及其导数)。有没有一种巧妙的方法来利用字典(或 table)来查看是否存在多个变量,或者如果不存在则插入一个零占位符列?

  2. 类似地,我们可以存储一个公式或指令以在字典(或 table)中应用以验证和 return 计算(即 BBB_VAL: BBB*BBB_PRICE .) 一些计算将依赖于其他计算(例如 BBB_Tax_Basis = BBB_VAL - BBB_COSTS 成本,因此可能存在迭代问题。

提前致谢!

如果您打算以类似方式更新 table 的许多列,功能更新可能是实现此目的的最佳方式。

func:{[t;x]
  if[not x in cols t;t:![t;();0b;(enlist x)!enlist 0]];
  :$[x in cols t;
    ![t;();0b;(enlist`$string[x],"_VAL")!enlist(*;x;`$string[x],"_PRICE")];
    t;
   ];
 };

此函数将为您作为参数传递的任何列更新 t*_VAL 列,同时首先还会为作为参数传递的任何缺失列添加一个零列。

q)t:([]AAA:10?100;BBB:10?100;CCC:10?100;AAA_PRICE:10*10?10;BBB_PRICE:10*10?10;CCC_PRICE:10*10?10;DDD_PRICE:10*10?10)
q)func/[t;`AAA`BBB`CCC`DDD]
AAA BBB CCC AAA_PRICE BBB_PRICE CCC_PRICE DDD_PRICE AAA_VAL BBB_VAL CCC_VAL DDD DDD_VAL
---------------------------------------------------------------------------------------
70  28  89  10        90        0         0         700     2520    0       0   0
39  17  97  50        90        40        10        1950    1530    3880    0   0
76  11  11  0         0         50        10        0       0       550     0   0
26  55  99  20        60        80        90        520     3300    7920    0   0
91  51  3   30        20        0         60        2730    1020    0       0   0
83  81  7   70        60        40        90        5810    4860    280     0   0
76  68  98  40        80        90        70        3040    5440    8820    0   0
88  96  30  70        0         80        80        6160    0       2400    0   0
4   61  2   70        90        0         40        280     5490    0       0   0
56  70  15  0         50        30        30        0       3500    450     0   0

正如您已经提到的,要涵盖第 2 点,函数字典可能是最好的方法。

q)dict:raze{(enlist`$string[x],"_VAL")!enlist(*;x;`$string[x],"_PRICE")}each`AAA`BBB`DDD
q)dict
AAA_VAL| * `AAA `AAA_PRICE
BBB_VAL| * `BBB `BBB_PRICE
DDD_VAL| * `DDD `DDD_PRICE

然后稍微修改一下函数...

func:{[dict;t;x]
  if[not x in cols t;t:![t;();0b;(enlist x)!enlist 0]];
  :$[x in cols t;
    ![t;();0b;(enlist`$string[x],"_VAL")!enlist(dict`$string[x],"_VAL")];
    t;
   ];
 };

产生类似的结果。

q)func[dict]/[t;`AAA`BBB`DDD]
AAA BBB CCC AAA_PRICE BBB_PRICE CCC_PRICE DDD_PRICE AAA_VAL BBB_VAL DDD DDD_VAL
-------------------------------------------------------------------------------
70  28  89  10        90        0         0         700     2520    0   0
39  17  97  50        90        40        10        1950    1530    0   0
76  11  11  0         0         50        10        0       0       0   0
26  55  99  20        60        80        90        520     3300    0   0
91  51  3   30        20        0         60        2730    1020    0   0
83  81  7   70        60        40        90        5810    4860    0   0
76  68  98  40        80        90        70        3040    5440    0   0
88  96  30  70        0         80        80        6160    0       0   0
4   61  2   70        90        0         40        280     5490    0   0
56  70  15  0         50        30        30        0       3500    0   0

这是另一种处理 dependent/cascading 计算的方法,它还根据 table.

中的可用列确定哪些计算是可能的,哪些计算是不可能的
q)show map:`AAA_VAL`BBB_VAL`AAA_RevenueP`AAA_RevenueM`BBB_Other!((*;`AAA;`AAA_PRICE);(*;`BBB;`BBB_PRICE);(+;`AAA_Revenue;`AAA_VAL);(%;`AAA_RevenueP;1e6);(reciprocal;`BBB_VAL));
AAA_VAL     | (*;`AAA;`AAA_PRICE)
BBB_VAL     | (*;`BBB;`BBB_PRICE)
AAA_RevenueP| (+;`AAA_Revenue;`AAA_VAL)
AAA_RevenueM| (%;`AAA_RevenueP;1000000f)
BBB_Other   | (%:;`BBB_VAL)

func:{c:{$[0h=type y;.z.s[x]each y;-11h<>type y;y;y in key x;.z.s[x]each x y;y]}[y]''[y];
    ![x;();0b;where[{all in[;cols x]r where -11h=type each r:(raze/)y}[x]each c]#c]};

q)t:([] AAA:1 2 3;AAA_PRICE:1 2 3f;AAA_Revenue:10 20 30;BBB:4 5 6);  
q)func[t;map]
AAA AAA_PRICE AAA_Revenue BBB AAA_VAL AAA_RevenueP AAA_RevenueM
---------------------------------------------------------------
1   1         10          4   1       11           1.1e-05
2   2         20          5   4       24           2.4e-05
3   3         30          6   9       39           3.9e-05


/if the right columns are there
q)t:([] AAA:1 2 3;AAA_PRICE:1 2 3f;AAA_Revenue:10 20 30;BBB:4 5 6;BBB_PRICE:4 5 6f);
q)func[t;map]
AAA AAA_PRICE AAA_Revenue BBB BBB_PRICE AAA_VAL BBB_VAL AAA_RevenueP AAA_RevenueM BBB_Other
--------------------------------------------------------------------------------------------
1   1         10          4   4         1       16      11           1.1e-05      0.0625
2   2         20          5   5         4       25      24           2.4e-05      0.04
3   3         30          6   6         9       36      39           3.9e-05      0.02777778

唯一需要注意的是,您的地图不能具有与地图的键和值相同的列名,也就是不能重复使用列名。并且假设地图中的所有符号都是列名(不是全局变量),尽管它可以扩展以涵盖

编辑:如果您有大量列图,那么以更垂直的方式定义它会更容易,如下所示:

map:(!). flip(
 (`AAA_VAL;     (*;`AAA;`AAA_PRICE));
 (`BBB_VAL;     (*;`BBB;`BBB_PRICE));
 (`AAA_RevenueP;(+;`AAA_Revenue;`AAA_VAL));
 (`AAA_RevenueM;(%;`AAA_RevenueP;1e6));
 (`BBB_Other;   (reciprocal;`BBB_VAL))
 );