first non NaN element value and index in matlab - matlab

I want to obtain value and index of first non-NaN element from each column of a matrix in the matlab.
In a separate problem--- There are few columns that does not have NaN. So in that case-- I would like to extract value and index of first non-NaN element from each column and otherwise first element of each column if column does not contain NaN.
Can anybody help regarding these two problems?

The index is easily obtained with the second output of max. The value can be found from that index using sub2ind or computing the corresponding linear index manually.
To return a different index in columns that contain all NaN, use the first output of max to detect that situation and change the result for those columns.
Let x denote your matrix. Then:
[m, index] = max(~isnan(x), [], 1);
value = x(index + (0:size(x,2)-1)*size(x,1));
%// or equivalently x(sub2ind(size(x), index, 1:size(x,2)))
index(~m) = size(x, 1); %// return last index for columns that have all NaN
Example
x = [ 8 NaN 3 NaN
NaN 4 5 NaN];
produces
index =
1 2 1 2
value =
8 4 3 NaN

Related

How can I get the values of non-NAN elements in a Matrix?

I have a huge matrix for which I need the row, column and values of non-NAN elements.
This works when I have zero (instead of NAN) and non-zero elements:
[rwpRow, rwpCol, rwpVal] = find( zerotest )
But when I do this for NAN matrix, I get all 1 values.
[rwpRow, rwpCol, rwpVal] = find(~isnan(nantest))
How can I do this?
The input to find is a logical array which is 1 for all non-nan elements. That 1 is what you get and find does not "see" the actual values. You have to split that up into separate calls:
select=~isnan(nantest)
[rwpRow, rwpCol] = find(select)
rwpVal=nantest(select)
You can only get the rows and columns from the call to find since it finds the 1s in ~isnan(nantest). Get all the non NaN values in the matrix in another step:
[rwpRow, rwpCol] = find(~isnan(nantest));
vals = nantest(~isnan(nantest));

How do I construct an Esri grid?

I read a lot of information about this subject but I can't obtain a solution about my problem.
First, I have a file with 3 columns: X Y Z
In MATLAB, I did this:
data = load('data.txt');
X = data(:,1);
Y = data(:,2);
Z = data(:,3);
This file is like this:
7037 6032 3
7036 6028 5
7037 6029 4
7037 6030 3
7038 6031 6
7039 6031 2
7037 6033 7
And I want to obtain the following matrix from the above matrix:
5 NaN NaN NaN NaN NaN
NaN 4 3 NaN 3 7
NaN NaN NaN 6 NaN NaN
NaN NaN NaN 2 NaN NaN
The rules is that the first column Y(1) = min(Y) , the second column Y(2) = Y(1) + 1.
The first line is X(1) = min(X), X(2) = X(1) + 1. Essentially, the first column acts as a row index, the second column acts as a column index, and for each row and column pair, the third column gets mapped to a location in this matrix. As such, the output matrix will be like so: out(1,1)=X(1) Y(1) ; out(1,2) = X(1) Y(2)
At the start, I think about created a matrix out like so:
xr = sort(unique(X));
yr = sort(unique(Y));
a = length(xr);
b = length(yr);
out = NaN(a,b);
After, with a loop, put I place this data onto this out matrix, but this obviously doesn't work.
For more information on an Esri grid, here's a Wikipedia article about it. The example grid in that page is what I desire. http://en.wikipedia.org/wiki/Esri_grid
I now understand what you want. The link that you posted from Wikipedia is very useful. You are trying to build what is known as an Esri grid. Here is a pictorial representation found on Wikipedia:
What you are given is a N x 3 matrix where the first column denotes the row IDs of this matrix, the second row denotes the column IDs of this matrix, and the third column denotes the values at each pair of IDs. So for example, given the example above - specifically looking at the right of the figure, your text file could look like:
275 125 5
275 175 2
...
...
25 75 5
25 125 1
Each row consists of a row index, a column index and a value that maps to this location in the grid. You had the right approach in that you should use unique - specifically the third output. We need to obtain a unique ID for the first two columns of your data independently. Once we do this, I'm going to show you the very powerful accumarray function. We are basically going to use the unique IDs found in the previous step, and we use these to index into our grid and place each value that corresponds to each unique pair of row and column IDs into this grid. Therefore, your code is very simply:
data = load('data.txt');
%// Or you can do this for reproducing the results
%data = [7037 6032 3;
%7036 6028 5;
%7037 6029 4;
%7037 6030 3;
%7038 6031 6;
%7039 6031 2;
%7037 6033 7];
[~,~,id1] = unique(data(:,1));
[~,~,id2] = unique(data(:,2));
out = accumarray([id1 id2], data(:,3), [], [], NaN);
out produces the desired Esri grid, and we get:
out =
5 NaN NaN NaN NaN NaN
NaN 4 3 NaN 3 7
NaN NaN NaN 6 NaN NaN
NaN NaN NaN 2 NaN NaN
So how does this work? accumarray accepts in a matrix of row and column locations that you want to use to access the output. At each of the corresponding row and column locations, you provide a value that gets mapped to this bin. Now, by default accumarray sums up the values that get mapped to each bin, but I'm going to assume that your values in your text file are all unique in that only one value gets mapped to each row and column index. Therefore, we can certainly get away with the default behaviour, and so you'd specify a [] for this behaviour (fourth input). Therefore, we will use the last column of your matrix as the values that get put into this matrix, use the [] input to allow accumarray to infer the size of your matrix (third input), then any values that don't get mapped to anything, we will fill this in with NaN. We aren't going to sum anything.
With the above explanation, the code follows.

Creating new matrix out of one column by order of two other columns

So I have a matrix A, take as an example
4 6 3.5
3 6 -1
A = 5 2 0.7
4 3 1.2
I now want to use Matlab to make a matrix B out of the last column of A in a very specific way. The rows of B should be ordered by the first column of A (in ascending order) and the columns of B should be ordered (ascending) by the second column of A. This can give empty elements in B, which should be assigned NaN. Applied to the example above this gives
NaN NaN -1
B = NaN 1.2 3.5
0.7 NaN NaN
Note that the number of rows and columns in B depend on the number of unique elements in the first and second column of A respectively.
I have tried a few different things trying to be clever with Matlab indexing but so far no success..
You can use this method
[~,J1,K1] = unique(A(:,1));
[~,J2,K2] = unique(A(:,2));
sz = [numel(J1) numel(J2)];
B = nan(sz);
B(sub2ind(sz, K1, K2)) = A(:,3);
first use unique to gather the unique items and their indices in the original column. The size of B is determined by number of unique elements in first and second column of A.
Now use linear indexing (obtained using sub2ind) to put the values in third column in the right place.

Get even/odd indices of a matrix - MATLAB

I have following problem:
I have a given matrix of let's say 4x4.
How can I get the indices of the following combinations:
row odd and column odd
row odd and column even
row even and column odd
row even and column even
For example if I have the matrix:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
'row odd and column odd' would be the indices of 1, 3, 9, 11...
'row odd and column even' would be the indices of 2, 4, 10, 12...
'row even and column odd' would be the indices of 5, 7, 13, 15...
and 'row even and column even' would be indices of 6, 8, 14, 16...
Also, is it possible to combine those operations so e.g. I get the indices for 'row odd and column odd' and 'row even and column even'?
Thank you!
It's pretty easy to do with indexing:
Odd rows and odd columns
B = A(1:2:end, 1:2:end);
Odd rows and even columns
B = A(1:2:end, 2:2:end);
Even rows and odd columns
B = A(2:2:end, 1:2:end);
Even rows and even columns
B = A(2:2:end, 2:2:end);
The above assumes that you want the actual matrix values themselves. It's a bit confusing as your matrix elements are the same as linear indexing values themselves. If you want to determine the actual column major indices to access the matrix, you can generate a vector from 1 to N where N is the total number of elements in your matrix, then reshape this matrix into the desired size that you want. After, use the same logic above to get the actual linear indices:
N = numel(A);
B = reshape(1:N, size(A,1), size(A,2));
ind = B(1:2:end, 1:2:end); %// For odd rows, odd columns
%// Repeat for the other ones...
Now, given your comment, you want to create a new matrix that will store only these extracted matrix values while making all of the other elements zero. If you want to do this, simply pre-allocate a matrix of zeroes, then copy over those values to extract using the computed indices into the new matrix. In other words:
N = numel(A);
B = reshape(1:N, size(A,1), size(A,2));
ind = B(1:2:end, 1:2:end); %// For odd rows, odd columns - Change to suit your tastes
out = zeros(size(A));
out(ind(:)) = A(ind(:));
If you want to combine the indices like having odd row - odd column, and even row - even column, just compute two sets of indices, concatenate them into a single vector and do the same syntax like before. Therefore:
N = numel(A);
B = reshape(1:N, size(A,1), size(A,2));
ind = B(1:2:end, 1:2:end); %// For odd rows, odd columns
ind2 = B(2:2:end, 2:2:end); %// For even rows, even columns
ind = [ind(:); ind2(:)];
out = zeros(size(A));
out(ind) = A(ind);
Code
N = size(A,1); %// Get size of input matrix A
case1_ind = bsxfun(#plus,[1:2:N]',(0:N/2-1)*2*N)
case2_ind = case1_ind + N
case3_ind = case1_ind + 1
case4_ind = case3_ind + N
Note: These outputs are indices. So, to get the actual outputs, use these as indices.
To combine indices for case 1 and case 4, just concatenate -
case14comb_ind = [case1_ind ; case4_ind]
Edit :
%// To copy onto some other matrix of the same size as A, do this for case 1
new_matrix = zeros(size(A))
new_matrix(case1_ind(:)) = A(case1_ind(:))
Repeat this for the other cases too.

matrix get min values of a matrix before max values occurred

I was trying to get the min values of a matrix before the max values of the matrix occurred. I have two matrices: matrix data and matrix a. Matrix a is a subset of matrix data and is composed of the max values of matrix data. I have the following code but obviously doing something wrong.
edit:
Matrix a are the max values of matrix data. I derived it from:
for x=1:size(data,1)
a(x)=max(data(x,:));
end
a=a'
clear x
matrix b code:
for x=1:size(data,1)
b(x)=min(data(x,(x<data==a)));
end
b=b'
clear x
matrix data matrix a matrix b
1 2 3 4 4 1
6 5 4 7 7 4
9 6 12 5 12 6
I need all the min values that occurred before to matrix a occurred in matrix data
Short and simple:
[a,idxmax] = max(data,[],2);
b = arrayfun(#(ii) min(data(ii,1:idxmax(ii))), 1:size(data,1));
which is the same as
b=NaN(1,size(data,1)); % preallocation!
for ii=1:size(data,1)
b(ii) = min(data(ii,1:idxmax(ii)));
end
Ignore maximum itself
If you want minimum of everything really before (and not including the maximum), it's possible that the maximum is the first number, and you try taking minimum of an empty matrix. Solution then is to use cell output, which can be empty:
b = arrayfun(#(ii) min(data(ii,1:idxmax(ii)-1)), 1:size(data,1),'uni',false);
Replace empty cells with NaN
If you want to replace empty cells to Nan and then back to a matrix use this:
b(cellfun(#isempty,b))={NaN};
b=cell2mat(b);
or simply use the earlier version and replace b(ii) with NaN when it is equal to a(ii) same outcome:
b = arrayfun(#(ii) min(data(ii,1:idxmax(ii))), 1:size(data,1));
b(b'==a) = NaN
Example:
data=magic(4)
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
outputs:
a' = 16 11 12 15
b =
16 5 6 4
and
b =[1x0 double] [5] [6] [4]
for the 2nd solution using cell output and ignoring the maximum itself also.
And btw:
for x=1:size(data,1)
a(x)=max(data(x,:));
end
a=a'
clear x
can be replaced with
a=max(data,[],2);
It's not pretty but this is the only way I found so far of doing this kind of thing without a loop.
If loops are ok I would recommend Gunther Struyf answer as the most compact use of matlab's in-built array looping function, arrayfun.
Some of the transposition etc may be superfluous if you're wanting column mins instead of row...
[mx, imx] = max(data');
inds = repmat(1:size(data,2), [size(data,1),1]);
imx2 = repmat(imx', [1, size(data,2)]);
data2 = data;
data2(inds >= imx2) = inf;
min(data2');
NOTE: if data is not needed we can remove the additional data2 variable, and reduce the line count.
So to demonstrate what this does, (and see if I understood the question correctly):
for input
>> data = [1,3,-1; 5,2,1]
I get minima:
>> min(data2')
ans = [1, inf]
I.e. it only found the min values before the max values for each row, and anything else was set to inf.
In words:
For each row get index of maximum
Generate matrix of column indices
Use repmat to generate a matrix, same size as data where each row is index of maximum
Set data to infinity where column index > max_index matrix
find min as usual.