(KDB+/q) Get diagonal elements of a matrix - kdb

I want to get all the diagonal elements of a matrix in kdb+/q.
E.g.
q)A:(1 2 3; 4 5 6; 7 8 9)
q)A
1 2 3
4 5 6
7 8 9
would return 1 5 9
My idea is to use "." to get the elements.
q) A . 1 1 / one of the diagonal elements
5
q) 2 #' til 3 / indices
0 0
1 1
2 2
But I tried many ways and can't get it working.

Following code returns diagonal elements of matrix
(1 2 3; 4 5 6; 7 8 9) #' til 3
The code
generates continuous list 0, 1, 2 on the right
Gets an element from every list on the left by applying corresponding index on the right (#' adverb)
Generic form looks like:
getDiagonal: {x#'til count x};
getDiagonal (1 2 3; 4 5 6; 7 8 9)

Related

How do I convert a list into a matrix in KDB?

I have a list of the form:
1 2 3 4
I'd like to convert it into a square matrix:
1 2
3 4
Which I think would be:
(1 2;3 4)
What's the canonical way to do this for, for n sized matrices in KDB?
You can use take
q)n: 2
q)(n; n) # 1 2 3 4
1 2
3 4
or for an m x n matrix:
q)m: 2
q)n: 3
q)(m; n) # 1 2 3 4 5 6
1 2 3
4 5 6
You can do:
n cut list
e.g.
q)3 cut til prd 3 3
0 1 2
3 4 5
6 7 8
Edit:
To insert any list into the closest n*n matrix and fill proceeding positions with NA's you can do:
q)f:{a:(ceiling sqrt b:count x); a cut x,((a*a) - b)#0N}
q)/e.g.
q)f til 10
0 1 2 3
4 5 6 7
8 9
q)

MATLAB - Frequency of an array element with a condition

I need some help please. I have an array, as shown below, 6 rows and 5 columns, none of the elements in any one row repeats. The elements are all single digit numbers.
I want to find out, per row, when a number, let's say 1 appears, I want to keep of how often the other numbers of the row appear. For example, 1 shows up 3 times in rows one, three and five. When 1 shows up, 2 shows up one time, 3 shows up two times, 4 shows up two times, 5 shows up one time, 6 shows up two times, 7 shows up one time, 8 shows up three times, and 9 shows up zero times. I want to keep a vector of this information that will look like, V = [3,1,2,2,1,2,1,3,0], by starting with a vector like N = [1,2,3,4,5,6,7,8,9]
ARRAY =
1 5 8 2 6
2 3 4 6 7
3 1 8 7 4
6 5 7 9 4
1 4 3 8 6
5 7 8 9 6
The code I have below does not give the feedback I am looking for, can someone help please? Thanks
for i=1:length(ARRAY)
for j=1:length(N)
ARRAY(i,:)==j
V(j) = sum(j)
end
end
Using indices that is in A creae a zero and one 6 * 9 matrix that [i,j] th element of it is 1 if i th row of A contains j.
Then multiply the zero and one matrix with its transpose to get desirable result:
A =[...
1 5 8 2 6
2 3 4 6 7
3 1 8 7 4
6 5 7 9 4
1 4 3 8 6
5 7 8 9 6]
% create a matrix with the size of A that each row contains the row number
rowidx = repmat((1 : size(A,1)).' , 1 , size(A , 2))
% z_o a zero and one 6 * 9 matrix that [i,j] th element of it is 1 if i th row of A contains j
z_o = full(sparse(rowidx , A, 1))
% matrix multiplication with its transpose to create desirable result. each column relates to number N
out = z_o.' * z_o
Result: each column relates to N
3 1 2 2 1 2 1 3 0
1 2 1 1 1 2 1 1 0
2 1 3 3 0 2 2 2 0
2 1 3 4 1 3 3 2 1
1 1 0 1 3 3 2 2 2
2 2 2 3 3 5 3 3 2
1 1 2 3 2 3 4 2 2
3 1 2 2 2 3 2 4 1
0 0 0 1 2 2 2 1 2
I don't understand how you are approaching the problem with your sample code but here is something that should work. This uses find, any and accumarray and in each iteration for the loop it will return a V corresponding to the ith element in N
for i=1:length(N)
rowIdx = find(any(A == N(i),2)); % Find all the rows contain N(j)
A_red = A(rowIdx,:); % Get only those rows
V = [accumarray(A_red(:),1)]'; % Count occurrences of the 9 numbers
V(end+1:9) = 0; % If some numbers don't exist place zeros on their counts
end

How to correct a vector index?

Ok so I am clustering data into clusters which are then indexed using a column. The data is in the form of motion vectors and so my data will look like this after being clustered:
[index x y x' y']
for example:
[1 3 5 4 6;
1 4 6 5 7;
2 3 5 4 6;
2 8 9 9 3;
3 2 3 2 4]
in above array there are 3 clusters, with clusters 1 and 2 each containing 2 vectors.
My problem is that I sometimes have to delete clusters based on certain criteria, and may be left with:
[2 3 5 4 6;
2 8 9 9 3;
3 2 3 2 4]
I want to be able to correct the index after deletion, so that it starts at 1 and ends with the number of clusters. So in this case replace the 2s with 1s and 3s with 2s.
Im sure there must be a simple way using a for loop but Ive been trying for a while and can't get ti right?
Assuming your matrix is called data, try this:
>> data = [2 3 5 4 6;
2 8 9 9 3;
3 2 3 2 4]
data =
2 3 5 4 6
2 8 9 9 3
3 2 3 2 4
>> data(:,1) = cumsum(diff(data([1 1:end], 1)) ~= 0) + 1
data =
1 3 5 4 6
1 8 9 9 3
2 2 3 2 4
A simple call to unique will help you do that. You can use the third output of it to assign each unique and new ID using the first column of the new data matrix (index vector) to replace its first column. Also, make sure you use the 'stable' flag so that it assigns IDs in order of occurrence from top to bottom:
%// Data setup
A = [1 3 5 4 6;
1 4 6 5 7;
2 3 5 4 6;
2 8 9 9 3;
3 2 3 2 4];
%-----
B = A(3:end,:); %// Remove first two rows
%// Go through the other IDs and reassign to unique IDs from 1 up to whatever
%// is left
[~,~,id] = unique(B(:,1), 'stable');
%// Replace the first column of the new matrix with the new IDs
B(:,1) = id; %// Replace first column with new IDs
We get:
>> B
B =
1 3 5 4 6
1 8 9 9 3
2 2 3 2 4

Matlab(the same cell in different matrix)

I have two matrix A and B. Suppose I would like to find in each row of matrix A the smallest number, and for the same cell that this number is in Matrix A, do find the corresponding number of the same cell in matrix B. For example the number in matrix A will be in the position A(1,3), A(2,9)...and I want the corresponding number in B(1,3), B(2,9)... Is it possible to do it, or I am asking something hard for matlab. Hope someone will help me.
What you can do is use min and find the minimum across all of the rows for each column. You would actually use the second output in order to find the location of each column per row that you want to find. Once you locate these, simply use sub2ind to access the corresponding values in B. As such, try something like this:
[~,ind] = min(A,[],2);
val = B(sub2ind(size(A), (1:size(A,1)).', ind));
val would contain the output values in the matrix B which correspond to the same positions as the minimum values of each row in A. This is also assuming that A and B are the same size. As an illustration, here's an example. Let's set A and B to be a random 4 x 4 array of integers each.
rng(123);
A = randi(10, 4, 4)
B = randi(10, 4, 4)
A =
7 8 5 5
3 5 4 1
3 10 4 4
6 7 8 8
B =
2 7 8 3
2 9 4 7
6 8 4 1
6 7 3 5
By running the first line of code, we get this:
[~,ind] = min(A,[],2)
ind =
3
4
1
1
This tells us that the minimum value of the first row is the third column, the minimum value of the next row is the 4th column, and so on and so forth. Once we have these column numbers, let's access what the corresponding values are in B, so we would want row and columns (1,3), (2,4), etc. Therefore, after running the second statement, we get:
val = B(sub2ind(size(A), (1:size(A,1)).', ind))
val =
8
7
6
6
If you quickly double check the accessed positions in B in comparison to A, we have found exactly those spots in B that correspond to A.
A = randi(9,[5 5]);
B = randi(9,[5 5]);
[C,I] = min(A');
B.*(A == repmat(C',1,size(A,2)))
example,
A =
2 1 6 9 1
2 4 4 4 2
5 6 5 5 5
9 3 9 3 6
4 5 6 8 3
B =
3 5 6 8 1
9 2 9 7 1
5 6 6 5 6
4 6 1 4 5
5 3 7 1 9
ans =
0 5 0 0 1
9 0 0 0 1
5 0 6 5 6
0 6 0 4 0
0 0 0 0 9
You can use it like,
B(A == repmat(C',1,5))
ans =
9
5
5
6
6
5
4
1
1
6
9

How to flip specific parts of a matrix

I am trying to flip certain parts of a matrix. I can explain better by example. Let's say that I have a matrix
M = [ 1 3 6;
1 2 4;
1 7 1;
2 9 0;
2 8 3;
2 4 2;
2 3 1;
3 6 5;
3 4 5;
3 1 9;
4 2 4;
4 8 6 ]
What I'd like to do here is take any rows with an even number in the first column, and flip the third column elements. The end result would look like this:
1 3 6
1 2 4
1 7 1
2 9 1 *
2 8 2 *
2 4 3 *
2 3 0 *
3 6 5
3 4 5
3 1 9
4 2 6 *
4 8 4 *
Note the rows marked with a star have had the elements of the third column flipped upside-down. The problem I'm having is going through each row like in a for-loop you cannot flip an entire set of rows.
Thanks in advance for any help.
Another time accumarray is the way to go:
A =[ 1 3 6 ;
1 2 4 ;
1 7 1 ;
2 9 0 ;
2 8 3 ;
2 4 2 ;
2 3 1 ;
3 6 5 ;
3 4 5 ;
3 1 9 ;
4 2 4 ;
4 8 6 ]
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} ); %// get groups according to
%// first column and flip it
C = vertcat(C{:}); %// cell array returned,
%// transform to matrix
mask = ~mod(A(:,1),2); %// mask for even numbers
A(mask,3) = C(mask); %// replace masked values of 3rd column with flipped ones
returns:
A =
1 3 6
1 2 4
1 7 1
2 9 1
2 8 2
2 4 3
2 3 0
3 6 5
3 4 5
3 1 9
4 2 6
4 8 4
Certainly slower, but just for fun in two lines:
C = accumarray(A(:,1),A(:,3),[],#(x) {flipud(x)} );
A(~mod(A(:,1),2),3) = getfield( vertcat(C{:}), {~mod(A(:,1),2)});
%// well no, I won't explain it...
Edit: I assumed your first column just contains integers!
I would suggest you break the problem down into stages, something like so:
Identify blocks you wish to flip
Extract them
Flip them
Replace them
You can identify a set of even numbers using the unique and mod functions, then use a for loop over them and use logical indexing to pull/replace the blocks.
Here, try this
a = magic(5); % Some data in a 5x5 matrix
b = 1:numel(a); % Indices of <a>
Rearrange b however you want, then do a=a(b) to reassign a based on the reassigned indices of b. For example, the following code
disp(a(b));
would just return the elements of a in their original order. For your application this code should work:
a = <your matrix data>
b = 1:numel(a);
b = [b(1:27) fliplr(b(28:31)) b(32:34) fliplr(b(35:36))] % Change this part
a = reshape(a(b),size(a))
You should change b based on whatever you need it to do.