kdb — KDB Применить логику там, где существует столбец — проверка данных

#kdb

#kdb

Вопрос:

Я пытаюсь выполнить некоторую простую логику в таблице, но я хотел бы убедиться, что столбцы существуют, прежде чем делать это в качестве шага проверки. Мои данные состоят из стандартных имен таблиц, хотя они не всегда присутствуют в каждом источнике данных.

Хотя следующее, похоже, работает (в настоящее время просто проверяет AAA) Мне нужно расширить, чтобы убедиться, что PRI_AAA (и, в конечном итоге, многие другие переменные) также присутствуют.

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

Вопрос из двух частей

  1. Это кажется довольно утомительным для каждой переменной (представьте AAA-ZZZ входные данные и их производные). Есть ли умный способ использовать словарь (или таблицу), чтобы узнать, существует ли количество переменных, или вставить столбец с нулями, если они этого не делают?

  2. Аналогично, можем ли мы сохранить формулу или инструкции для применения в словаре (или таблице) для проверки и возврата вычисления (т. Е. BBB_VAL: BBB*BBB_PRICE .) Некоторые вычисления будут зависеть от других (например, BBB_Tax_Basis = BBB_VAL - BBB_COSTS затрат, поэтому могут возникнуть итеративные проблемы.

Заранее благодарю!

Ответ №1:

Функциональное обновление может быть лучшим способом достижения этой цели, если вы намерены обновить многие столбцы таблицы аналогичным образом.

 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
  

Комментарии:

1. Еще раз спасибо Cathal….at в настоящее время я пишу вложенные условные выражения, чтобы проверить и посмотреть, существуют ли обе переменные, и, хотя это работает, это довольно утомительно и возвращает таблицу t , если какая-либо из переменных не существует: t: $[ AAA в столбцах t; $[ AAA_PRICE в столбцах t; t: update AAA_Revenue: AAA_Revenue (AAA*AAA_PRICE) from t; t];t]; для каждой переменной. Единственное, что меня беспокоит, это зависимые вычисления, хотя я предполагаю, что каждая функция и словарь могут быть дискретными (т. Е. Налоговый словарь зависит от словаря доходов и т. Д.) Еще раз спасибо, я собираюсь протестировать это сегодня утром!

Ответ №2:

Вот еще один подход, который обрабатывает зависимые / каскадные вычисления, а также определяет, какие вычисления возможны или нет, в зависимости от доступных столбцов в таблице.

 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))
 );
  

Комментарии:

1. Спасибо, Терри, мне нужно разобраться с этой функцией. Я все еще не совсем понимаю синтаксис q. Я полагаю, вы понимаете мою цель. Этот map словарь может стать довольно большим, но преимуществом будет единый репозиторий для этих базовых расчетов денежных потоков. Для справки, у меня есть ~ 100 строк вложенных условных обновлений для более чем 6,5 мм записей и занимает ~ 1000 мс. Я протестирую сегодня и сообщу, смогу ли я заставить все это работать. ** РЕДАКТИРОВАТЬ ** — Я также не использую никаких глобальных переменных

2. ОК. Смотрите мое дополнительное редактирование выше относительно большого количества сопоставлений

3. О, здорово, это значительно упростит сборку!

4. Хороший материал. Рекурсивная .z.s логика сканирует карту на наличие вложенных сопоставлений, а затем заменяет их базовыми вычислениями, пока все на карте не будет записано в терминах базовых вычислений для фактических / существующих столбцов таблицы.

5. Посмотрите, как parse считывает его и работает с этим : 0N!parse"select totalR:AAA BBB CCC DDD EEE from tab"; . В этом случае вложенных сумм вы можете сгенерировать вложение, используя что-то вроде (1#`TotalRevenue)!enlist{( ;y;x)}/[reverse`AAA`BBB`CCC`DDD`EEE]