Функциональное добавление столбцов в kdb+q

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

Как я могу этого добиться?

Например:

 table:   

 a |  col10  col20 col30 

 1 |    2      3     4
 2 |    5      7     8

 // Assume that I have numbers 10, 20 ,30 obtained from column names

    I want something like **update NewCol:10*col10+20*col20+30*col30 from table**

     except that no.of columns is not fixed so are their inlcluded numbers

person pikachuchameleon    schedule 18.06.2014    source источник


Ответы (4)


Мы хотим использовать функциональное обновление (простой пример показан здесь: http://www.timestored.com/kdb-guides/functional-queries-dynamic-sql#functional-update)

Для этого конкретного запроса мы хотим сгенерировать дерево вычислений предложения select, то есть последней части оператора функционального обновления. Самый простой способ сделать это — проанализировать аналогичный оператор, а затем воссоздать этот формат:

q)/ create our table
q)t:([] c10:1 2 3; c20:10 20 30; c30:7 8 9; c40:0.1*4 5 6)
q)t
c10 c20 c30 c40
---------------
1   10  7   0.4
2   20  8   0.5
3   30  9   0.6

q)parse "update r:(10*c10)+(20*col20)+(30*col30) from t"
!
`t
()
0b
(,`r)!,(+;(*;10;`c10);(+;(*;20;`col20);(*;30;`col30)))
q)/ notice the last value, the parse tree
q)/ we want to recreate that using code
q){(*;x;`$"c",string x)} 10
*
10
`c10
q){(+;x;y)} over {(*;x;`$"c",string x)} each 10 20
+
(*;10;`c10)
(*;20;`c20)
q)makeTree:{{(+;x;y)} over {(*;x;`$"c",string x)} each x}

/ now write as functional update
q)![t;();0b; enlist[`res]!enlist makeTree 10 20 30]
c10 c20 c30 c40 res
-------------------
1   10  7   0.4 420
2   20  8   0.5 660
3   30  9   0.6 900

q)update r:(10*c10)+(20*c20)+(30*c30) from t
c10 c20 c30 c40 r
-------------------
1   10  7   0.4 420
2   20  8   0.5 660
3   30  9   0.6 900
person Ryan Hamilton    schedule 18.06.2014
comment
Привет, я пытался использовать тот же трюк на этом столе. Но все равно показывает ошибку. т:([] а1:1 3;а2:2 4); столбец: a1a2; константа: 1 2; ![t;();0b;зачислить['Новое]! (список +,{(*;x;y)}'[const;col])]. Можете ли вы помочь мне с этим ? - person pikachuchameleon; 18.06.2014

Я думаю, что функциональный выбор (как предложил @Ryan) - это то, что нужно, если таблица довольно общая, т. Е. Имена столбцов могут различаться, а количество столбцов неизвестно.

Тем не менее, я предпочитаю способ, которым @JPC использует вектор для решения задачи умножения и суммирования, то есть update res:sum 10 20 30*(col10;col20;col30) from table

Давайте объединим оба подхода вместе с некоторыми крайними случаями:

q)show t:1!flip(`a,`$((10?2 3 4)?\:.Q.a),'string 10?10)!enlist[til 100],0N 100#1000?10
a | vltg4 pnwz8 mifz5 pesq7 fkcx4 bnkh7 qvdl5 tl5 lr2 lrtd8
--| -------------------------------------------------------
0 | 3     3     0     7     9     5     4     0   0   0
1 | 8     4     0     4     1     6     0     6   1   7
2 | 4     7     3     0     1     0     3     3   6   4
3 | 2     4     2     3     8     2     7     3   1   7
4 | 3     9     1     8     2     1     0     2   0   2
5 | 6     1     4     5     3     0     2     6   4   2
..
q)show n:"I"$string[cols get t]inter\:.Q.n
4 8 5 7 4 7 5 5 2 8i
q)show c:cols get t
`vltg4`pnwz8`mifz5`pesq7`fkcx4`bnkh7`qvdl5`tl5`lr2`lrtd8
q)![t;();0b;enlist[`res]!enlist({sum x*y};n;enlist,c)]
a | vltg4 pnwz8 mifz5 pesq7 fkcx4 bnkh7 qvdl5 tl5 lr2 lrtd8 res
--| -----------------------------------------------------------
0 | 3     3     0     7     9     5     4     0   0   0     176
1 | 8     4     0     4     1     6     0     6   1   7     226
2 | 4     7     3     0     1     0     3     3   6   4     165
3 | 2     4     2     3     8     2     7     3   1   7     225
4 | 3     9     1     8     2     1     0     2   0   2     186
5 | 6     1     4     5     3     0     2     6   4   2     163
..
person WooiKent Lee    schedule 18.06.2014

Вы можете создать запрос функциональной формы, как указал @Ryan Hamilton, и в целом это будет лучший подход, поскольку он очень гибкий. Но если вы просто хотите сложить их, умножив на какой-то вес, я предпочитаю идти другими путями.

РЕДАКТИРОВАТЬ: пропущено, что вы сказали, что число в имени столбца может варьироваться, и в этом случае вы можете легко настроить это. Если все имена столбцов начинаются с одинакового количества букв, просто отбросьте их, а затем проанализируйте оставшиеся в int или что у вас есть. В противном случае, если числа встроены в текст, проверьте этот другой вопрос

//Create our table with a random number of columns (up to 9 value columns) and 1 key column
q)show t:1!flip (`$"c",/:string til n)!flip -1_(n:2+first 1?10) cut neg[100]?100
c0| c1 c2 c3 c4 c5 c6 c7 c8 c9
--| --------------------------
28| 3  18 66 31 25 76 9  44 97
60| 35 63 17 15 26 22 73 7  50
74| 64 51 62 54 1  11 69 32 61
8 | 49 75 68 83 40 80 81 89 67
5 | 4  92 45 39 57 87 16 85 56
48| 88 34 55 21 12 37 53 2  41
86| 52 91 79 33 42 10 98 20 82
30| 71 59 43 58 84 14 27 90 19
72| 0  99 47 38 65 96 29 78 13

q)update res:sum (1+til -1+count cols t)*flip value t from t
c0| c1 c2 c3 c4 c5 c6 c7 c8 c9 res
--| -------------------------------
28| 3  18 66 31 25 76 9  44 97 2230
60| 35 63 17 15 26 22 73 7  50 1551
74| 64 51 62 54 1  11 69 32 61 1927
8 | 49 75 68 83 40 80 81 89 67 3297
5 | 4  92 45 39 57 87 16 85 56 2582
48| 88 34 55 21 12 37 53 2  41 1443
86| 52 91 79 33 42 10 98 20 82 2457
30| 71 59 43 58 84 14 27 90 19 2134
72| 0  99 47 38 65 96 29 78 13 2336

q)![t;();0b; enlist[`res]!enlist makeTree 1+til -1+count cols t] ~ update res:sum (1+til -1+count cols t)*flip value t from t
1b

q)\ts do[`int$1e4;![t;();0b; enlist[`res]!enlist makeTree 1+til 9]]
232 3216j
q)\ts do[`int$1e4;update nc:sum (1+til -1+count cols t)*flip value t from t]
69 2832j

Я не проверял это на большом столе, так что будьте осторожны

person JPC    schedule 18.06.2014

Вот еще одно решение, которое также быстрее.

t,'([]res:(+/)("I"$(string tcols) inter\: .Q.n) *' (value t) tcols:(cols t) except  keys t)

Потратив некоторое время, мы также можем уменьшить количество слов. Логика такая:

a:"I"$(string tcols) inter\: .Q.n

Здесь я сначала извлекаю целые числа из имен столбцов и сохраняю их в векторе. В конце запроса объявляется переменная tcols, которая представляет собой не что иное, как столбцы таблицы, за исключением ключевых столбцов.

b:(value t) tcols:(cols t) except keys t

Здесь я извлекаю каждый вектор-столбец.

c:(+/) a *' b

Умножение каждого вектора-столбца (var b) на его целое число (var a) и добавление соответствующих значений из каждого полученного списка.

t,'([]res:c)

Наконец, сохранение результата во временной таблице и присоединение к t.

person Rahul    schedule 18.06.2014
comment
интересно, я действительно считаю это решение более медленным на моей машине. Я вижу некоторое незначительное замедление, создавая и добавляя temptable по столбцу, а не напрямую обновляя его как новый столбец. Несколько быстрых комментариев: * уже будет атомарным, поэтому нет необходимости в '. (+/) фактически является sum, оба, кажется, выполняют ~ на моей машине. Я вижу, что value flip value keyed_table быстрее, чем (value keyed_table) cols[keyed_table] except keys keyed_table, отличается ли это на вашей машине? - person JPC; 19.06.2014