How to reorder a vector to matrix without loop? - matlab

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).'].';

Related

how can one obtain all combinations of a vector?

I want to find all possible variations (combinations) of a vector, choosing various numbers of elements from that vector.
For example, suppose I have the vector:
x = [1 2 3 4 5];
I can determine the number of combinations for each number of chosen elements:
x = [1 2 3 4 5]';
n = numel(x);
for k = 1:n
combs(k) = nchoosek(n,k);
end
sum(combs)
This results in:
combs = 5 10 10 5 1
sum(combs) = 31
I want a way to store all 31 of these combinations in an array, for example a cell array, with n cells, within each is an array in which each row is a vector combination of the elements.
e.g. at k = 4:
combs{4} =
1 2 3 4
1 2 3 5
1 2 4 5
1 3 4 5
2 3 4 5
Is there an existing function that does this, or what would be the most simple approach to this?
Call nchoosek with a vector as first input, using arrayfun (or equivalently for) to loop over the number of picked elements:
n = 5;
combs = arrayfun(#(k) nchoosek(1:n,k), 1:n, 'UniformOutput', false);
Here is an approach using dec2bin , find and accumarray:
x = [1 2 3 4 5];
[a b] = find(dec2bin(1:2^numel(x)-1)=='1');
combs = accumarray(a,x(b),[],#(c){c});

Reshape 59x16 double into 236x4?

How can I reshape a matrix in MATLAB, preferably using reshape?
A simple matrix setup:
A = [1 4 7 10; 2 5 8 11; 3 6 9 12]
that I want to reshape into
B = [1 4; 2 5; 3 6; 7 10; 8 11; 9 12]
I've tried numerous settings of reshape, but I cannot figure it out.
1 2 3 4
5 6 7 8
reshaped into
1 2
5 6
3 4
7 8
You can use reshape and permute:
reshape(permute(reshape(A,size(A,1),2,[]),[1 3 2]),[],2)
Thanks to #LuisMendo that suggests a modification to the answer to avoid depending on the size of A.
If I understand the transformation properly it is:
A = [1 4 7 10; 2 5 8 11; 3 6 9 12]
B = A(:,1:end/2);
B = [B;A(:,end/2+1:end)];
Is this correct?
EDIT:
Or the general case:
function [B] = elefaaant(A,n)
[a,b] = size(A);
if mod(b,n) ~= 0
error('Cannot reshape')
end
B = zeros(a*n,b/n);
fac = b/n;
for i = 1:n
B((i-1)*a+1:i*a,:) = A(:,(i-1)*fac+1:i*fac);
end
B = A(:,1:end/2);
B = [B;A(:,end/2+1:end)];
C = B(:,1:end/2);
C = [C;B(:,end/2+1:end)];
Maybe it can be done in a simpler way, but seems to work.

permutation of separate rows of matrix

How to effectively vectorize the following MATLAB code, which performs permutation of each row of matrix R by indices in corresponding row of matrix P?
for i = 1:size(P,1)
pP(i,:) = R(i,P(i,:));
end
example:
P = [3 2 1;
3 1 2;
2 3 1;
2 1 3;
1 2 3;
1 3 2]
R = [6 5 4;
6 4 5;
5 6 4;
5 4 6;
4 5 6;
4 6 5]
produce following matrix pR:
4 5 6
5 6 4
6 4 5
4 5 6
4 5 6
4 5 6
One approach with bsxfun -
nrows = size(R,1)
pP = R(bsxfun(#plus,[1:nrows]',(P-1)*nrows))
Or with ndgrid -
[m,n] = size(R)
pP = R(sub2ind([m n],ndgrid(1:m,1:n),P))
Or replace ndgrid(1:m,1:n) with repmat: repmat([1:m]',[1 n]) or with meshgrid:meshgrid(1:m,1:n).'.
This might not be the best way to do it, but you could do something like:
IND1 = P(:,1)
Q(:,1) = diag(R(:,IND));
and repeat for P(:,2), P(:,3) in a similar fashion.
You can use arrayfun to avoid the loop but probably won't gain in performance if that it is the reason for vectorizing it:
cell2mat(arrayfun(#(k) R(k, P(k,:)), (1:size(P,1)).', 'uni', 0))

How to compare in Matlab two matrices of different dimension and get the frequency of equal rows?

I have matrix A in Matlab of dimension hxk and a matrix B of dimension yxk. I want to construct a vector C of dimension yx1 listing in each row j how many times B(j,:) appears in A.
If you are looking for perfect matches, one solution with bsxfun -
C = squeeze(sum(all(bsxfun(#eq,A,permute(B,[3 2 1])),2),1))
You can also use pdist2 (from the Statistics Toolbox):
C = sum(pdist2(A, B)==0);
Another solution using ismember and accumarray
A=[1 2 3; 4 5 6; 7 8 9; 1 2 3; 4 5 6; 10 11 12; 7 8 9];
B=[1 2 3; 10 11 12; 3 4 5; 7 8 9];
[uB,aB,cB]=unique(B,'rows');
[~,LocB] = ismember(A,uB,'rows');
C = accumarray(nonzeros(LocB),1,[size(B,1),1]);
C=C(cB);
which returns
C =
2 1 0 2
or some crazy coding which seems to be faster for most instances:
[u,v,w]=unique([B;A],'rows');
wB=w(1:size(B,1));
wA=w(size(B,1)+1:end);
C=accumarray(wA,1,[numel(v),1]);
C=C(wB);

simple sliding window filter in 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...