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

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))

Related

MATLAB: Filter struct based on column value

i'm new to matlab, too used to python and having difficulty finding a way to filter a struct similar to how i can filter a pandas dataframe in python based on condition.
Matlab
a = arrayfun(#(x) x.value ==10, Data);
Data_10 = Data(a);
Error using arrayfun Non-scalar in Uniform output, at index 1, output
1. Set 'UniformOutput' to false.
How i would do so in python:
Data_10 = Data[Data.value == 10]
Try this:
Data_10 = zeros(size(Data.value));
Data_10(Data.value==10) == 10;
This should write into your array Data_10 the value 10 into each position, that has a 10 in Data and leave the rest as 0.
I am not sure if I fully understood your question. Here is my underestanding:
You want to filter certain values of an matrix.
Lets imagine we have a Matrix A filled with values. You want to filter values smaller than lowthresh = 0 and greater than upthresh = 5.
A = [3 6 -2.4 1; 0 34 4.76 0.5; 84 3 2.32 4; 1 -1 2 3.99];
lowthresh = 0;
upthresh = 5;
A(A<lowthresh | A>upthresh) = NaN; % Nan is a good flag
Output:
A =
3.0000 NaN NaN 1.0000
0 NaN 4.7600 0.5000
NaN 3.0000 2.3200 4.0000
1.0000 NaN 2.0000 3.9900
Having substituted your values you can do some basic functions ignoring NaNs:
For instance average:
mean(A,'omitnan')
ans =
1.3333 3.0000 3.0267 2.3725
I hope this adresses your question. Notice, that you can do this for any statement, that returns a boolean (isnan(), ... ) even if the boolean does not have anything to do with the matrix at all.
Lets say we have 2 matrizes that have the same size but different numbers:
A =
1 1 0
1 1 0
0 0 0
B =
0 0 0
0 0 0
0 0 0
We can easily say:
B(A==1) = 2
B =
2 2 0
2 2 0
0 0 0
I hope it helped a bit,
cheers Pablo

Replace non-NaN values with their row indices within matrix

I have the 4x2 matrix A:
A = [2 NaN 5 8; 14 NaN 23 NaN]';
I want to replace the non-NaN values with their associated indices within each column in A. The output looks like this:
out = [1 NaN 3 4; 1 NaN 3 NaN]';
I know how to do it for each column manually, but I would like an automatic solution, as I have much larger matrices to handle. Anyone has any idea?
out = bsxfun(#times, A-A+1, (1:size(A,1)).');
How it works:
A-A+1 replaces actual numbers in A by 1, and keeps NaN as NaN
(1:size(A,1)).' is a column vector of row indices
bsxfun(#times, ...) multiplies both of the above with singleton expansion.
As pointed out by #thewaywewalk, in Matlab R2016 onwards bsxfun(#times...) can be replaced by .*, as singleton expansion is enabled by default:
out = (A-A+1) .* (1:size(A,1)).';
An alternative suggested by #Dev-Il is
out = bsxfun(#plus, A*0, (1:size(A,1)).');
This works because multiplying by 0 replaces actual numbers by 0, and keeps NaN as is.
Applying ind2sub to a mask created with isnan will do.
mask = find(~isnan(A));
[rows,~] = ind2sub(size(A),mask)
A(mask) = rows;
Note that the second output of ind2sub needs to be requested (but neglected with ~) as well [rows,~] to indicate you want the output for a 2D-matrix.
A =
1 1
NaN NaN
3 3
4 NaN
A.' =
1 NaN 3 4
1 NaN 3 NaN
Also be careful the with the two different transpose operators ' and .'.
Alternative
[n,m] = size(A);
B = ndgrid(1:n,1:m);
B(isnan(A)) = NaN;
or even (with a little inspiration by Luis Mendo)
[n,m] = size(A);
B = A-A + ndgrid(1:n,1:m)
or in one line
B = A-A + ndgrid(1:size(A,1),1:size(A,2))
This can be done using repmat and isnan as follows:
A = [ 2 NaN 5 8;
14 NaN 23 NaN];
out=repmat([1:size(A,2)],size(A,1),1); % out contains indexes of all the values
out(isnan(A))= NaN % Replacing the indexes where NaN exists with NaN
Output:
1 NaN 3 4
1 NaN 3 NaN
You can take the transpose if you want.
I'm adding another answer for a couple of reasons:
Because overkill (*ahem* kron *ahem*) is fun.
To demonstrate that A*0 does the same as A-A.
A = [2 NaN 5 8; 14 NaN 23 NaN].';
out = A*0 + kron((1:size(A,1)).', ones(1,size(A,2)))
out =
1 1
NaN NaN
3 3
4 NaN

Number of Non-NaN Rows in a 3D Matrix MATLAB

I have a 3D matrix with NaN padded to obtain equal number of rows in each 2D matrix i.e each (:,:,ind). Now i need to find the number of actual non-NaN rows in each (:,:,ind).
A simple example of what I need:
% Input:
A(:,:,1) = [ 1 1;
2 2;
NaN NaN];
A(:,:,2) = [ 2 2;
NaN NaN;
NaN NaN];
% Function call:
B = callingfunction(A);
% Output:
B = [2 1] % Number of Non-NaN rows in each 2D Matrix
Approach #1
B = squeeze(sum(all(~isnan(A),2),1))
Here's the build-up process to get a hang of it -
Start>>> Given A:
>> A
A(:,:,1) =
1 1
2 2
NaN NaN
A(:,:,2) =
2 2
NaN NaN
NaN NaN
1) Detect all non-NaN positions:
>> ~isnan(A)
ans(:,:,1) =
1 1
1 1
0 0
ans(:,:,2) =
1 1
0 0
0 0
2) Find rows with all non-Nan elements:
>> all(~isnan(A),2)
ans(:,:,1) =
1
1
0
ans(:,:,2) =
1
0
0
3) Sum up the number of all such rows:
>> sum(all(~isnan(A),2),1)
ans(:,:,1) =
2
ans(:,:,2) =
1
4) Get the result as a 1D array:
>> squeeze(sum(all(~isnan(A),2),1))
ans =
2
1
Approach #2
B = squeeze(sum(~any(isnan(A),2),1))
Use the same break-up-my-code-into-pieces process as listed earlier here and in all your future MATLAB codes and all past MATLAB codes that didn't make sense to do so now!

Taking the mean of a matrix with NaN's in Matlab [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Dealing with NaN’s in matlab functions
Is there a one line command that allows you to take the elementwise average of a matrix (ignoring NaN's) in Matlab? For example,
>> A = [1 0 NaN; 0 3 4; 0 NaN 2]
A =
1 0 NaN
0 3 4
0 NaN 2
So the mean(A) should equal (1+3+2+4+0+0+0)/7 = 1.4286
Also, I don't have access to the stats toolbox so I cannot use nanmean()
You can use isnan() to filter out the unwanted elements:
mean(A(~isnan(A)))
nanmean
Performs just like mean, but ignoring nans.
For example:
>> A = [1 0 NaN; 0 3 4; 0 NaN 2]
A =
1 0 NaN
0 3 4
0 NaN 2
>> nanmean(A)
ans =
0.333333333333333 1.5 3
>> nanmean(A,2)
ans =
0.5
2.33333333333333
1
>> nanmean(A(:))
ans =
1.42857142857143

Removing NaN elements from a matrix

There is one NaN element per row, I want to remove it.
A=[NaN 1 2;
3 NaN 4;
NaN 5 6];
The desired output is:
[1 2;
3 4;
5 6]
A = [NaN 1 2 ; 3 NaN 4; NaN 5 6]
sz = size(A);
B = reshape(A', size(A,1)*size(A,2), 1);
B(isnan(B)) = [];
B = reshape(B, sz(2)-1, sz(1))'
I thought it could be done in one line, but I was wrong. See solution below:
Given (added row helps me debug my indexing below):
>> A = [NaN 1 2 ; 3 NaN 4; NaN 5 6; 7 8 NaN]
A =
NaN 1 2
3 NaN 4
NaN 5 6
7 8 NaN
Then:
>> Atrans = A';
>> B = reshape( Atrans(~isnan(Atrans)) ,[],size(Atrans,2))'
B =
1 2
3 4
5 6
7 8
Incidentally, the Matlab idiom of performing a simple logical check on an array within an logical indexing operation is very common and incredibly useful. The archetypical example is:
>> x(x>0) %This returns a 1D column vector of all values of x
%which are greater than 0, regardless of the initial
%size of x. Multidimensional inputs are unwrapped
%column-first
Everything else above is size and dimension handling.
Here it is - please note that the code is not robust. It assumes that indeed in every row there is a NaN element.
While it is not a vectorized solution, it has other advantages - like a clear code.
for i=1:size(A,1)
x = A(i,:);
x(isnan(x)) = [];
B(i,:) = x;
end
B
B =
1 2
3 4
5 6