Matlab: convert NaNs from xlsread to blank - matlab

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.

Related

How to fill in missing NAN's?

I want to change [1 nan 1 2 2 nan nan 3 nan 4 nan nan 5] into [1 1.5 1 2 2 2 3 3 3.5 4 4 5 5]. If there is a single NAN, I want the NAN to be filled in with the average of the numbers before and after. If there is more than one NAN.
I want the NAN to be filled in with the nearest number.
So far, I only have the code to find the single NAN's:
max_x = x(:, 2);
min_x = x(:, 3);
for jj = 1:length(max_x)
for kk = 1:length(min_x)
if isnan(max_x(jj))
max_x (jj) = ((max_x(jj-1)+max_x(jj+1))/2);
elseif isnan (min_x(kk))
min_x (kk) = ((min_x(kk-1)+min_x(kk+1))/2);
end
end
end
How do I fill in the NAN's that aren't single?
Much thanks.
The title of this question is also nearly the answer - Fill in missing values using fillmissing.
A = [1 nan 1 2 2 nan nan 3 nan 4 nan nan 5];
B = fillmissing(A,'linear');
This function was introduced in R2016b.
The same logic can be implemented using interp1 and isnan.
idx = ~isnan( A );
x = 1:numel(A);
B = interp1( x(idx), A(idx), x, 'linear', 'extrap' );
Note that the extrapolation here gives slightly different behaviour for NaN values at each end of the input vectors.
A sample code:
% To paste in main .m file
A = [1 nan 1 2 2 nan nan 3 nan 4 nan nan 5]; % Input array
[A] = new_array(A) % Function to get a new array
% To paste in individual .m file as function
function [x]= new_array(x)
is_nan_ar = isnan(x); % Getting 0/1 array of nan elements
array_l = length(x); % Getting length of x array (just to do it only once)
for k = 1:array_l % Checking every element of input array whether it's...
if (k==1) && (is_nan_ar(k)==1) % First element and nan
kk = 2; % Initial index for searching the nearest non-nan element
while (isnan(is_nan_ar(kk))==1) % Checking elements for being nan
kk=kk+1; % Increasing index while we're searching
end
x(k) = x(kk); % Writing down the first not nan element
elseif (k==array_l) && (is_nan_ar(k)==1) % The same search for the last
kk = array_l-1; % Intial index
while (isnan(is_nan_ar(kk))==1) % Reversed search for not not nan
kk=kk-1;
end
x(k) = x(kk); % Writing down what we found
elseif (is_nan_ar(k)==1) % When we're checking not the first and not the last
s_r = 1; % Search range (1 element to the left/right)
while (is_nan_ar(k-s_r)==1) && (is_nan_ar(k+s_r)==1) %Looking for not nan
s_r = s_r+1; % Increasment of the range if didn't find
end
if (is_nan_ar(k-s_r)==0) && (is_nan_ar(k+s_r)==0) % Two non-nans are near
x(k) = (x(k-s_r)+x(k+s_r))/2;
elseif (is_nan_ar(k-s_r)==0) % Only one non-nan on the left
x(k) = x(k-s_r);
else % Only one non-nan on the right
x(k) = x(k+s_r);
end
end
end
end

MATLAB multidimensional array

I have been trying to use the multidimensional array function to store NxN vectors of length n in each (i,j) entry of a 3d matrix of NxNxn dimensions.
My code looks like:
a=zeros(N,N,n);
a(i,j,:)=v_ij; %here v is a vector of length n, which differs for each i,j
However when I try to extract each vector by typing e.g. a(1,1,:) I don't get a nice vector. Rather I get something like:
ans(:,:,1) = ..
ans(:,:,2) = ..
...
I don't understand why it says ans(:,:)...
That's because each vector v_ij is stored along the 3rd dimension of your matrix, so when you access a(1,1,:), you are looking for a multidimensional array consisting of every value at the location (1,1) along the 3rd dimension of a.
Let's consider a simple example:
N = 2;
n = 3;
a = zeros(N,N,n);
for k = 1:N
for l = 1:N
v_kl = randi([0 10],1,n);
a(k,l,:) = v_kl;
end
end
The randomly-generated matrix a is a 2x2x3 matrix that looks like this:
a(:,:,1) =
4 1
4 10
a(:,:,2) =
0 2
0 5
a(:,:,3) =
2 2
9 5
Therefore, using a(1,1,:) is equivalent to getting the element located at (1,1) for all 3 dimensions, here it would be 4,0 and 2.
Indeed, calling a(1,1,:) yields:
ans(:,:,1) =
4
ans(:,:,2) =
0
ans(:,:,3) =
2
Benoit_11's answer plus squeeze should work, but I would like to propose a different solution.
Rather than creating a NxNxn array, why not make it nxNxN?
N = 2;
n = 3;
a = zeros(n,N,N);
for p = 1:N
for q = 1:N
v_pq = randi([0 10],1,n);
a(:,p,q) = v_pq;
if (p == 1) && (q == 1)
v_pq %// display vector at a(:,1,1)
end
end
end
a
v_pq =
3 4 8
a =
ans(:,:,1) =
3 3
4 9
8 7
ans(:,:,2) =
5 6
10 1
9 5
Now the vectors are stored along the first dimension, so [3 4 8] shows up as the first column of ans(:,:,1). To access it you would use a(:,p,q) rather than a(p,q,:):
a(:,1,1)
ans =
3
4
8

summation values in structure in matlab

I have a 3-by-3-by-3 struct, struct, with fields bit. In each field I have two values. I want to divide values of each field by a summation of values of each field in dimension 3
for example if
struct(1,1,1).bit=[2, 3]
struct(1,1,2).bit=[4, 5]
struct(1,1,3).bit=[6, 7]
my new struct values must be for example:
newstruct(1,1,1).bit=[2/(2+4+6) , 3/(3+5+7)]
newstruct(1,1,2).bit=[4/(2+4+6) , 5/(3+5+7)]
newstruct(1,1,3).bit=[6/(2+4+6) , 7/(3+5+7)]
As it is MATLAB, you should possibly go with an nD array instead of the struct.
Yet, if you still want to do it this way, don't fear the good old for-loop:
for d1 = 1:size(in,1)
for d2 = 1:size(in,2)
d3sum = sum(cat(1,in(d1,d2,:).bit),1);
for d3 = 1:size(in,3)
out(d1,d2,d3).bit = in(d1,d2,d3).bit./d3sum;
end
end
end
I think the only way to do this is with a for loop, or to use nD arrays:
s(1,1,1).bit = [2 3];
s(1,1,2).bit = [4 5];
s(1,1,3).bit = [6 7];
[m,n,p] = size(s);
[mm,nn] = size(s(1,1,1).bit); % assume all elements of the structure have the same dimension
struct_sum = zeros(1,nn);
% compute the sums
for k=1:p
struct_sum = struct_sum+s(1,1,k).bit;
end
% create the new stucture
for k=1:p
s1(1,1,k).bit = s(1,1,k).bit./struct_sum;
end
UPDATE: option with nD array
s(1,1,1,1:2)=[2 3];
s(1,1,2,1:2)=[4 5];
s(1,1,3,1:2)=[6 7];
s1 = s./sum(s); % you can specify sum(s,3) to sum along the 3rd dimension - you may also need to use squeeze(...) to remove unnecessary dimensions
Check it gives the correct results:
>> s1(1,1,:,1)
ans =
ans(:,:,1) = 0.16667
ans(:,:,2) = 0.33333
ans(:,:,3) = 0.50000
>> [2 4 6]/12
ans =
0.16667 0.33333 0.50000
>> s1(1,1,:,2)
ans =
ans(:,:,1) = 0.20000
ans(:,:,2) = 0.33333
ans(:,:,3) = 0.46667
>> [3 5 7]/15
ans =
0.20000 0.33333 0.46667

How to get row and column of actual element in Octave/MatLab

I'm trying to get the row of the actual element (indX) in a matrix when I use this
matrix2 = matrix .* indX;
Suppose that matrix = ones(2,2)
I'm waiting matrix2 with these values [1 1; 2 2]
I can use "for" for this
[rows columns] = size(matrix) for (indX=0; indX<rows; indX++) matrix2(indX,:) = matrix(indX,:) .* indX;endfor
Is it possible to get the indX without make use of "for" ?
If yes, how can I do that ?
You can use bsxfun:
matrix2 = bsxfun(#times, (1:size(matrix,1))', matrix); %'
matrix =
4 2
3 3
4 1
>> bsxfun(#times, (1:size(matrix,1))', matrix ), % '
ans =
4 2
6 6
12 3

Is there a way to return many columns with linear indexing in MatLab?

Suppose a 3-D matrix :
>> a = rand(3,4,2)
a(:,:,1) =
0.1067 0.7749 0.0844 0.8001
0.9619 0.8173 0.3998 0.4314
0.0046 0.8687 0.2599 0.9106
a(:,:,2) =
0.1818 0.1361 0.5499 0.6221
0.2638 0.8693 0.1450 0.3510
0.1455 0.5797 0.8530 0.5132
I use linear indexing to have many element at a time:
>> index1 = [1 ; 2 ; 1 ; 3];
>> index2 = [1 ; 4 ; 2 ; 3];
>> index3 = [1 ; 1 ; 2 ; 1];
>> indices = sub2ind(size(a), index1, index2, index3)
>> a(indices)
ans =
0.1067
0.4314
0.1361
0.2599
I would like to do the same thing, put return all the values of the first dimensions. The size of this dimension may vary. The return should be, in that case:
>> indices = sub2ind(size(a), ??????, index2, index3);
>> a(indices)
ans =
0.1067 0.9619 0.0046 % a(:,1,1)
0.8001 0.4314 0.9106 % a(:,4,1)
0.1361 0.8693 0.5797 % a(:,2,2)
0.0844 0.3998 0.2599 % a(:,3,1)
Any way to do that in MatLab?
ind1 = repmat((1:size(a,1)),length(index2),1);
ind2 = repmat(index2,1,size(a,1));
ind3 = repmat(index3,1,size(a,1));
indices = sub2ind(size(a),ind1,ind2,ind3)
indices =
1 2 3
10 11 12
16 17 18
7 8 9
a(indices)
ans =
0.1067 0.9619 0.0046
0.8001 0.4314 0.9106
0.1361 0.8693 0.5797
0.0844 0.3998 0.2599
You can get the result you want by doing linear indexing on the last two dimensions separate from the first two dimensions. Even in the 3d data block where you expect to reference by a(:,:,:) you can reference by a(:) (as you know) or a(:,:). The following code finds the sub2ind for the last two dimensions then just repeats them using meshgrid. This ends up being very similar to the solution proposed by #tmpearce but explicitly shows the semi-linear indexing and uses meshgrid instead of repmat:
dim1 = 3;
dim2 = 4;
dim3 = 2;
rand('seed', 1982);
a = round(rand(dim1,dim2,dim3)*10)
% index1 = :
index2 = [1 ; 4 ; 2 ; 3];
index3 = [1 ; 1 ; 2 ; 1];
indices = sub2ind([dim2 dim3], index2, index3)
a(:, indices) % this is a valid answer
[X,Y] = meshgrid(1:dim1, indices)
indices2 = sub2ind([dim1, dim2*dim3], X,Y);
a(indices2) % this is also a valid answer, with full linear indexing