How to convert string cell array to int and NaN in Matlab? - matlab

I have a string cell array that contains a mix of numbers and None values. I want to convert the None into NaN and numbers into int.
x = {'23','3','None'}
new_x = {23,3,NaN}

You can try cellfun with str2double, e.g.,
>> cellfun(#str2double,x,"UniformOutput", false)
ans =
{
[1,1] = 23
[1,2] = 3
[1,3] = NaN
}
or another option (thank #Luis Mendo)
>> num2cell(str2double(x))
ans =
{
[1,1] = 23
[1,2] = 3
[1,3] = NaN
}

Related

Octave: A(~isnan(A)) results vector containing NaNs?

May be I don't get a basic thing, but I recently discovered this behaviour, and by now I don't understand what's happening:
A = [3 NaN .12 NaN NaN 9]
A =
3 NaN 0.12 NaN NaN 9
>> nansA = isnan(A)
nansA =
0 1 0 1 1 0
>> nnansA = ~isnan(A)
nnansA =
1 0 1 0 0 1
>> nnansA1 = ~isnan(A(1:end))
nnansA1 =
1 0 1 0 0 1
>> nnansA2 = ~isnan(A(2:end))
nnansA2 =
0 1 0 0 1
>> AnnansA1 = A(~isnan(A(1:end)))
AnnansA1 =
3 0.12 9
>> **AnnansA2 = A(~isnan(A(2:end)))
AnnansA2 =
NaN NaN
What is happening here?
Does this happen in Matlab too?
I would expect something like ... AnnansA2 = 0.12 9
What is happening here is that you're indexing A with a logical array of a different size and expect the indexing to not start at the beginning.
Let's deconstruct, from the inside:
>> A = [3 NaN .12 NaN NaN 9]
A =
3.0000 NaN 0.1200 NaN NaN 9.0000
>> # B a new array, with 5 elements (A had 6 elements)
>> B = A(2:end)
B =
NaN 0.1200 NaN NaN 9.0000
>> # mask is a logical array with 5 elements, like B, and not 6, like A.
>> # mask knows nothing about A or B. It simply "selects" (indexes) the
>> # 1st, 3rd, and 4th element of any array.
>> mask = isnan (B)
mask =
1 0 1 1 0
>> # Invert the mask, now "selects" the 2nd and 5th element of any array.
>> not_mask = ! mask
not_mask =
0 1 0 0 1
>> # Return the 2nd and 5th element of A.
>> A(not_mask)
ans =
NaN NaN
I think you're surprised by the behaviour because you expect that A(2:end) "remembers" that it comes from A to index the right "region" of A. This does not happen, it's just a logical array that "remembers" nothing from which array it came (and often used to index different arrays).
As a side note, and answering one of your questions, Matlab behaviour is the same as Octave.
Anyway, what you're doing looks a bit odd, maybe do this instead:
A(! isnan (A))(2:end)
You're off by one.
You need to do AnnansA2 = A(~isnan(A(1:end)))
If you want to return only the last two non-nans, index the result like;
ananIdxs = ~isnan(A)
AnnansA2 = A(ananIdxs(2:end))

Replace Nan by a number in a cell array with Matlab

a = { [5 5 5 6 ] [ Nan Nan Nan Nan]; [ 7 8 8 8 ] [1 2 3 5] }
i want to replace a{1,2} by [1 1 1 1 ]
Is it possible? because I tried this function:
function k = non(a)
[l ,c ] = size(a);
for i= 1 : l
for j =1 : c
if a{i,j} == [ NaN NaN NaN NaN ]
k{i,j} = [ 1 1 1 1]
else
k{i,j} = a{i,j} ;
end
end
end
end
but it doesn't work.
You can define the following simple function:
function matrix = replace_nan(matrix, value)
matrix(isnan(matrix)) = value;
end
and then use cellfun to execute it over all elements of your cell array (I have generalized your problem slightly by allowing you to define value as the number to replace the NaN with, and making the elements variable length):
>> a = {[ 3 NaN] [NaN NaN NaN] [1 2 3 4 5 NaN 0 NaN]};
>> value = 1; %% the value to replace the NaN with
>> z = cellfun(#replace_nan, a, repmat( {value}, size(a,1), size(a,2)) , 'UniformOutput', 0);
>> z{1}
ans =
3 1
>> z{2}
ans =
1 1 1
>> z{3}
ans =
1 2 3 4 5 1 0 1
A few comments on the use of cellfun here: cellfun takes a function, in this case replace_nan, and a cell array, in this case a, and iterates the function call to replace_nan(). If replace_nan were a single argument function, we could say cellfun(#replace_nan, a), but the way I defined it, the function takes two arguments. The way to specify that in cellfun is to provide a second cell array with the value arguments. That is the repmat({1},size(a,1),size(a,2)) which creates a second cell array with the same dimensions as a, but filled with 1's.
EDIT: The comment discussion brings up a good point: you cannot use == to test for NaN, you must use MATLAB's isnan() function.
>> [NaN NaN] == [NaN NaN]
ans =
0 0
>> isnan( [NaN NaN] )
ans =
1 1
Or even shorter this way:
a(cellfun(#(cell) any(isnan(cell(:))),a))={[1 1 1 1]};

Most efficient way of unpacking cell array with one nested level

I am using cellfun with UniformOutput set to 0. This applies the specified function to each cell, returning the output as a cell in a cell array.
Each of these cells are a cell array with 1 row and 6 columns. For example, a cell array with two cells:
ans =
{
[1,1] =
{
[1,1] = 1
[1,2] = 1
[1,3] = 1
[1,4] = 9
[1,5] = hello
[1,6] = 3
}
[2,1] =
{
[1,1] = 1
[1,2] = 1
[1,3] = 1
[1,4] = -33
[1,5] = world
[1,6] = 3
}
}
I would like to know the most efficient way to convert this into the 2x6 cell array, i.e.:
ans =
{
[1,1] = 1
[1,2] = 1
[1,3] = 1
[1,4] = 9
[1,5] = hello
[1,6] = 3
[2,1] = 1
[2,2] = 1
[2,3] = 1
[2,4] = -33
[2,5] = world
[2,6] = 3
}
Use cat(1,data{:}) which uses the comma separated list data{:} to unpack the cell and cat to concatenate.

Matlab: convert NaNs from xlsread to blank

The SOM 2.1 Toolbox is having issues with NaNs.
The code below only works for cell arrays and not double precision arrays of numbers.
[D, headers] = xlsread('Workbook2.xlsx', 'Sheet1', 'A2:BE101');
idx = isnan(D);
D(idx) = {[]}
The following error occurred converting from cell to double:
Error using double
Conversion to double from cell is not possible.
Any suggestions?
First of all you cannot do this : D(idx) = {[]} if you have a double array.
Then, isnan does not work with cell arrays. Consider the following cell:
a = cell(2,2);
a{1,1} = NaN;
a{1,2} = 2;
a{2,1} = NaN;
a{2,2} = 'hi';
you cab either use isnan element-wise (on each element of a cell), like:
isnan(a{1,1})
=
1
or when all the elements of the cell are the same type, you can use cell2mat function first to convert it and then check all the elements with isnan at once, such as:
a = cell(2,2);
a{1,1} = NaN;
a{1,2} = 2;
a{2,1} = NaN;
a{2,2} = 3;
c=cell2mat(a)
c =
NaN 2
NaN 3
isnan(c)
ans =
1 0
1 0
So the answer depends on the xls sheet that you have, and the type of the data. You may use one of the mentioned options.
Update
An example if you are using double array:
>> D = rand(2,3);
>> D(2,2) = NaN
D =
0.8147 0.1270 0.6324
0.9058 NaN 0.0975
>> idx = isnan(D)
idx =
0 0 0
0 1 0
>> D(idx) = []
D =
Columns 1 through 3
0.8147 0.9058 0.1270
Columns 4 through 5
0.6324 0.0975
Of course, it breaks the structure of the matrix into a vector.

Search particular matrix in cell array

So, I have this cell array contains n x 2 matrix in each cell. Here is the sample data :
[16 17;17 17]
<6x2 double>
<52x2 double>
[17 17;17 18]
[17 18;17 17]
What I am going to do is eliminate the duplicated matrix (matrices with same values or reversed values). in this case is [17 18; 17 17] (5th row), because we already have [17 17; 17 18] (4th row)
I tried using unique function but it says that the function just worked for strings. I also tried to find it with cellfun like this
cellfun(#(x) x==whatToSearch, lineTraced, 'UniformOutput', false)
but it says 'Matrix dimension must agree'
Thanks in advance.
Here is a solution. Given a m x 1 column cell array C of matrices, this code deletes the equivalent duplicates. (Here it will delete the 4th and 5th matrices, which are equivalent to the 1st).
C{1} = magic(3);
C{2} = magic(4);
C{3} = magic(5);
C{4} = C{1};
C{5} = flipud(C{1});
myEq = #(A,B) isequal(A,B) | isequal(A,flipud(B)); %// equivalence operator tests for same or up-down flipped matrix
C = C(:); %// ensure the cell array is a column
Crep = repmat(C,1,size(C,1)); %// repeat cell array along rows to get a square
comp = cellfun(myEq,Crep,Crep'); %'//get a comparison matrix by comparing with transpose
comp = tril(comp) - eye(size(comp)); %// ignore upper triangle and diagonal
idx = find( sum(comp,2)==0 ); %// get index of matrices we want to keep
result = C(idx); %// get result
The output is deletes the 4th and 5th matrices, leaving the first three magic matrices:
>> result
result =
[3x3 double] [4x4 double] [5x5 double]
>> result{1}, result{2}, result{3}
ans =
8 1 6
3 5 7
4 9 2
ans =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
ans =
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
Here's code that does what you want.
mydup = rand(5,2);
mycell = {mydup;mydup;rand(7,2);rand(3,2);rand(5,2)}
myNewCell = trimCell(mycell)
Where trimCell is the function below:
function myNewCell = trimCell(myCell)
exclude = false(size(myCell));
for iter = 1:size(myCell,1)
toCompare = myCell{iter};
comparisons = cellfun(#(x) all(size(x)==size(toCompare)) && myEquals(x, toCompare),myCell);
% comparisons has at least 1 true in it, because toCompare==toCompare
exclude(iter) = sum(comparisons)>1;
end
myNewCell = myCell(~exclude);
end
function boolValue = myEquals(x,y)
assert(all(size(x)==size(y)));
boolValue = true;
for iter = 1:size(x,1)
thisRow = all(sort(x(iter,:))==sort(y(iter,:)));
boolValue = boolValue && thisRow;
if ~boolValue
return
end
end
end
Basically, what this function does, is, for each matrix in the cell it checks first if the sizes are equal. If the sizes aren't equal, then we know the matrices aren't equal, even if we reorder the rows.
If they are the same size, then we need to check if they're equal after row reordering. That's accomplished by the function myEquals which goes through row by row and sorts the rows before comparing them. It exits with false on the first row it finds that is not equal after reordering.
Hope this helps,
Andrew