Select an element of a Sub matrix - matlab

I have a Matrix of 100 sub matrix . Each of this sub matrix have 6 elements (1*6),
I need to compute the mean of the first element of each sub matrix then the
second, etc
Example:
B=[4,**3**,2,1,1,2]
C=[4,**3**,5,1,1,2]
D=[6,**3**,2,1,1,2]
A={B,C,D}
...etc
So I want the mean of the surlined numbers, then the next etc
How can I do that ???
Thanks by advance,

i think what you need here is the command cell2mat. here a small script of how to compute means automatically without knowing the size of the data. let me know if that was what you were looking for.
% Problem
vec1 = [4,3,2,1,1,2];
vec2 = [4,3,5,1,1,2];
vec3 = [6,3,2,1,1,2];
A = {vec1,vec2,vec3};
% get dimensions
cols = numel(cell2mat(A(1)));
rows = numel(A);
% convert list of vectors to matrix
M = cell2mat(A);
M = reshape(M,[cols,rows]);
M = M';
means = mean(M)

Related

Mixing 3D arrays into a bigger 3D array

I wish to fill a N x M x W matrix ‘S’ with the data from matrices ‘P’ and ‘Q’. They are defined below and illustrated in the attached image. Also, we know for sure that n_1 + n_2 = N, m < M, so all the data may fit in the ‘S’ matrix.
S = zeros(M,N,W);
P = rand(m,n_1,W);
Q = rand(m,n_2,W);
I wish to combine ‘P’ and ‘Q’ in a manner specified by 3 other matrices, ‘Line_num’, ‘P_col’ and ‘Q_col’, described below and in the middle part of the attached image.
P_col = randperm(N); P_col = P_col(1:n_1); % 1 x n_1 matrix
Q_col = setxor(P_col, 1:1:N); % 1 x n_2 matrix
Line_num is a matrix composed of W vectors of the form aa:1:bb, where bb-aa = m and aa is chosen at random for each vector.
The important thing is that in this case the data along the 3rd dimension in all these matrixes represent W different test cases, with the data being different and not to be mixed between each other.
To fill ‘S’ one may proceed in two logical steps (although if it can be done in one I shall be glad)
combine Q and P into an intermediate matrix Y of shape m x N x W by
interweaving their columns. The columns specified in ‘Q_col’ are
taken from Q (using the vector index) and put in the matrix Y (using
the vector value). The same goes for P.
For each of the W vectors composing Line_num and arrays composing S,
use the values in the vector Line_num to spread out Y to the
corresponding rows in S, meanwhile maintaining their top to bottom
order.
I wish to achieve this without for-loops as I am looking to ‘vectorize’ my code and thus improve its running speed.
I have had a look at this post and this post, which are similar to what I desire. However they are simpler as the numbers to be extracted are constant. Maybe something similar would be appropriate?
Thank you for your help :)
Link to the image aforementioned
EDIT: here is an example code with a for-loop of what I want (my problem is that I want to get rid of the loop)
W = 4;
N = 10; n_1 = 4; n_2 = 6;
M = 20; m = 5;
P_col = [1,3,5,8]; % 1 x n_1 matrix
Q_col = setxor(P_col, 1:1:N); % 1 x n_2 matrix
line_num(:,:,1) = [1,5,10,15,18];
line_num(:,:,2) = [2,3,8,11,12];
line_num(:,:,3) = [4,7,8,14,19];
line_num(:,:,4) = [2,6,13,15,16];
S = zeros(M,N,W);
P = rand(m,n_1,W);
Q = rand(m,n_2,W);
for w=1:W
line_num_I = line_num(:,:,w);
S(line_num_I,Q_col,w) = Q(:,:,w);
S(line_num_I,P_col,w) = P(:,:,w);
end
Here is a vectorized solution. I'm not sure if it is more efficient than loop version specially when the size of data is large.
S ( reshape(line_num,[],1,W) ...
+ ([Q_col-1 P_col-1]) * M ...
+ (reshape(0:W-1,1,1,[]))*M*N ...
) ...
= ...
[reshape(Q,[],W);reshape(P,[],W)];
Here implicit expansion is used to convert subscripts to indices. Equivalently bsxfun can be used to compute linear indices:
S ( ...
bsxfun(#plus, ...
reshape(line_num,[],1,W), ...
bsxfun (#plus, ...
([Q_col-1 P_col-1]) * M, ...
(reshape(0:W-1,1,1,[]))*M*N ...
) ...
) ...
) ...
= ...
[reshape(Q,[],W);reshape(P,[],W)];
*Here You can find how to convert 3D index to lindex.
So I ended up finding the answer. For those of you that it may interest, the above for-loop may be replaced by
% 1. Combine columns
mixed_col = zeros(m,N,W);
mixed_col(:,Q_col,:) = Q(:,:,:);
mixed_col(:,P_col,:) = P(:,:,:);
mixed_col = permute(mixed_col,[2,1,3]); % turn 3D matrix into 2D [1]
mixed_col = reshape(mixed_col,N,[],1)';
% 2. Combine lines
S = reshape(S,M*w,N,1); % turn 3D matrix into 2D [2]
line_num_v = permute(line_num + reshape((0:1:(W-1)).*M,1,1,W),[2,1,3]); % turn 3D matrix into 2D [3]
line_num_v = reshape(line_num_v,[],1,1);
S(line_num_v,:) = mixed_col(:,:); % combine using three 2D matrices
S = permute(reshape(S',N,M,W),[2,1,3]);
This involves lots of reshaping but I don't have a simpler answer.
Thanks again for your help.

Generate a random sparse matrix with N non-zero-elements

I've written a function that generates a sparse matrix of size nxd
and puts in each column 2 non-zero values.
function [M] = generateSparse(n,d)
M = sparse(d,n);
sz = size(M);
nnzs = 2;
val = ceil(rand(nnzs,n));
inds = zeros(nnzs,d);
for i=1:n
ind = randperm(d,nnzs);
inds(:,i) = ind;
end
points = (1:n);
nnzInds = zeros(nnzs,d);
for i=1:nnzs
nnzInd = sub2ind(sz, inds(i,:), points);
nnzInds(i,:) = nnzInd;
end
M(nnzInds) = val;
end
However, I'd like to be able to give the function another parameter num-nnz which will make it choose randomly num-nnz cells and put there 1.
I can't use sprand as it requires density and I need the number of non-zero entries to be in-dependable from the matrix size. And giving a density is basically dependable of the matrix size.
I am a bit confused on how to pick the indices and fill them... I did with a loop which is extremely costly and would appreciate help.
EDIT:
Everything has to be sparse. A big enough matrix will crash in memory if I don't do it in a sparse way.
You seem close!
You could pick num_nnz random (unique) integers between 1 and the number of elements in the matrix, then assign the value 1 to the indices in those elements.
To pick the random unique integers, use randperm. To get the number of elements in the matrix use numel.
M = sparse(d, n); % create dxn sparse matrix
num_nnz = 10; % number of non-zero elements
idx = randperm(numel(M), num_nnz); % get unique random indices
M(idx) = 1; % Assign 1 to those indices

Merge matrixes that are generated by function [duplicate]

In MatLab, I have a matrix SimC which has dimension 22 x 4. I re-generate this matrix 10 times using a for loop.
I want to end up with a matrix U that contains SimC(1) in rows 1 to 22, SimC(2) in rows 23 to 45 and so on. Hence U should have dimension 220 x 4 in the end.
Thank you!!
Edit:
nTrials = 10;
n = 22;
U = zeros(nTrials * n , 4) %Dimension of the final output matrix
for i = 1 : nTrials
SimC = SomeSimulation() %This generates an nx4 matrix
U = vertcat(SimC)
end
Unfortunately the above doesn't work as U = vertcat(SimC) only gives back SimC instead of concatenating.
vertcat is a good choice, but it will result in a growing matrix. This is not good practice on larger programs because it can really slow down. In your problem, though, you aren't looping through too many times, so vertcat is fine.
To use vertcat, you would NOT pre-allocate the full final size of the U matrix...just create an empty U. Then, when invoking vertcat, you need to give it both matrices that you want to concatenate:
nTrials = 10;
n = 22;
U = [] %create an empty output matrix
for i = 1 : nTrials
SimC = SomeSimulation(); %This generates an nx4 matrix
U = vertcat(U,SimC); %concatenate the two matrices
end
The better way to do this, since you already know the final size, is to pre-allocate your full U (as you did) and then put your values into U via computing the correct indices. Something like this:
nTrials = 10;
n = 22;
U = U = zeros(nTrials * n , 4); %create a full output matrix
for i = 1 : nTrials
SimC = SomeSimulation(); %This generates an nx4 matrix
indices = (i-1)*n+[1:n]; %here are the rows where you want to put the latest output
U(indices,:)=SimC; %copies SimC into the correct rows of U
end

Find the product of all entries of vector x

Here is what I am trying to do:
Let x be a vector with n entries x1,x2,...xn. Write a mat-lab program which computes the vector p with entries defined by
pk = X1*X2....Xk-1*Xk+1...Xn.
for each k =1,2,...n.
pk is the product of all the entries of x except xk. (use prod command of compute the product of all the entries, then divide by xk). Take the appropriate special action if either one of more the entries of x is zero. Using vectors throughout and no 'for' loop.
I spent too much time to figure out this problem. I still could not get it. Please help!
Brute force:
n = numel(x);
X = repmat(x(:),1,n); %// put vector in column form and repeat
X(1:n+1:end) = 1; %// make diagonal 1
result = prod(X); %// product of each column
Saving computations:
ind = find(x==0);
if numel(ind)>1 %// result is all zeros
result = zeros(size(x));
elseif numel(ind)==1 %// result is all zeros except at one entry
result = zeros(size(x));
result(ind) = prod(nonzeros(x));
else %// compute product of all elements and divide by each element
result = prod(x)./x;
end

How can I build a Scilab / MATLAB program that averages a 3D matrix?

I need to make a scilab / MATLAB program that averages the values of a 3D matrix in cubes of a given size(N x N x N).I am eternally grateful to anyone who can help me.
Thanks in advance
In MATLAB, mat2cell and cellfun make a great team for working on N-dimensional non-overlapping blocks, as I think is the case in the question. An example scenario:
[IN]: A = [30x30x30] array
[IN]: bd = [5 5 5], size of cube
[OUT]: B = [6x6x6] array of block means
To accomplish the above, the solution is:
dims = [30 30 30]; bd = [5 5 5];
A = rand(dims);
f = floor(dims./bd);
remDims = mod(dims,bd); % handle dims that are not a multiple of block size
Ac = mat2cell(A,...
[bd(1)*ones(f(1),1); remDims(1)*ones(remDims(1)>0)], ....
[bd(2)*ones(f(2),1); remDims(2)*ones(remDims(2)>0)], ....
[bd(3)*ones(f(3),1); remDims(3)*ones(remDims(3)>0)] );
B = cellfun(#(x) mean(x(:)),Ac);
If you need a full size output with the mean values replicated, there is a straightforward solution involving the 'UniformOutput' option of cellfun followed by cell2mat.
If you want overlapping cubes and the same size output as input, you can simply do convn(A,ones(blockDims)/prod(blockDims),'same').
EDIT: Simplifications, clarity, generality and fixes.
N = 10; %Same as OP's parameter
M = 10*N;%The input matrix's size in each dimensiona, assumes M is an integer multiple of N
Mat = rand(M,M,M); % A random input matrix
avgs = zeros((M/N)^3,1); %Initializing output vector
l=1; %indexing
for i=1:M/N %indexing 1st coord
for j=1:M/N %indexing 2nd coord
for k=1:M/N % indexing third coord
temp = Mat((i-1)*N+1:i*N,(j-1)*N+1:j*N,(k-1)*N+1:k*N); %temporary copy
avg(l) = mean(temp(:)); %averaging operation on the N*N*N copy
l = l+1; %increment indexing
end
end
end
The for loops and copying can be eliminated once you get the gist of indexing.