How do I implement convolution in KDB? - kdb

I'm trying to convolve a small vector (kernel) across a longer series.
The simplest possible kernel is (-1 1), which is the equivalent of the diff operator.
My failed attempt is:
{sum (x;y)*(-1;1)} scan til 10
0 1 1 2 2 3 3 4 4 5
This doesn't work, as it supplies the previous evaluation as the right component of the binary fn. What I should be doing is evaluating the function on each pair and storing the result. The result I'm looking for is:
1 1 1 1 1 1 1 1 1
What I can't figure out is an elegant KDB way of doing this calculation.
Is there an elegant way to do this in KDB?

You could use the each prior iterator to do this - https://code.kx.com/q/ref/maps/#each-prior
q)-':[til 10]
0 1 1 1 1 1 1 1 1 1

Maybe something like:
q)1_sum(1;-1)*1 prev\til 10
1 1 1 1 1 1 1 1 1
Can you provide more examples?

Related

Delete adjacent repeated terms

I have the following vector a:
a=[8,8,9,9,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8]
From a I want to delete all "adjacent" repetitions to obtain:
b=[8,9,1,2,3,4,5,6,7,8]
However, when I do:
unique(a,'stable')
ans =
8 9 1 2 3 4 5 6 7
You see, unique only really gets the unique elements of a, whereas what I want is to delete the "duplicates"... How do I do this?
It looks like a run-length-encoding problem (check here). You can modify Mohsen's solution to get the desired output. (i.e. I claim no credit for this code, yet the question is not a duplicate in my opinion).
Here is the code:
a =[8,8,9,9,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8]
F=find(diff([a(1)-1, a]));
Since diff(a) returns an array of length (length(a) -1), we want to add a value at the beginning (i.e the a(1)) to get a vector the same size as a. Here we subtract 1 so that, as mentioned by #surgical_tubing, the command find effectively finds it because it looks for non zero elements, so we want to make sure the value is non zero.
Hence diff([a(1)-1, a]) looks like this:
Columns 1 through 8
1 0 1 0 -8 0 1 0
Columns 9 through 16
1 0 1 0 1 0 1 0
Columns 17 through 20
1 0 1 0
Now having found the repeated elements, we index back into a with the positions found by find:
newa=a(F)
and output:
newa =
Columns 1 through 8
8 9 1 2 3 4 5 6
Columns 9 through 10
7 8

Count non-zero entries in each column of a matrix

If I have a matrix:
A = [1 2 3 4 5; 1 1 6 1 2; 0 0 9 0 1]
A =
1 2 3 4 5
1 1 6 1 2
0 0 9 0 1
How can I count the number of non-zero entries for each column? For example the desired output for this matrix would be:
2, 2, 3, 2, 3
I am not sure how to do this as size, length or numel do not appear to meet the requirements. Perhaps it would be best to remove zero entries first?
It's simply
> A ~= 0
ans =
1 1 1 1 1
1 1 1 1 1
0 0 1 0 1
> sum(A ~= 0, 1)
ans =
2 2 3 2 3
Here's another solution I can suggest that isn't very speed worthy for dense matrices but quite fast for sparse matrices (thanks #user1877862!). This also would mimic how one might do this in a compiled language, like C or Java, and perhaps for research purposes too. First find the row and column locations that are non zero, then do a histogram on just the column locations to count the frequency of how often you see a non-zero in each column. In other words:
[~,col] = find(A ~= 0);
counts = histc(col, 1:size(A,2));
find outputs the row and column locations of where a matrix satisfies some Boolean condition inside the argument of the function. We ignore the first output as we aren't concerned with the row locations.
The output we get is:
counts =
2
2
3
2
3

Matlab: command for counting occurrences in ascending order not cumulatively?

This must be asked before but I cannot find it now. It calculates the amount of zeros, add the count of zeros to vector, then calculate the amount of ones, append the count of ones to the vector and so on. If zero count, make it as zero.
Is there some zero command to do this counting in Matlab?
Input ---> Output
0 1 1 1 2 3 3 4 7 ---> [1,3,1,2,1,0,0,1]
0 1 1 1 ---> 1 3
2 7 ----> 0 0 1 0 0 0 0 1
To get the total count of occurrences of each number, use histc:
x = [0 1 1 1 2 3 3 4 7]; %// example data
histc(x, 0:max(x))

Quick way to sort an array with respect to row sum in Matlab

Here's a small example of what I want. Given the following array:
1 1 2
2 2 1
1 1 1
1 1 6
Sorted (row sum is shown in parenthesis):
1 1 6 (8)
2 2 1 (5)
1 1 2 (4)
1 1 1 (3)
Is there a quick way to achieve this in Matlab?
Since sort returns the indexes in order as well as the sorted matrix, you can use these indices to access the original data -- try this:
% some data
A = [
1 1 2;
2 2 1;
1 1 1;
1 1 6;
];
% compute the row totals
row_totals = sum(A,2);
% sort the row totals (descending order)
[sorted, row_ids] = sort(row_totals, 'descend');
% and display the original data in that order (concatenated with the sums)
disp([A(row_ids,:), row_totals(row_ids)])
>>>
1 1 6 8
2 2 1 5
1 1 2 4
1 1 1 3
The ugliest one-liner I could come up with:
>> subsref( sortrows( [sum(A,2) A], -1 ), struct('type','()','subs',{{':',1+(1:size(A,2))}}) )
ans =
1 1 6
2 2 1
1 1 2
1 1 1
Disclaimer: I don't think anyone should write this kind of code, but it's a nice practice to keep your Matlab's skills sharp.
Just do something very simple like follows
temp = [1 1 2
2 2 1
1 1 1
1 1 6];
rowSums = sum(temp,2);
[~,idx] = sort(rowSums,'descend');
output = [temp(idx,:),rowSums(idx)];
EDIT
Changed the above code to make sure the sum is appended to the last column. I did not notice that this was a requirement when I read the question initially.
I leave it for you to judge if this is uglier than #Shai's:
fliplr(diff([sortrows(fliplr(-cumsum(A,2))) zeros(size(A,1),1) ],1,2))
Let's do some matrix multiplication
>> sortrows([sum(A,2) A], -1)*[zeros(1,size(A,2)); eye(size(A,2))]
returns
ans =
1 1 6
2 2 1
1 1 2
1 1 1

How to count number of elements in specific row? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Count number of values in matrix within given range
I have the following matrix
A=[ 1 2 3 4 5 6 7;
3 4 5 6 8 9 1;
3 4 2 5 6 7 8]
How to find out how many element there are in the first row, which have a value in the range >2 & <6?
If I understood well what you mean with account, if you want to find elements that meet your criteria:
B = A(1,:)
find(B > 2 & B < 6)
or in one line:
find(A(1,:) > 2 & A(1,:) < 6)
You must know also that find gives you the indices, not the actual elements, of the array that satisfy the logical expression given.
You need to think in terms of matrices, using vectorized computations. (Using find is not a good solution here, since it is not vectorized to operate independently on the rows.)
First, what happens if you try the test, A > 2, in MATLAB? TRY IT!
A=[ 1 2 3 4 5 6 7;
3 4 5 6 8 9 1;
3 4 2 5 6 7 8];
>> A > 2
ans =
0 0 1 1 1 1 1
1 1 1 1 1 1 0
1 1 0 1 1 1 1
MATLAB generates a logical array, true where an element of A was greater than 2. Similarly, if we type A < 6, we get another logical array.
>> A < 6
ans =
1 1 1 1 1 0 0
1 1 1 0 0 0 1
1 1 1 1 0 0 0
What if we combine the two ops into one expression?
>> (A > 2) & (A < 6)
ans =
0 0 1 1 1 0 0
1 1 1 0 0 0 0
1 1 0 1 0 0 0
Ok, so this array tells us where both sub-expressions were true. Note that we can operate on a logical array using sum and other arithmetic ops.
>> sum((A > 2) & (A < 6),2)
ans =
3
3
3
So the above expression counts the number of elements that satisfy your goal for each row, and it will be quite fast. Learn to use MATLAB as it should be used. Your code will get better.