simple sliding window filter in Matlab - matlab

I don't have the package for nlfilter and I didn't quite follow this example.
I have a really simple function fun and I want to apply it to a moving window of an array. The array is Nx1, and I want to look at length k intervals, say. So for N=10 and k=3 and fun = #(x) min(x); I would get
A = [13 14 2 14 10 3 5 9 15 8];
filter(A,k,fun) = [2 2 2 3 3 3 5 8];
Here I only want to look at indices 1,2,3 then 2,3,4 then ... then 8,9,10, so the final sequence is length 7. I can do this easy with a for loop, but I have no idea how to vectorize it for Matlab. Help, please. Thanks.

Here is one very simple and fast way to do it:
>> min([A(1:(end-2)); A(2:(end-1)); A(3:end)], [], 1)
ans =
2 2 2 3 3 3 5 8
EDIT: Since you want a full function...
function running_min = running_min(x, k)
xrep = repmat(x, 1, k);
xrep = reshape([xrep zeros(1, k)], length(x)+1, k);
running_min = min(xrep, [], 2)';
running_min = running_min(1:end-k);

The post you mentioned gave a general solution for building sliding windows (you could control: overlapping vs. distinct, slide step, overlap amount, windows size)
In your case, it is much simpler and can be easily performed with the HANKEL function:
x = [13 14 2 14 10 3 5 9 15 8];
idx = hankel(1:3, 3:length(x))
min( x(idx) )
If you want to build a reusable solution:
function y = myFilter(x,k,fcn)
idx = hankel(1:k, k:length(x));
y = cellfun(fcn, num2cell(x(idx),1));
end
which we use as:
x = [13 14 2 14 10 3 5 9 15 8];
y = myFilter(x, 3, #(x)min(x))
Note I am using CELLFUN in case fcn cannot operate across dimensions in a vectorized manner...

Related

Matlab resample array based on second array

Let's say I have two datasets, both consisting of an x and y array, e.g.:
x_1 = [1 2 3 4 5 6 7 8 9 10];
y_1 = [8 12 20 3 4 9 10 55 3 2];
x_2 = [2 5 6 8 9];
y_2 = [4 18 3 12 1];
Now, I'd like to calculate a new metric z = y_1 ./ y_2 but I want to compare elements of y_1 by elements of y_2 with the same x, value:
z = [12 4 9 55 3 2] ./ [4 18 3 12 1]
How can I then find this second array containing only the values of y_2 with a corresponding x_2 value that occurs in x_1 in an efficient way?
So far, I came up with this solution but I doubt it's the most efficient possibility:
for i = 1:numel(x_2)
z(i) = y_2(i) / y_1(y_1 == x_2(i));
end
Since looping over elements can generally be avoided in Matlab, I assume there's better ways to do this.
So basically, I want to resample the second dataset to make its x_2 array equal to x_1
You can vectorize this using ismember:
[Lia,Locb] = ismember(x_1, x_2);
z = y_1(Lia) ./ y_2(nonzeros(Locb).');
Whether you should or not is another question. Avoiding loops in MATLAB is largely an obsolete strategy since MATLAB started introducing the JIT compilation engine. I have my doubts that vectorized version will be any faster than the for-loop, except maybe for the largest datasets, and I don't believe it is any more readable. YMMV
Similar to previous answer, but shorter:
y_1(ismember(x_1,x_2))./y_2
Note: I've checked this on Octave, as don't have Matlab license.

diagonal averaging of matrix in matlab

let us consider following matrix
A=[1 2 3 4;2 4 6 7;3 1 9 8]
A =
1 2 3 4
2 4 6 7
3 1 9 8
size of which can easily be calculated using
n,m]=size(A)
n =
3
m =
4
let us consider that we want to get following vector v
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2)/2;
v(3)=(A(3,1)+A(2,2)+A(1,3))/3;
v(4)=(A(3,2)+A(2,3)+A(1,4))/3;
v(5)=(A(3,3)+A(2,4))/2;
v(6)=A(3,4);
definitely we need vector with size
v=zeros(n+m-1,1);
i have calculated first two element which seems trivial
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2))/2;
but all others i need to implement using cycles,please pay attention that i need it for general matrix using same principle,not exact for such matrix
my starting code is following
function [v]=dehankel(A);
%convert matrix A to vector using diagonal averaging
[n,m]=size(A);
v=zeros(n+m-1,1);
v(1)=A(1,1);
v(2)=(A(2,1)+A(1,2))/2;
for i=2:3
for j=2:3
please help me how to continue
A =
1 2 3 4
2 4 6 7
3 1 9 8
[n,m]=size(A);
v=zeros(n+m-1,1);
i = 1;
for d = -(n-1):(m-1)
v(i) = mean(diag(flipud(A),d));
i = i+1;
end
It can be done without loops (not the most readable code, I admit):
B = zeros(size(A,1)+size(A,2)-1, size(A,2));
B(bsxfun(#plus, (1:size(A,1)).', (0:size(A,2)-1)*(size(A,1)+size(A,1)+1))) = A;
v = sum(B.')./[1:size(A,1) size(A,1):-1:1];

Matlab, How to get each column in a matrix

I got a 4-by-n matrix, like
A =
1 5 9
3 0 6
2 3 10
7 8 4
What I want to do with A is getting each half column of A as
Line1Point1 = [1 3]
Line1Point2 = [2 7]
Line2Point1 = [5 0]
Line2Point2 = [3 8]
Line3Point1 = [9 6]
Line3Point2 = [10 4]
How could I do that? I’m pretty new to matlab coding.. Any help is really appreciated..
Cheers
Use reshape function, for example:
>> A = [1 5 9;
3 0 6;
2 3 10;
7 8 4];
>> reshape(A,2,6)
ans =
1 2 5 3 9 10
3 7 0 8 6 4
Storing such information as many variables is generally a bad idea
Some options for storing and accessing are
Cell array
Line=mat2cell(A,[2,2],ones(1,size(A,2))).'
access with
Line{2,1}
ans =
5
0
Indexing
as other answers
Anonymous Function
Line=#(l,p)A(2*p-1:2*p,l)
access with
Line(2,1)
ans =
5
0
Structure
Not really a useful solution, more for interests sake
for ii=1:size(A,2);for jj=1:2;Line(ii).Point(jj).Value=A(2*jj-1:2*jj,ii);end;end
access with
Line(2).Point(1).Value
ans =
5
0
A(1:2,1) will give you first half of the first column.
A(3:4,1) will give you second half of the first column.
A(1:2,2) will give you first half of the second column.
A(3:4,2) will give you second half of the second column.
A(1:2,3) will give you first half of the third column.
A(3:4,3) will give you second half of the third column.
You can create the variables with the eval function, which executes the input string. Using eval is commonly regarded as bad practice since it is horrible to debug.
Nevertheless, here's the code:
A = [1 5 9; 3 0 6; 2 3 10; 7 8 4];
for ii = 1:length(A(1,:))
eval(['Line' num2str(ii) 'Point1 = A(1:2, ii)' ]);
eval(['Line' num2str(ii) 'Point2 = A(3:4, ii)' ]);
end
% Now all variables are created - for example: Line2Point1
A more elegant solution could be to store the vectors in a cell array. You can acces the first vectors for example by typing: c{1,1}
c = cell(length(A(1,:)),2)
for ii = 1:length(A(1,:))
c{ii,1} = A(1:2, ii);
c{ii,2} = A(3:4, ii);
end
I would suggest using 3D arrays to store and then access those values.
Code
N = size(A,1)/2;
LinePoint = permute(reshape(A,N,size(A,1)/N,[]),[1 3 2])
Here,
2nd dimension indices (columns) would represent Line IDs
3rd dimension indices would represent Point IDs.
Thus, the representative 3D array would be - LinePoint(:,LineID,PointID).
Example run
For your given A, we would have LinePoint as -
LinePoint(:,:,1) =
1 5 9
3 0 6
LinePoint(:,:,2) =
2 3 10
7 8 4
Thus,
Line1Point1 would be denoted by LinePoint(:,1,1)
Line1Point2 would be denoted by LinePoint(:,1,2)
Line2Point1 would be denoted by LinePoint(:,2,1)
Line2Point2 would be denoted by LinePoint(:,2,2)
Line3Point1 would be denoted by LinePoint(:,3,1)
Line3Point2 would be denoted by LinePoint(:,3,2)

How to reorder a vector to matrix without loop?

Here is my task
I have a vector like this
a = [1 2 3 4 5 6 7 8 9 10 11];
I want to have a matrix like this:
b = [1 2 3;
3 4 5;
5 6 7;
7 8 9;
9 10 11];
That is in every two elements I pick three elements.
In general, I want pick m elements in every k elements.
I know how to do it with a loop, but I want to ask if there is a way that can do it without a loop in MATLAB.
Thanks in advance.
To pick m elements every k elements:
inds = bsxfun(#plus,(1:m),(0:k:(numel(a)-m)).')
a(inds)
That pattern appears in the hankel matrix.
ha = hankel(a');
b = ha(1:k:end-m+1, 1:m);
I came up with something like this, but I'm not sure it works for all cases:
a(cumsum([1:m; ones(floor((numel(a) - m) / k), m) * k]))
Another approach:
m = 3;
k = 2;
a = [1 2 3 4 5 6 7 8 9 10 11]; %// length should be {a multiple of k} plus m
result = reshape(a(1:floor(numel(a)/k)*k), k, []);
result = [result; result(1:m-k,2:end) a(end-m+k+1:end).'].';

Extract the sequence matrix elements?

I have a matrix as shown in below:
A=[2 4;1 3;8 6;5 1;4 9]
now i need to extract the matrix A into 2 parts:
newpoint=[2 4];
rest=[1 3;8 6;5 1;4 9];
then apply loop again to extract the second column as new point :
newpoint=[1 3];
rest=[2 4;8 6;5 1;4 9];
Applying loop again to take third column number as new point :
newpoint=[8 6];
rest=[2 4;1 3;5 1;4 9];
Take the number in row sequence until the last row . Can someone be kind enough to help.Thanks~
Apart from HebeleHododo's answer, if you have big matrices maybe you can try this:
A = [2 4; 1 3; 8 6; 5 1; 4 9];
B = zeros(size(A,1)-1,size(A,2));
for idx = 1:size(A, 1)
newpoint = A(idx, :);
B(1:idx-1,:) = A(1:idx-1,:);
B(idx:end,:) = A(idx+1:end,:);
% do stuff
end
It doesn't get rid of the for loop, but the temporary B matrix is pre-allocated and the copy between A and B is clear, which makes it quicker.
For A = rand(100000,2); HebeleHododo's method takes ~123 seconds in my computer
and the one above takes ~85 seconds.
Edit: Just for reference, the timing is done using Intel Core i5-3450 CPU # 3.10GHz and Matlab R2011b
You said you want to extract columns, but gave examples with rows. I am going ahead and assuming you meant rows.
You can do it with a for loop.
A = [2 4; 1 3; 8 6; 5 1; 4 9];
for idx = 1:size(A, 1)
newpoint = A(idx, :);
rest = A; % Copy A to rest
rest(idx, :) = []; % Remove newpoint line
% do stuff
end
Results of first two iterations:
newpoint =
2 4
rest =
1 3
8 6
5 1
4 9
newpoint =
1 3
rest =
2 4
8 6
5 1
4 9
This is not a good method if your A matrix is big.
Edit: In fact, do not use this method. George Aprilis timed it and found 123 seconds for a 100000x2 matrix. I guess my computer is much slower. It took 216 seconds. I repeat, do not use this.