Matlab - Two Column Matrices into One Column Matrix with rows elements - matlab

I have two column matrices:
size(X) = 50 x 1
size(Y) = 50 x 1
which I got from ind2sub
I want to create a structure str such that
str(i).XYZ returns [X(i), Y(i)] for i in [1,50]
I am trying to use
str = struct('XYZ', num2cell([X,Y]));
However, I believe for this to work properly, I need to modify [X,Y] to a matrix of row vectors, each row vector being [X(i), Y(i)]. Not sure if there is a better approach

You are basically on the right way, but num2cell([X,Y]) creates a 2x50 cell, which results in a 2x50 struct. You want to split your input matrix [X,Y] only among the second dimensions so each cell is a 2x1, use num2cell([X,Y],2)
str = struct('XYZ', num2cell([X,Y],2));

Concatenate the two vectors, convert from matrix to cell, and then from cell to struct array:
str = cell2struct(mat2cell([X Y], ones(1,size(X,1)), size(X,2)+size(Y,2) ).', 'XYZ');

Related

Matlab Mean over same-indexed elements across cells

I have a cell array of 53 different (40,000 x 2000) sparse matrices. I need to take the mean over the third dimension, so that for example element (2,5) is averaged across the 53 cells. This should yield a single (33,000 x 2016) output. I think there ought to be a way to do this with cellfun(), but I am not able to write a function that works across cells on the same within-cell indices.
You can convert from sparse matrix to indices and values of nonzeros entries, and then use sparse to automatically obtain the sum in sparse form:
myCell = {sparse([0 1; 2 0]), sparse([3 0; 4 0])}; %// example
C = numel(myCell);
M = cell(1,C); %// preallocate
N = cell(1,C);
V = cell(1,C);
for c = 1:C
[m n v] = find(myCell{c}); %// rows, columns and values of nonzero entries
M{c} = m.';
N{c} = n.';
V{c} = v.';
end
result = sparse([M{:}],[N{:}],[V{:}])/C; %'// "sparse" sums over repeated indices
This should do the trick, just initialize an empty array and sum over each element of the cell array. I don't see any way around using a for loop without concatenating it into one giant 3D array (which will almost definitely run out of memory)
running_sum=zeros(size(cell_arr{1}))
for i=1:length(cell_arr)
running_sum=running_sum+cell_arr{i};
end
means = running_sum./length(cell_arr);

use vertcat for concatenate columns of matrix to make 1D column

let us consider following bit of code:
[m,n]=size(X);
if m == (n+1)
Z = vertcat(U(:,1:2:d), V(:,1:2:d));
else
Z = vertcat(U(:,[1:2:d]));
end
C=Z(:);
What I want it to do is concatenate the singular vectors into one column vector. For example, I want to concatenate the first d left and right singular vectors, but the problem is that it creates a multidimensional column, that's why I wrote C=Z(:). But, can I use vertcat to just create a 1D column vector? Thanks in advance!
It looks like you may have just flipped your row and column indexing. U(:,1:2:d) will return a row vector, which you are then vertcating with another row vector. Try this instead:
[m,n]=size(X);
if m == (n+1)
Z = vertcat(U(1:2:d,:), V(1:2:d,:));
else
Z = vertcat(U([1:2:d]), :));
end
C=Z(:);
I hope that helps.

How to transpose a cell of Mx1 cells and vectors?

I have a 1xN cell, call it X, whose components X{i} (for i in {1, 2, ..., N}) are either Mx1 cells of strings or Mx1 numeric vectors.
NOTE: the fact that X contains both text cells and numeric vectors precludes using cell2mat here:
>> tmp = cell2mat(X);
Error using cell2mat (line 46)
All contents of the input cell array must be of the same data type.
My question is:
What's MATLAB's "idiomatic" way to transpose this data into an array of M 1xN cells?
EDIT: To be clear, the data structure I want to arrive at, let's call it Y, is an M-long array of 1xN cells (each consisting of a mixture of numbers and strings). E.g., if N=2, and if X{1} is an Mx1 cell of strings, and X{2} is an Mx1 vector of doubles, then the desired data structure Y is such that, for any 1 ≤ i ≤ M, Y(i,:) is a 1x2 cell whose first element is the i-th string in X{1} and whose second element is the i-th double in X{2}. I.e. Y(i,:) would be the same as the 1x2 cell Yi defined as follows
xi1 = X(i, 1);
xi2 = X(i, 2);
Yi = {xi1{1} xi2{1}};
(Sorry for the awkwardness! I just can't find a MATLAB expression for Yi directly in terms X and i, without having to create intermediate variables xi1 and xi2.)
First of all, to my knowledge there is no 'idiomatic' way of doing that i Matlab. Remember, we're talking about a complex data structure with nested cells and differing types.
I tried to cook up a solution based on cellfun. It quickly got complicated and I didn't even succeed. So instead I would recommend doing a simple double for loop and a if like this:
for a=1:size(X,2),
for b=1:size(X{a},1),
if iscell(X{a}),
Y{a,b} = X{a}{b};
else
Y{a,b} = X{a}(b);
end
end
end
If X = {{'s1';'s2'} [3; 4]} then this solution will give Y = {'s1' 3 ;'s2' 4}.
As you see I have flattened the cell to one depth. To get your 1xN vectors, do Y{1,:}
Hope it helps
If each cell in X contains a vector of the same size convert it to a matrix, transpose that matrix and then convert it back to a cell array?
tmp = cell2mat(X);
Y = mat2cell(tmp', ...);
Here is the function:
feval(#(y) feval(#(x) cellfun(#(varargin)[varargin],x{:},'un',0), cellfun(#(x) feval(#(varargin) varargin{3-varargin{1}}(), iscell(x),x,num2cell(x)),y,'un',0)), {{'1','2','3'},[4 5 6],{7,8,9}})
Or stored as a function name:
transpose_nest = #(cell_nest) feval(#(y) feval(#(x) cellfun(#(varargin)[varargin],x{:},'un',0), cellfun(#(x) feval(#(varargin) varargin{3-varargin{1}}(),iscell(x),x,num2cell(x)),y,'un',0)), cell_nest);
transpose_nest({{'1','2','3'},[4 5 6],{7,8,9}})
{{'1',4,7},{'2',5,8},{'3',6,9}}
It is based on a Matlab equivalent of Scheme's (apply map list '(("1" "2" "3") (4 5 6) (7 8 9))) that only works on sub cells:
feval(#(x) cellfun(#(varargin)[varargin],x{:},'un',0), {{'1','2','3'},{4,5,6},{7,8,9}})
{{'1',4,7},{'2',5,8},{'3',6,9}}
The extra part:
#(x) feval(#(varargin) varargin{3-varargin{1}}(), iscell(x), x, num2cell(x))
is an if statement within an anonymous function that calls num2cell if any sub element is a vector

How can I extract n elements from each m-by-m window of a matrix without using loops in MATLAB?

I have a matrix and 2 parameters. The first parameter n is the number of elements to be selected. The second is the window size m.
I want to select n number of elements from every m-by-m window from the matrix. As a result we will have a p-by-q cell array where p is matrix_height/m and q is matrix_width/m.
Each element of the cell array contains the n greatest numbers from the corresponding window. It does not necessarily need to be a cell array, it can be anything that will store the necessary data.
One way to do this is by first finding all the unique m-by-m submatrices of your matrix using the function IM2COL, then sorting each column in descending order using the function SORT, and finally extracting the top n rows. If your initial matrix is A and your output matrix is B, this is what it would look like:
B = sort(im2col(A,[m m],'distinct'),1,'descend');
B = B(1:n,:); %# Get the top n values
Note that B will be an n-by-m^2 matrix. If you want to turn this into a p-by-q cell array, you can do this using the functions NUM2CELL and RESHAPE:
nBlocks = ceil(size(A)./m); %# The number of blocks in each dimension
B = reshape(num2cell(B,1),nBlocks(1),nBlocks(2));
EDIT:
If you also want to get the indices of each value with respect to the input matrix A, that is a bit more complicated. You can do it by getting the second output from SORT, which in this case will be the linear indices of the values within each m-by-m submatrix. You can convert these to subscripts using the function IND2SUB, then shift the row and column indices to account for the position of each m-by-m block:
[B,index] = sort(im2col(A,[m m],'distinct'),1,'descend');
B = B(1:n,:); %# Get the top n values
index = index(1:n,:); %# Get the top n values
[r,c] = ind2sub([m m],index); %# Convert linear indices to subscripts
nBlocks = size(A)./m; %# The number of blocks in each dimension
r = r+repmat(0:m:(nBlocks(1)-1)*m,n,nBlocks(2)); %# Shift the row indices
c = c+kron(0:m:(nBlocks(2)-1)*m,ones(n,nBlocks(1))); %# Shift the column indices
And now you can collect the row indices, column indices, and values together into a cell array using the functions MAT2CELL and RESHAPE:
B = mat2cell([r(:) c(:) B(:)],n.*ones(1,size(B,2)));
B = reshape(B,nBlocks(1),nBlocks(2));
Alternatively, you can create a structure array instead of a cell array using the functions NUM2CELL, STRUCT, and RESHAPE:
B = struct('rowIndices',num2cell(r,1),...
'colIndices',num2cell(c,1),...
'values',num2cell(B,1));
B = reshape(B,nBlocks(1),nBlocks(2));
NOTE:
The function IM2COL will pad partial blocks with zeroes in the event that a dimension of A is not an even multiple of m. If any of this zero-padding appears in the top n values for a block, one or both of the corresponding row and column indices will be out of range (i.e. have a value larger than the size of that dimension for the matrix A). Thus by checking that the row and column indices are in range you can make sure you are not including any of the zero-padding in your subsequent analysis.

In MATLAB how can I set all the values of a matrix to string?

I have a MATLAB matrix, that is 1000x4, to use as an input for a function. I need to add a new column that contains a certain string. So how can I make a new column where all the values are 'TEST'?
Since it's a little unclear what you want, here are some options:
To make a 1000-by-4 matrix where each row is 'TEST', you can use the function REPMAT:
M = repmat('TEST',1000,1);
To add 'TEST' to the end of each row of a 1000-by-4 matrix of characters, you can use the function STRCAT:
M = repmat('a',1000,4); %# Sample matrix filled with 'a'
M = strcat(M,'TEST'); %# Append 'TEST' to each row of M
If your 1000-by-4 matrix is a numeric array instead of an array of characters, you will have to use cell arrays to combine the different types of data. Here's one way you can do this:
M = rand(1000,4); %# A matrix of random numeric values
M = num2cell(M,2); %# Put each row of M in a cell, making
%# a 1000-by-1 cell array
M(:,2) = {'TEST'}; %# Add a second column to the cell array,
%# where each cell contains 'TEST'
A matrix cannot contain a string (like 'TEST').
You need to use a cell array
If this is an existing matrix M of cell strings,
M(:,end+1) = {'TEST'};