Converting Matrix into an array - matlab

I have a matrix that is size(A) = 20x301088 and another vector linear_index which is 301088x1.
I need to convert A into an array that is 97x97x32x20. But it has to be in a certain order, the vector linear_index contains the linear indices of a 97x97x32 in a specific order.
For example, the element at A(20,4) should be put into linear_index(4) of B(:,:,:,20). Hopefully that makes sense. Each row of A will make its own 97x97x32 matrix, and the elements will be placed at the indices specified by the value in linear_index.
I have done it once but it requires the shiftdim command:
B(1:length(lx) , linear_index) = A(1:length(lx) , :);
B = shiftdim(A,1);
This works, but the shiftdim command takes a bit of time, especially as the size of my matrices can go up to 97x97x32x194.

How about
>> B = A(:,linear_index)'; %' re-order and permute
>> B = reshape( B, 97, 97, 32, 194, 20 );

Related

Matlab: How to extract specific cells from a 3D array using list of indices?

I have a source matrix A(m,n) for which I used "find" and now I have a list of desired indices [y,x].
I also have a 3D matrix with dimensions B(m,n,3).
I want to extract all the elements in B using the result from find.
So if find yields 4 pairs of results, I would like to have a 4x3 matrix with the contents of the Z dimension of B for the resulting indices.
I tried many things but keep failing:
A = rand(480,640);
[y,x] = find(A < 0.5);
o = B(y,x,:);
Requested 39024x39024x3 (34.0GB) array exceeds maximum array size preference.
I am clearly doing something wrong since B has dimensions (640,640,3).
With the way you are trying to index, matlab tries to index B with every combination of the elements in y and x resulting in a massive matrix. I've implemented a for loop to do what I think you are asking.
I would also note that in order to index across B the first two dimensions need to be the same size as A, Otherwise you will not be able to index B past the maximum row or column index in A.
A = rand(480,640);
B = rand(480,640,3);
[x,y] = find(A < 0.5);
o = zeros(size(x,1),1,3); % x and y are the same length so it doesn't matter
for i = 1:size(x,1)
o(i,1,:)= B(x(i),y(i),:);
end
o = reshape(o,size(x,1),3);
You can reshape B to a 2D matrix of size [m*n , 3] then use logical indexing to extract elements:
C = reshape(B, [], 3);
o = C(A<0.5, :);

Averaging Across All Matrices Stored in Structure

I am currently using the following code to get an average across 8766 matrices stored in a structure, matData, but when I look inside Mcell (1x8766 cell) all of the values stored in each cell are duplicates of that in cell 1x1. I would like to know what I am doing wrong, since I will then take the nanmean of all the matrices in this structure.
Mcell = arrayfun(#(x) matData(sprintf('(%d)',x)).shape, 1:8766, 'uni', 0);
M = nanmean( reshape(cell2mat(Mcell), 192, 144, []), 3 );
Extra notes: matData is 1x8766 struct with 1 field files in matdata are called matData(i).shape where i=1:8766 and are 192x144 double.
Thank you for all of your input and help.
You just need a combination of struct2cell, cell2mat and nanmean:
matData = cell2struct(num2cell(randn(192,144,8766),[1,2]), 'shape', 1); % Sample input
result = nanmean(cell2mat(struct2cell(matData)),3);

put matrices into an empty cell using matlab

I have four 2*2 matrices called m1,m2,m3,m4. I want to create an empty 2*2 cell array which every element of it will be also 2*2 matrices. Then I want to put m1(1,1) & m2(1,1) & m3(1,1) & m4(1,1) elements into that created empty cell matrices so that element (1,1) of them will be that m1(1,1) & m2(1,1) & m3(1,1) & m4(1,1) s. And again do it again for next remaind elements as I said.
Can anyone help me do this with matlab?
You don't need anything crazy, just reshape and num2cell
c = reshape(num2cell([m1(:), m2(:), m3(:), m4(:)], 2), size(m1));
I think this is a good general way to do it.
Edit: 2015/07/25 14:45
Based on your comments it seems like what you have is a cell array
M = {m1, m2, ..., mn}
I think you're saying that each m is 2x2, but I'll assume it's qxr
And you want to get it in the form,
c = {[m1(1,1), m2(1,1), ..., mn(1,1)], [m1(1,2), m2(1,2), ..., mn(1,2)], ..., [m1(1,q), m1(1,q), ..., mn(1,q)]
[m1(2,1), m2(2,1), ..., mn(2,1)], [m1(2,2), m2(2,2), ..., mn(2,2)], ..., [m1(2,q), m1(2,q), ..., mn(2,q)]
...
[m1(r,1), m2(r,1), ..., mn(r,1)], [m1(r,2), m2(r,2), ..., mn(r,2)], ..., [m1(r,q), m1(r,q), ..., mn(r,q)]}
If all this is accurate, then the code you need is
c = reshape(num2cell(cell2mat(cellfun(#(m) m(:), M(:)', 'uni', 0)), 2), size(M{1}));
So a good way to test this is to make a M, then run the code
M = arrayfun(#(i) randi(100, 7, 3), 1:14, 'uni', 0);
c = reshape(num2cell(cell2mat(cellfun(#(m) m(:), M(:)', 'uni', 0)), 2), size(M{1}));
the only new piece compared to the above code is the cell2mat(cellfun(#(m) m(:), M(:)', 'uni', 0)). This takes M (which is a cell array of matrices) and first turns it into a cell array of column vectors (by the cellfun). It then concatenates those columns into a matrix which each row is a m1(i,j), m2(i,j), ... set. Then like before we split each row into its own cell of a cell array, then reshape it so it's the same size as one of the m's.
This seems to be a pure syntax problem.
c = cell(4,4); %Create the empty cell
c{1,1} = [m1(1,1) m2(1,1); m3(1,1) m4(1,1)]; Put a constructed 2x2 matrix in position 1,1
c{1,2} = [m1(1,2) m2(1,2); m3(1,2) m4(1,2)];
c{2,1} = [m1(2,1) m2(2,1); m3(2,1) m4(2,1)];
c{2,2} = [m1(2,2) m2(2,2); m3(2,2) m4(2,2)];
If you want, (e.g. if your actual problem is a much bigger size) you can do the same thing in loops. There may even be a clever arrayfun solution. But nothing will be faster.

Bitwise or over an array in Matlab?

I have a large array of binary numbers, and I want to do a bitwise OR over one dimension of the array:
X = [ 192, 96, 96, 2, 3
12, 12, 128, 49, 14
....
];
union_of_bits_on_dim2 = [
bitor(X(:,1), bitor(X(:,2), bitor(X(:,3), ... )))
];
ans =
[ 227
191
... ]
Is there a simple way of doing this? I'm actually working on an n-dimensional array. I tried bi2de but it flattens out my array and so the subscripting becomes complicated.
I could do it easily if matlab had a fold function but I don't think it does.
OK #Divakar asked for runnable code so to make it clear here is a long-winded version that might work for a 2D array.
function U=union_of_bits_on_dim2(X)
U=zeros(size(X,1),1);
for i=1:size(X,2)
U=bitor(U,X(:,i));
end
Surely it be done without looping? I was of course hoping that bitor could take arbitrary numbers of arguments. Then it could have been done with mat2cell.
One vectorized approach -
[m,n] = size(X) %// Get size of input array
bd = dec2bin(X)-'0' %// Get binary digits
%// Get cumulative "OR-ed" version with ANY(..,1)
cum_or = reshape(any(permute(reshape(bd,m,n,[]),[2 3 1]),1),8,[])
%// Finally convert to decimals
U = 2.^(7: -1:0)*cum_or
I don't know any function that can do that automatically. However you can loop over the dimension you are interested in:
function result = bitor2d(A)
result = A(1,:);
for i=2:size(A,1)
result = bitor(result,A(i,:));
end
end
If your array has more than 2 dimensions, then you need to prepare it to have only 2.
function result = bitornd(A,whichdimension)
B = shiftdim(A,whichdimension-1); % change dimensions order
s = size(B);
B = reshape(B,s(1),[]); % back to the original shape
result = bitor2d(B);
s(1) = 1;
result = reshape(result,s); % back to the original shape
result = shiftdim(result,1-whichdimension); % back to the original dimension order
end

Comparing two matrices of different size to get common elements in Matlab

I have matrix A size 100x100 and matrix B with size 200x200. I want to check whether each element in A is found in B or not and return a vector of common elements. So for example if the first element in A (1,1) is '10' then will check if B has an element '10' or not, if yes then will be added to the resulted common elements vector. So if anyone could please advise.
Use:
[C, ia, ib] = intersect(A,B);
C is the common elements vector, ia contains the indices of A and ib contains the indices of B, such that C = A(ia) and C = B(ib). If you don't want indices, simply use:
C = intersect(A,B);
To search for every elements in A matrix in B matrix You can convert them to row vectors as follows:
A1 = reshape(A, 1, length(A));
B1 = reshape(B, 1, length(B));
And then use intersect.