I have a set of values (say 20 values) in an array .
A = [1:20]
I want to divide it in to subsets of known size.
If I want to divide it in to 4 sets of size 5 then I can use
y = reshape(A,5,4)'
But my problem is when I dont have matching multiples of sizes.
Say I want to divide array in to sets of 3. So there will be 7 sets but the last set will be short.
what exactly I want is
a1= [1 2 3]
a2= [4 5 6]
a3= [7 8 9]
a4= [10 11 12]
a5= [13 14 15]
a6= [16 17 18]
a7= [19 20]
How can I do this kind of subgrouping to a vector in MATLAB?
You can use
y = mat2cell(A,1, diff([0:n:numel(A)-1 numel(A)]));
Then a1=y{1} and so on.
You'll need to write your own function for this. For example:
A = 1:20;
n = length(A);
x = 3;
y = ceil(n/x);
out = cell(y,1);
for i = 1:y
startIdx = x*(i-1)+1;
endIdx = min(startIdx + x - 1,n);
out{i} = A(startIdx:endIdx);
end
Then you can access each row in the cell array:
a1 = out{1};
a2 = out{2};
...
A = 1:20;
n = 3;
% y = number of sets
y = ceil(length(A) / n);
ai = num2cell(reshape(A(1:n*y),m,n)');
if length(A) > n * y
ai = [ai; A(n*y+1:end)];
end
Related
I have a 3x3 Matrix and want to save the indices and values into a new 9x3 matrix. For example A = [1 2 3 ; 4 5 6 ; 7 8 9] so that I will get a matrix x = [1 1 1; 1 2 2; 1 3 3; 2 1 4; 2 2 5; ...] With my code I only be able to store the last values x = [3 3 9].
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x=[];
for i = 1:size(A)
for j = 1:size(A)
x =[i j A(i,j)]
end
end
Thanks for your help
Vectorized approach
Here's one way to do it that avoids loops:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
[ii, jj] = ndgrid(1:size(A,1), 1:size(A,2)); % row and column indices
vv = A.'; % values. Transpose because column changes first in the result, then row
x = [jj(:) ii(:) vv(:)]; % result
Using your code
You're only missing concatenation with previous x:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x = [];
for i = 1:size(A)
for j = 1:size(A)
x = [x; i j A(i,j)]; % concatenate new row to previous x
end
end
Two additional suggestions:
Don't use i and j as variable names, because that shadows the imaginary unit.
Preallocate x instead of having it grow in each iteration, to increase speed.
The modified code is:
A = [1 2 3 ; 4 5 6 ; 7 8 9];
x = NaN(numel(A),3); % preallocate
n = 0;
for ii = 1:size(A)
for jj = 1:size(A)
n = n + 1; % update row counter
x(n,:) = [ii jj A(ii,jj)]; % fill row n
end
end
I developed a solution that works much faster. Here is the code:
% Generate subscripts from linear index
[i, j] = ind2sub(size(A),1:numel(A));
% Just concatenate subscripts and values
x = [i' j' A(:)];
Try it out and let me know ;)
i have a vector and a scalar as input in a problem , the problem is to compute the largest product of n consecutive number of the vector and output the product and the index of the element of the vector that is the first term of the product.
E.g vector =[ 1 2 3 4 5 6] , n=3
I'm supposed to get '3' (i e n) consecutive number of vector whose product is the largest .
in this case it will be 4*5*6
so output will be 120 and 4 as the index.
now if vector has fewer than 'n' elements, the function outputon returns 0 and -1 as the output.
please i need ideas on how to achieve this
You can make a simple implementation with loops:
a = [1 2 3 4 5 6]
w = 3
n = length(a)
maximum = -1
for i = 1:n-w
p = prod(a(i:i+w))
if (p > maximum)
maximum = p
end
end
maximum
Or, you can use the nlfilter from the image processing palette.
a = []
w = 3
if (length(a) >= w)
products = nlfilter(a, [1 w], #(x) prod(x))
res = max(products)
else
res = -1
end
You can create the moving window from the answer of raryeng for the question Matrix with sliding window elements and then appyl cumprod on the columns and take the max with its index.
myvec = [1 2 2 1 3 1];
n = 3;
ind = bsxfun(#plus, 1:n, (0:1:length(myvec)-n).')';
M = cumprod(myvec(ind));
[val,its_ind] = max(M(end,:));
You can encapsulate this with an if condition checking whether the length of myvec is larger than
You can compute the element-wise logarithm of your vector, so multiplication becomes addition; and sliding addition is just convolution with a window of ones:
function [m, p] = f(v, n)
if numel(v) < n
m = -1;
p = 0;
else
c = conv(log(v(:)), ones(n,1), 'valid'); % convolution with vector of n ones
[~, m] = max(c); % starting index of maximizing window
p = prod(v(m+(0:n-1))); % corresponding product
end
Examples:
>> v = [1 2 3 4 5 6]; n = 3;
>> [m, p] = f(v,n)
m =
4
p =
120
>> v = [1 2 3 4 5 6]; n = 7;
>> [m, p] = f(v,n)
m =
-1
p =
0
>> v = [1 4 6 2 5 3]; n = 3;
>> [m, p] = f(v,n)
m =
3
p =
60
I have been trying to use the multidimensional array function to store NxN vectors of length n in each (i,j) entry of a 3d matrix of NxNxn dimensions.
My code looks like:
a=zeros(N,N,n);
a(i,j,:)=v_ij; %here v is a vector of length n, which differs for each i,j
However when I try to extract each vector by typing e.g. a(1,1,:) I don't get a nice vector. Rather I get something like:
ans(:,:,1) = ..
ans(:,:,2) = ..
...
I don't understand why it says ans(:,:)...
That's because each vector v_ij is stored along the 3rd dimension of your matrix, so when you access a(1,1,:), you are looking for a multidimensional array consisting of every value at the location (1,1) along the 3rd dimension of a.
Let's consider a simple example:
N = 2;
n = 3;
a = zeros(N,N,n);
for k = 1:N
for l = 1:N
v_kl = randi([0 10],1,n);
a(k,l,:) = v_kl;
end
end
The randomly-generated matrix a is a 2x2x3 matrix that looks like this:
a(:,:,1) =
4 1
4 10
a(:,:,2) =
0 2
0 5
a(:,:,3) =
2 2
9 5
Therefore, using a(1,1,:) is equivalent to getting the element located at (1,1) for all 3 dimensions, here it would be 4,0 and 2.
Indeed, calling a(1,1,:) yields:
ans(:,:,1) =
4
ans(:,:,2) =
0
ans(:,:,3) =
2
Benoit_11's answer plus squeeze should work, but I would like to propose a different solution.
Rather than creating a NxNxn array, why not make it nxNxN?
N = 2;
n = 3;
a = zeros(n,N,N);
for p = 1:N
for q = 1:N
v_pq = randi([0 10],1,n);
a(:,p,q) = v_pq;
if (p == 1) && (q == 1)
v_pq %// display vector at a(:,1,1)
end
end
end
a
v_pq =
3 4 8
a =
ans(:,:,1) =
3 3
4 9
8 7
ans(:,:,2) =
5 6
10 1
9 5
Now the vectors are stored along the first dimension, so [3 4 8] shows up as the first column of ans(:,:,1). To access it you would use a(:,p,q) rather than a(p,q,:):
a(:,1,1)
ans =
3
4
8
MATLAB:
I am trying to do basis expansion of a huge matrix(1000x15).
For example,
X =
x1 x2
1 4
2 5
3 6
I want to build a new matrix.
Y =
x1 x2 x1*x1 x1*x2 x2*x2
1 4 1 4 16
2 5 4 10 25
3 6 9 18 36
Could any one please suggest a easier way to do this
% your input
A = [1 4; 2 5; 3 6];
% generate pairs
[p,q] = meshgrid(1:size(A,2), 1:size(A,2));
% only retain unique pairs
ii = tril(p) > 0;
% perform element wise multiplication
res = [A A(:,p(ii)) .* A(:,q(ii))];
Using the one-liner from this answer to get the 2-combinations of the indices, you can generate the matrix without the interleaved ordering with
function Y = columnCombo(Y)
comb = nchoosek(1:size(Y,2),2);
Y = [Y , Y.^2 , Y(:,comb(:,1)).*Y(:,comb(:,2))];
end
For the interleaved ordering, I came up with this, possibly sub-optimal, solution:
function Y = columnCombo(Y)
[m,n] = size(Y);
comb = nchoosek(1:n,2);
Y = [Y,zeros(m,n + size(comb,1))];
col = n+1;
for k = 1:n-1
Y(:,col) = Y(:,k).*Y(:,k) ;
ms = comb(comb(:,1)==k,:) ;
ncol = size(ms,1) ;
Y(:,col+(1:ncol)) = Y(:,ms(:,1)).*Y(:,ms(:,2)) ;
col = col + ncol + 1 ;
end
Y(:,end) = Y(:,n).^2;
end
This problem is a succession of my previous problem:
1) Extract submatrices, 2) vectorize and then 3) put back
Now, I have two patients, named Ann and Ben.
Indeed the matrices A and B are data for Ann and the matrix C is data for Ben:
Now, I need to design a matrix M such that y = M*x where
y = [a11, a21, a12, a22, b11, b21, b12, b22]' which is a vector, resulting from concatenation of the top-left sub-matrices, Ann and Ben;
x = [2, 5, 4, 6, 7, 9, 6, 2, 9, 3, 4, 2]' which is a vector, resulting from concatenation of sub-matrices A, B and C.
Here, the M is a 8 by 12 matrix that
a11 = 2 + 7, a21 = 5 + 9, .., a22 = 6 + 2 and b11 = 9, ..b22 = 2.
I design the M manually by:
M=zeros(8,12)
M(1,1)=1; M(1,5)=1; % compute a11
M(2,2)=1; M(2,6)=1; % compute a21
M(3,3)=1; M(3,7)=1; % compute a12
M(4,4)=1; M(4,8)=1; % compute a22
M(5,9)=1; % for setting b11 = 9, C(1,1)
M(6,10)=1; % for setting b21 = 3, C(2,1)
M(7,11)=1; % for setting b12 = 4, C(1,2)
M(8,12)=1 % for setting b22 = 2, C(2,2)
Obviously, in general for M(i,j), i means the 8 linear-index position of vector y and j means linear-index position of vector x.
However, I largely simplified my original problem that I want to construct this M automatically.
Thanks in advance for giving me a hand.
Here you have my solution. I have essentially build the matrix M automatically (from the proper indexes) as you suggested.
A = [2 4 8;
5 6 3;
10 3 6];
B = [7 6 3;
9 2 9;
10 2 3];
C = [9 4 7;
3 2 5;
10 3 4];
% All matrices in the same array
concat = cat(3, A, B, C);
concat_sub = concat(1:2,1:2,:);
x = concat_sub(:);
n = numel(x)/3; %Number of elements in each subset
M2 = zeros(12,8); %Transpose of the M matrix (it could be implemented directly over M but that was my first approach)
% The indexes you need
idx1 = 1:13:12*n; % Indeces for A
idx2 = 5:13:12*2*n; % Indices for B and C
M2([idx1 idx2]) = 1;
M = M2';
y = M*x
I have taken advantage of the shape that the matrix M shold take:
You can index into things and extract what you want without multiplication. For your example:
A = [2 4 8; 5 6 3; 10 3 6];
B = [7 6 3; 9 2 9; 10 2 3];
C = [9 4 7;3 2 5; 10 3 4];
idx = logical([1 1 0;1 1 0; 0 0 0]);
Ai = A(idx);
Bi = B(idx);
Ci = C(idx);
output = [Ai; Bi; Ci];
y = [Ai + Bi; Ci]; % desired y vector
This shows each step individually but they can be done in 2 lines. Define the index and then apply it.
idx = logical([1 1 0;1 1 0;0 0 0]);
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Also you can use linear indexing with idx = [1 2 4 5]' This will produce the same subvector for each of A B C. Either way works.
idx = [1 2 4 5]';
or alternatively
idx = [1;2;4;5];
output = [A(idx); B(idx); C(idx)];
y = [Ai + Bi; Ci]; % desired y vector
Either way works. Check out doc sub2ind for some examples of indexing from MathWorks.