How can one drop/delete columns from a KDB table in place? - kdb

Following the documentation, I tried to do the following:
t:([]a:1 2 3;b:4 5 6;c:`d`e`f) // some input table
`a`b _ t // works: delete NOT in place
(enlist `a) _ t // works: delete NOT in place
t _:`a`b // drop columns in place does not work; how to make it to work?
// 'type
// [0] t _:`a`b
Thank you very much for your help!

You should be able to use
delete a,b from `t
to delete in place (The backtick implies in place).
Alternatively, for more flexibility you could use the functional form;
![`t;();0b;`a`b]

The simplest way to achieve column deletion in place is using qSQL:
t:([]a:1 2 3;b:4 5 6;c:`d`e`f)
delete a,b from `t -- here, the backtick before t makes the change in place.
q)t
c
-
d
e
f

Michael & Kyle have covered the q-SQL options; for completeness, here are a couple of other options using _:
Using _ as in your question, you can re-assign this back to t e.g.
t:`a`b _ t
You can also use . amend with an empty list of indexes i.e. "amend entire", which can be done in-place by passing `t or not in-place by passing just t e.g.
q).[t;();`a`b _] / not in-place
c
-
d
e
f
q).[`t;();`a`b _] / in-place
`t
q)t
c
-
d
e
f

Related

Why does 'sum' work but '+/' not work in KDB queries?

Why does sum work here, but the underlying form +/ not work? (Taken from https://code.kx.com/q/ref/sum/)
t: ([]name:`Jack`Jill`Janet;hair:`brown`black`fair;eye:`blue`green`hazel;age:12 9 14)
q)select sum age from t
age
---
35
q)select +/age from j
'/
[0] select +/age from j
^
This is because +/ is k syntax. To invoke it (and similar k constructs) in q you will need to wrap it in parentheses.
select enlist (+/)age from j
In general, if an inbuilt q keyword exists for the associated k expression, you should use the keyword (sum in this case) as it likely carries further optimisations.
In the case of sum q will automatically enlist the result inside a select statement which (+/) won't do. Hence why I have done it manually above. Otherwise expect a 'rank error.

How can I convert this select statement to functional form?

I am having a couple of issues to put this in a functional format.
select from tableName where i=fby[(last;i);([]column_one;column_two)]
This is what I got:
?[tableName;fby;enlist(=;`i;(enlist;last;`i);(+:;(!;enlist`column_one`column_two;(enlist;`column_one;`column_two))));0b;()]
but I get a type error.
Any suggestions?
Consider using the following function, adjust from the buildQuery function given in the whitepaper on Parse Trees. This is a pretty useful tool for quickly developing in q, this version is an improvement on that given in the linked whitepaper, having been extended to handle updates by reference (i.e., update x:3 from `tab)
\c 30 200
tidy:{ssr/[;("\"~~";"~~\"");("";"")] $[","=first x;1_x;x]};
strBrk:{y,(";" sv x),z};
//replace k representation with equivalent q keyword
kreplace:{[x] $[`=qval:.q?x;x;"~~",string[qval],"~~"]};
funcK:{$[0=t:type x;.z.s each x;t<100h;x;kreplace x]};
//replace eg ,`FD`ABC`DEF with "enlist`FD`ABC`DEF"
ereplace:{"~~enlist",(.Q.s1 first x),"~~"};
ereptest:{((0=type x) & (1=count x) & (11=type first x)) | ((11=type x)&(1=count x))};
funcEn:{$[ereptest x;ereplace x;0=type x;.z.s each x;x]};
basic:{tidy .Q.s1 funcK funcEn x};
addbraks:{"(",x,")"};
//where clause needs to be a list of where clauses, so if only one whereclause need to enlist.
stringify:{$[(0=type x) & 1=count x;"enlist ";""],basic x};
//if a dictionary apply to both, keys and values
ab:{$[(0=count x) | -1=type x;.Q.s1 x;99=type x;(addbraks stringify key x),"!",stringify value x;stringify x]};
inner:{[x]
idxs:2 3 4 5 6 inter ainds:til count x;
x:#[x;idxs;'[ab;eval]];
if[6 in idxs;x[6]:ssr/[;("hopen";"hclose");("iasc";"idesc")] x[6]];
//for select statements within select statements
//This line has been adjusted
x[1]:$[-11=type x 1;x 1;$[11h=type x 1;[idxs,:1;"`",string first x 1];[idxs,:1;.z.s x 1]]];
x:#[x;ainds except idxs;string];
x[0],strBrk[1_x;"[";"]"]
};
buildSelect:{[x]
inner parse x
};
We can use this to create the functional query that will work
q)n:1000
q)tab:([]sym:n?`3;col1:n?100.0;col2:n?10.0)
q)buildSelect "select from tab where i=fby[(last;i);([]col1;col2)]"
"?[tab;enlist (=;`i;(fby;(enlist;last;`i);(flip;(lsq;enlist`col1`col2;(enlist;`col1;`col2)))));0b;()]"
So we have the following as the functional form
?[tab;enlist (=;`i;(fby;(enlist;last;`i);(flip;(lsq;enlist`col1`col2;(enlist;`col1;`col2)))));0b;()]
// Applying this
q)?[tab;enlist (=;`i;(fby;(enlist;last;`i);(flip;(lsq;enlist`col1`col2;(enlist;`col1;`col2)))));0b;()]
sym col1 col2
----------------------
bah 18.70281 3.927524
jjb 35.95293 5.170911
ihm 48.09078 5.159796
...
Glad you were able to fix your problem with converting your query to functional form.
Generally it is the case that when you use parse with a fby in your statement, q will convert this function into its k definition. Usually you should just be able to replace this k code with the q function itself (i.e. change (k){stuff} to fby) and this should run properly when turning the query into functional form.
Additionally, if you check out https://code.kx.com/v2/wp/parse-trees/ it goes into more detail about parse trees and functional form. Additionally, it contains a script called buildQuery which will return the functional form of the query of interest as a string which can be quite handy and save time when a functional form is complex.
I actually got it myself ->
?[tableName;((=;`i;(fby;(enlist;last;`i);(+:;(!;enlist`column_one`column_two;(enlist;`column_one;`column_two)))));(in;`venue;enlist`venueone`venuetwo));0b;()]
The issues was a () missing from the statement. Works fine now.
**if someone wants to add a more detailed explanation on how manual parse trees are built and how the generic (k){} function can be replaced with the actual function in q feel free to add your answer and I'll accept and upvote it

pythonic way to delete edge attributes

In order to remove attributes from a networkx graph I have the following code:
for (n1,n2) in graph.edges(data=False):
for att in att_list:
graph[n1][n2].pop(att, None)
Is there a more pythonic way to do so?
If you only want to delete a few attributes in some list, say att_list
for n1, n2, d in graph.edges(data=True):
for att in att_list:
d.pop(att, None)
Or you can replace the last line with if att in d: del d[att] if it bothers you that pop returns something that you aren't using. The improvement compared to your code is that by having data=True I get d immediately, rather than having to reference graph[n1][n1] later.
See Removing multiple keys from a dictionary safely for how to remove multiple keys from a dictionary (which is what d is). Fundamentally that's what your problem reduces to once you've got d.
Alternately, if you want to clear all of the attributes, then note that if we set data=True, then graph.edges also returns a dictionary with the attributes. Clear this dictionary.
for (n1, n2, d) in graph.edges(data=True):
d.clear()
Here's a complete example
import networkx as nx
G=nx.Graph()
G.add_edge(1,2,weight=2)
G.edge[1][2]
> {'weight': 5}
for (n1, n2, d) in G.edges(data=True):
d.clear()
G.edge[1][2]
> {}
#just to check the edge in the opposite order
G.edge[2][1]
> {}

kdb apply function in select by row

I have a table
t: flip `S`V ! ((`$"|A|B|"; `$"|B|C|D|"; `$"|B|"); 1 2 3)
and some dicts
t1: 4 10 15 20 ! 1 2 3 5;
t2: 4 10 15 20 ! 0.5 2 4 5;
Now I need to add a column with values on the the substrings in S and the function below (which is a bit pseudocode because I am stuck here).
f:{[s;v];
if[`A in "|" vs string s; t:t1;];
else if[`B in "|" vs string s; t:t2;];
k: asc key t;
:t k k binr v;
}
problems are that s and v are passed in as full column vectors when I do something like
update l:f[S,V] from t;
How can I make this an operation that works by row?
How can I make this a vectorized function?
Thanks
You will want to use the each-both adverb to apply a function over two columns by row.
In your case:
update l:f'[S;V] from t;
To help with your pseudocode function, you might want to use $, the if-else operator, e.g.
f:{[s;v]
t:$["A"in ls:"|"vs string s;t1;"B"in ls;t2;()!()];
k:asc key t;
:t k k binr v;
};
You've not mentioned a final else clause in your pseudocode but $ expects one hence the empty dictionary at the end.
Also note that in your table the columns S and V have been cast to a symbol. vs expects a string to split so I've had to use the stringoperation - this could be removed if you are able to redefine your original table.
Hope this helps!

How to remove element from list in KDB?

For instance, I have:
x: (`a`b!(1;2); (); `a`b!(3;4))
and I want to remove the (). I have tried using ? (match)
x[x ? not ()]
but that just gives ().
What is the correct expression?
Background
I often use peach to execute a series of queries, and often some will return missing data in the form of (). Hence I want to remove the () and get back to a nice table.
Well, if you are returning tables already (rather than dictionaries), you could always just raze and that would be enough to get rid of the empty list. Technically, it is appended, but if you append an empty list on a list, you get the original list. Recall that a table is simply a list of dictionaries, so this remains the case here as well.
//I'm enlisting your dictionaries,
//so that they become tables and then raze
q)raze #[x; 0 2; enlist]
a b
---
1 2
3 4
Snippets such as raze f each x or raze f peach x are very common, and I suspect this is the idiom that would be best for your use case.
You can use except as well:
q)x except 1#()
a b
---
1 2
3 4
() is an empty list. So it has count of zero. Therefore we can use:
q)x where not 0 = count each x
a b
---
1 2
3 4
A slight more generic way to get rid of unwanted elements :
q)x where not x~\:()
a b
---
1 2
3 4
q)x where not x~\:`a`b!(1;2)
()
`a`b!3 4