How would I write a function in q/kdb that computes the value in a vector.
q)l:1 1 1 2 2 2 3 4 1 2 7 6 4
q)where max[a]=a:count each group l
1 2
q)min where max[a]=a:count each group l
1
q)mode:{where max[a]=a:count each group x}
q)min mode l
1
q)mode l
1 2
As you can see above I would just define a mode function and then use min before the function call to return an atom of the lowest value.
Related
How to get sum of eath two elements with the vector functions? I want the same result as:
{x+y}':[1 2 3 2 1]
Why this approach gives something different than first one?
sum':[1 2 3 2 1]
sum is not the same as {x+y}.
sum has rank 1 meaning it takes one input and sums the elements of that input.
It can sum an atom:
q)sum 1
1
a uniform list
q)sum 1 2
3
or a list of lists
q)sum(1 2;3 4)
4 6
{x+y} is rank 2 meaning it requires two inputs.
q){x+y}[1;2]
3
q){x+y}[1 2;3 4]
4 6
Giving it an atom, a single list, or a list of lists leads to projections
q){x+y}1
{x+y}[1]
q){x+y}1 2
{x+y}[1 2]
q){x+y}(1 2;3 4)
{x+y}[(1 2;3 4)]
Since each-prior (':) creates binary pairs from the input and attempts to apply a rank 2 function, it works as intended on your rank 2 function {x+y}.
But since sum is not rank 2 the each-prior doesn't generate pairs in the same way, it's equivalent to doing
q){x}':[1 2 3 2 1]
1 2 3 2 1
q){sum x}':[1 2 3 2 1]
1 2 3 2 1
You could force it to be rank 2:
q){sum(x;y)}':[1 2 3 2 1]
1 3 5 5 3
but this gives a different result since sum ignores nulls while + doesn't.
q)sum(0N;1)
1
q)0N+1
0N
Finally, an alternative way to achieve this using sum (and without using each-prior) is to shift the vector using prev and then sum
q){sum(prev x;x)}[1 2 3 2 1]
0N 3 5 5 3
Given 2 vectors A and B, I want to concatenate each element of A with each element of B. For example if A and B were as follows:
A: 0 1 2
B: 3 4 5
then the output should be (0 3;1 4; 2 5)
Joining the two vectors using the each (each-both in this case) iterator returns your desired output.
q)0N!A,'B
(0 3;1 4;2 5)
0 3
1 4
2 5
You could also instantiate through the following
(A;B) to create a 2x3 matrix which can be flipped to get what you require
q)A:0 1 2
q)B:3 4 5
q)(A;B)
0 1 2
3 4 5
q)flip (A;B)
0 3
1 4
2 5
I'm currently learning kdb+/q.
I have a table of data. I want to take 2 columns of data (just numbers), compare them and create a new Boolean column that will display whether the value in column 1 is greater than or equal to the value in column 2.
I am comfortable using the update command to create a new column, but I don't know how to ensure that it is Boolean, how to compare the values and a method to display the "greater-than-or-equal-to-ness" - is it possible to do a simple Y/N output for that?
Thanks.
/ dummy data
q) show t:([] a:1 2 3; b: 0 2 4)
a b
---
1 0
2 2
3 4
/ add column name 'ge' with value from b>=a
q) update ge:b>=a from t
a b ge
------
1 0 0
2 2 1
3 4 1
Use a vector conditional:
http://code.kx.com/q/ref/lists/#vector-conditional
q)t:([]c1:1 10 7 5 9;c2:8 5 3 4 9)
q)r:update goe:?[c1>=c2;1b;0b] from t
c1 c2 goe
-------------
1 8 0
10 5 1
7 3 1
5 4 1
9 9 1
Use meta to confirm the goe column is of boolean type:
q)meta r
c | t f a
-------| -----
c1 | j
c2 | j
goe | b
The operation <= works well with vectors, but in some cases when a function needs atoms as input for performing an operation, you might want to use ' (each-both operator).
e.g. To compare the length of symbol string with another column value
q)f:{x<=count string y}
q)f[3;`ab]
0b
q)t:([] l:1 2 3; s: `a`bc`de)
q)update r:f'[l;s] from t
l s r
------
1 a 1
2 bc 1
3 de 0
I ran into an operation I cannot seem to achieve via vectorization.
Let's say I want to find the matrix of the application defined by
h: X -> cross(V,X)
where V is a predetermined vector (both X and V are 3-by-1 vectors).
In Matlab, I would do something like
M= cross(repmat(V,1,3),eye(3,3))
to get this matrix. For instance, V=[1;2;3] yields
M =
0 -3 2
3 0 -1
-2 1 0
Let's now suppose that I have a 3-by-N matrix
V=[V_1,V_2...V_N]
with each column defining its own cross-product operation. For N=2, here's a naive try to find the two cross-product matrices that V's columns define
V=[1,2,3;4,5,6]'
M=cross(repmat(V,1,3),repmat(eye(3,3),1,2))
results in
V =
1 4
2 5
3 6
M =
0 -6 2 0 -3 5
3 0 -1 6 0 -4
-2 4 0 -5 1 0
while I was expecting
M =
0 -3 2 0 -6 5
3 0 -1 6 0 -4
-2 1 0 -5 4 0
2 columns are inverted.
Is there a way to achieve this without for loops?
Thanks!
First, make sure you read the documentation of cross very carefully when dealing with matrices:
It says:
C = cross(A,B,DIM), where A and B are N-D arrays, returns the cross
product of vectors in the dimension DIM of A and B. A and B must
have the same size, and both SIZE(A,DIM) and SIZE(B,DIM) must be 3.
Bear in mind that if you don't specify DIM, it's automatically assumed to be 1, so you're operating along the columns. In your first case, you specified both the inputs A and B to be 3 x 3 matrices. Therefore, the output will be the cross product of each column independently due to the assumption that DIM=1. As such, you expect that the i'th column of the output contains the cross product of the i'th column of A and the i'th column of B and the number of rows is expected to be 3 and the number of columns needs to match between A and B.
You're getting what you expect because the first input A has [1;2;3] duplicated correctly over the columns three times. From your second piece of code, what you're expecting for V as the first input (A) looks like this:
V =
1 1 1 4 4 4
2 2 2 5 5 5
3 3 3 6 6 6
However, when you do repmat, you are in fact alternating between each column. In fact, you are getting this:
V =
1 4 1 4 1 4
2 5 2 5 2 5
3 6 3 6 3 6
repmat tile matrices together and you specified that you wanted to tile V horizontally three times. That's obviously not correct. This explains why the columns are swapped because the second, fourth and sixth columns of V actually should appear at the last three columns instead. As such, the ordering of your input columns is the reason why the output appears swapped.
As such, you need to re-order V so that the first three vectors are [1;2;3], followed by the next three vectors as [4;5;6] after. Therefore, you can generate your original V matrix first, then create a new matrix such that the odd column comes first in a group of three, followed by the even column in a group of three after:
>> V = [1,2,3;4,5,6].';
>> V = V(:, [1 1 1 2 2 2])
V =
1 1 1 4 4 4
2 2 2 5 5 5
3 3 3 6 6 6
Now use V with cross and maintain the same second input:
>> M = cross(V, repmat(eye(3), 1, 2))
M =
0 -3 2 0 -6 5
3 0 -1 6 0 -4
-2 1 0 -5 4 0
Looks good to me!
Please allow me to post this admin:
ok so this is my problem, i want to generate all combination of a, and b, for example 1 and 2, having a combinations of (1,2), (2,1),(-1,2), and (2,-1), so 4 combination, but i want only one combination as representative of all 4 combination to be display in output for example only (1,2). so this is my draft code:
fprintf(' a b z \n _ _ _ \n');
for a= -1:3
for b=-1:3
z=a^2 + b^2
end
end
ctr=1;
i(:,3) %the position of z in array
for x =1:length(z) %the length of z array
if z = i(1,1)
ctr = ctr +1;
else
fprintf(' %d %d %d\n',a,b,z);
end
end
so this the output i want:
a b z no. of repetitions
1 1 2 4
1 0 1 4
1 2 5 4
1 3 10 4
0 2 4 2
0 3 9 2
2 2 8 1
2 3 13 2
3 3 18 1
0 0 0 1
no. of repetition means how many possible combination of a and b can generate
in=-1:3
%calculate z
[a,b]=meshgrid(in);
z=a.^2+b.^2;
%sort absolute values ascending, which allows to use unique
ac=sort(abs([a(:) b(:)]),2);
%use unique to identify duplicates
[f,g,h]=unique(ac,'rows');
%count
cnt=histc(h,1:max(h));
disp([a(g),b(g),z(g),cnt])
The output is:
0 0 0 1
1 0 1 4
2 0 4 2
3 0 9 2
1 1 2 4
2 1 5 4
3 1 10 4
2 2 8 1
3 2 13 2
3 3 18 1