Allow non-numeric entries in matrix in MATLAB - matlab

I wrote a code that replaces non-numeric values in the matrix by some number.
Now, to test it I would like to allow MATLAB to accept non-numeric entries.
My code starts with prompt:
matrix_input = input('Please enter the matrix: x=');
If I enter something like [1,2,3;4,5,?], MATLAB gives an error: Unbalanced or unexpected parenthesis or bracket. Since all brackets seem to be balanced, I assume this is due to non-numeric entry. Is it possible to make MATLAB allow non-numeric entries?

You need a cell array. Each cell of a cell array can hold any type of data. Curly braces are used to create a cell array like this:
cell_array = {1, 2, 3; '4', '?', 6};
If you use regular braces to access an element in a cell array you get a cell. If you use curly braces you get the contents of the cell. It's this difference that tends to catch people out with cell arrays.
cell_array(1) % Returns a 1x1 cell containing the value 1.
cell_array{1} % Returns 1
EDIT
Out of curiosity, what code are you using to replace the non-numeric values? For a cell array I came up wit the following:
idx = cellfun(#isnumeric, cell_array);
cell_array(~idx) = {NaN};
matrix = cell2mat(cell_array);
As mentioned in the comments, you could also use a struct array:
struct_array = struct('v', {1, 2, 3; '4', '?', 6});
This would create an array of structures where the field v contains the value. However, I can't think of a neat way to perform the replacement at the minute.

Related

How to access and modify a particular value in a cell array in MATLAB? [duplicate]

C is a cell consisting of some vectors:
C = {[1, 2], [2, 3]};
I want to read the first entry of the first vector in C. But I can not use the following:
C{1}[2]
I get the following error:
Error: Unbalanced or unexpected parenthesis or bracket.
How can I make it read the value?
You can access individual elements of matrices in cell array like this:
C{n,m}(ii,jj);
This will give you element (ii,jj) of the matrix at index (n,m) of the cell array.
Hence, for your particular example,
val = C{1,1}(1,1) (or val = C{1}(1))
will assign the value of the first element of the first vector in the cell array to the variable val.

Printing progress in command window

I'd like to use fprintf to show code execution progress in the command window.
I've got a N x 1 array of structures, let's call it myStructure. Each element has the fields name and data. I'd like to print the name side by side with the number of data points, like such:
name1 number1
name2 number2
name3 number3
name4 number4
...
I can use repmat N times along with fprintf. The problem with that is that all the numbers have to come in between the names in a cell array C.
fprintf(repmat('%s\t%d',N,1),C{:})
I can use cellfun to get the names and number of datapoints.
names = {myStucture.name};
numpoints = cellfun(#numel,{myStructure.data});
However I'm not sure how to get this into a cell array with alternating elements for C to make the fprintf work.
Is there a way to do this? Is there a better way to get fprintf to behave as I desire?
You're very close. What I would do is change your cellfun call so that the output is a cell array instead of a numeric array. Use the 'UniformOutput' flag and set this to 0 or false.
When you're done, make a new cell array where both the name cell array and the size cell array are stacked on top of each other. You can then call fprintf once.
% Save the names in a cell array
A = {myStructure.name};
% Save the sizes in another cell array
B = cellfun(#numel, {myStructure.data}, 'UniformOutput', 0);
% Create a master cell array where the first row are the names
% and the second row are the sizes
out = [A; B];
% Print out the elements side-by-side
fprintf('%s\t%d\n', out{:});
The trick with the third line of code is that when you unroll the cell array using {:}, this creates a comma-separated list unrolled in column-major format, and so doing out{:} actually gives you:
A{1}, B{1}, A{2}, B{2}, ..., A{n}, B{n}
... which provides the interleaving you need. Therefore, providing this order into fprintf coincides with the format specifiers that are specified and thus gives you what you need. That's why it's important to stack the cell arrays so that each column gives the information you need.
Minor Note
Of course one should never forget that one of the easiest ways to tackle your problem is to just use a simple for loop. Even though for loops are considered bad practice, their performance has come a long way throughout MATLAB's evolution.
Simply put, just do this:
for ii = 1 : numel(myStructure)
fprintf('%s\t%d\n', myStructure(ii).name, numel(myStructure(ii).data));
end
The above code is arguably more readable in comparison to what we did above with cell arrays. You're accessing the structure directly rather than having to create intermediate variables for the purpose of calling fprintf once.
Example Run
Here's an example of this running. Using the data shown below:
clear myStructure;
myStructure(1).name = 'hello';
myStructure(1).data = rand(5,1);
myStructure(2).name = 'hi';
myStructure(2).data = zeros(3,3);
myStructure(3).name = 'huh';
myStructure(3).data = ones(6,4);
I get the following output after running the printing code:
hello 5
hi 9
huh 24
We can see that the sizes are correct as the first element in the structure is simply a random 5 element vector, the second element is a 3 x 3 = 9 zeroes matrix while the last element is a 6 x 4 = 24 ones matrix.

subindex into a cell array of strings

I have a 6 x 3 cell (called strat) where the first two columns contain text, the last column has either 1 or 2.
I want to take a subset of this cell array. Basically select only the rows where the last column has a 1 in it.
I tried the following,
ff = strat(strat(:, 3), 1:2) == 1;
The error message is,
Function 'subsindex' is not defined for values of class 'cell'.
How can I index into a cell array?
Cell arrays are accessed through braces {} instead of parentheses (). Then, as a 2nd subtlety, when pulling values out of a cell arrays, you need to gather them...for numerics you gather them into regular arrays using [] and for strings you gather them into a new cell array using {}. Confusing, eh?
ff = { strat{ [strat{:,3}]==1 , 1:2 } };
Gathering into cell arrays this way can often give the wrong shape when you're done. So, you might try something like this
ind = find([strat{:,3}]==1); %find the relevant indices
ff = {{strat{ind,1}; strat{ind,2}}'; %this will probably give you the right shape

matlab: Adding square brackets to all individual numerical values within cell arrays

I wish to add a cell array (Ma) into another cell array. However both needs to be of the same format (individual cells in square brackets).
For instance I have an array..
Ma{1,:}.'
ans =
Columns 1 through 8
'83.6' '85.2' '91' '87.9' '91.8' '86.3' '90.6' '90.2'
How do i add square brackets to all the numerical values of very individual cells?
Below is what i wish to obtain, it is also a 1x8 cell.
ans =[83.6] [85.2] [91] [87.9] [91.8] [86.3] [90.6] [90.2]
Your cell values are strings (you can tell by the quote marks ' surrounding the values). You wish to convert them to numerical values ("add square brrckets around them" as you put it).
To convert string to double you can use str2double command:
M = str2double( M{1,:} );
You don't need to add the square brackets yourself. This just means that it is a numerical value in a cell.
In order to achieve this you should do the following, using both the num2cell as str2double functions:
newM = num2cell(str2double(Ma{1,:}))

Substrings from a Cell Array in Matlab

I'm new to MATLAB and I'm struggling to comprehend the subtleties between array-wise and element wise operations. I'm working with a large dataset and I've found the simplest methods aren't always the fastest. I have a very large Cell Array of strings, like in this simplified example:
% A vertical array of same-length strings
CellArrayOfStrings = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'};
I'm trying to extract an array of substrings, for example:
'a1'
'b1'
'c1'
'd1'
I'm happy enough with an element-wise reference like this:
% Simple element-wise substring operation
MySubString = CellArrayOfStrings{2}(3:4); % Expected result is 'b1'
But I can't work out the notation to reference them all in one go, like this:
% Desired result is 'a1','b1','c1','d1'
MyArrayOfSubStrings = CellArrayOfStrings{:}(3:4); % Incorrect notation!
I know that Matlab is capable of performing very fast array-wise operations, such as strcat, so I was hoping for a technique that works at a similar speed:
% An array-wise operation which works quickly
tic
speedTest = strcat(CellArrayOfStrings,'hello');
toc % About 2 seconds on my machine with >500K array elements
All the for loops and functions which use behind-the-scenes iteration I have tried run too slowly with my dataset. Is there some array-wise notation that would do this? Would somebody be able to correct my understanding of element-wise and array-wise operations?! Many thanks!
I can't work out the notation to reference them all in one go, like this:
MyArrayOfSubStrings = CellArrayOfStrings{:}(3:4); % Incorrect notation!
This is because curly braces ({}) return a comma-separated list, which is equivalent to writing the contents of these cells in the following way:
c{1}, c{2}, and so on....
When the subscript index refers to only one element, MATLAB's syntax allows to use parentheses (()) after the curly braces and further extract a sub-array (a substring in your case). However, this syntax is prohibited when the comma separated lists contains multiple items.
So what are the alternatives?
Use a for loop:
MyArrayOfSubStrings = char(zeros(numel(CellArrayOfStrings), 2));
for k = 1:size(MyArrayOfSubStrings, 1)
MyArrayOfSubStrings(k, :) = CellArrayOfStrings{k}(3:4);
end
Use cellfun (a slight variant of Dang Khoa's answer):
MyArrayOfSubStrings = cellfun(#(x){x(3:4)}, CellArrayOfStrings);
MyArrayOfSubStrings = vertcat(MyArrayOfSubStrings{:});
If your original cell array contains strings of a fixed length, you can follow Dan's suggestion and convert the cell array into an array of strings (a matrix of characters), reshape it and extract the desired columns:
MyArrayOfSubStrings =vertcat(CellArrayOfStrings{:});
MyArrayOfSubStrings = MyArrayOfSubStrings(:, 3:4);
Employ more complicated methods, such as regular expressions:
MyArrayOfSubStrings = regexprep(CellArrayOfStrings, '^..(..).*', '$1');
MyArrayOfSubStrings = vertcat(MyArrayOfSubStrings{:});
There are plenty solutions to pick from, just pick the one that fits you most :) I think that with MATLAB's JIT acceleration, a simple loop would be sufficient in most cases.
Also note that in all my suggestions the obtained cell array of substrings cell is converted into an array of strings (a matrix). This is just for the sake of the example; obviously you can keep the substrings stored in a cell array, should you decide so.
cellfun operates on every element of a cell array, so you could do something like this:
>> CellArrayOfStrings = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'};
>> MyArrayofSubstrings = cellfun(#(str) str(3:4), CellArrayOfStrings, 'UniformOutput', false)
MyArrayofSubstrings =
'a1'
'b1'
'c1'
'd1'
If you wanted a matrix of strings instead of a cell array whose elements are the strings, use char on MyArrayOfSubstrings. Note that this is only allowed when each string is the same length.
You can do this:
C = {'aaa123'; 'bbb123'; 'ccc123'; 'ddd123'}
t = reshape([C{:}], 6, [])'
t(:, 3:4)
But only if your strings are all of equal length I'm afraid.
You can use char to convert them to a character array, do the indexing and convert it back to cell array
A = char(CellArrayOfStrings);
B = cellstr(A(:,3:4));
Note that if strings are of different lengths, char pads them with spaces at the end to create the array. Therefore if you index for a column that is beyond the length of one of the short strings you may receive some space characters.