cut vector according to NaN values - matlab

data_test is a vector that is populated by numbers with some NaN.
data_test = [NaN, 2, 3, 4, NaN,NaN,NaN, 12 ,44, 34, NaN,5,NaN];
I would like to cut data_test according to the NaNs and create a cell array containing the pieces of data_set in between NaNs.
data_cell{1}=[2 3 4];
data_cell{2}=[12 44 34];
data_cell{3}=[5];
at this point I need to filter these values (this is OK, just as an example the filtered values will be the same of data_test +1)
data_cell{1} -> data_cell_filt{1}
data_cell{2} -> data_cell_filt{2}
data_cell{3} -> data_cell_filt{3}
and put back the filtered values in data_test.
data_cell_filt{1}
data_cell_filt{2} -> data_test
data_cell_filt{3}
in order that data_test is
data_test = [NaN, 3, 4, 5, NaN,NaN,NaN, 13 ,45, 35, NaN, 6, NaN];
ps (data_test in my case is ~20000 elements)

You can do it easily with a loop or use arrayfun like this:
A = [NaN, 2, 3, 4, NaN, NaN, NaN, 13, 45, 35, NaN, 6, NaN]
i1 = find(diff(isnan(A))==-1)+1 %// Index where clusters of numbers begin
i2 = find(diff(isnan(A))==1) %// Index where clusters of numbers end
data_cell_filt = arrayfun(#(x,y)({A(x:y)}),i1,i2 ,'uni', false)

One approch with accumarray and cumsum and diff
%// find the index of regular numbers
idx = find(~isnan(data_test))
%// group the numbers which are adjacent, to some index number
idx1 = cumsum([1,diff(idx)~=1])
%// put all those numbers of same index number into a cell
out = accumarray(idx1.',data_test(idx).',[],#(x) {x.'})
Sample run:
data_test = [NaN, 2, 3, 4, NaN,NaN,NaN, 12 ,44, 34, NaN,5,NaN];
>> celldisp(out)
out{1} =
2 3 4
out{2} =
12 44 34
out{3} =
5

Convolution-based approach:
ind = isnan(data_test);
t = conv(2*x-1, [-1 1], 'same'); %// convolution is like correlation but flips 2nd input
starts = find(t==2); %// indices of where a run of non-NaN's starts, minus 1
ends = find(t==-2); %// indices of where it ends
result = mat2cell(data_test(~ind), 1, ends-starts); %// pick non-NaN's and split

Related

Matrix periodic boundary conditions Matlab

I need some help, i have a matrix rapresenting points on a grid and when given a element i would like to find the indices of its nearest neighbors keeping in mind that i have periodic boundary conditions, so that if i have the element A(1,1) its nearest neighbors are
A(1,N)
A(2,1)
A(1,2)
A(N, 1)
Where A is my matrix and N is the dimension, and i need a code which will find the indices of n.n of a given element.
Thanks in advance.
Here's my interpretation of your problem:
Given some periodic matrix A:
>> A = magic(4)
A =
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
and some element x (example 1), then find the (i,j) indices of the 4 neighbours of x. In this case, the indices (3, 4), (4,3), (4, 1), (1, 4) correspond to 12, 15, 4, 13.
Since I don't know your use case, I don't know in what format the indices are most convenient for you. But as an example, we can write a function neighbors which returns a struct with the 4 indices of the element x.
function out = neighbors(A, x)
[m, n] = size(A);
[i, j] = find(A == x);
mod2 = #(x) mod(x-1, [m, n])+1;
out.down = mod2([i+1, j ]);
out.up = mod2([i-1, j ]);
out.right = mod2([i , j+1]);
out.left = mod2([i , j-1]);
end
We can then run the function as follows.
A = magic(4);
out = neighbors(A, 1);
A(out.left(1), out.left(2)); % this returns 15
A(out.right(1), out.right(2)); % this returns 4
A(out.up(1), out.up(2)); % this returns 12
A(out.down(1), out.down(2)); % this returns 13

Loop through three arrays, apply function to elements and store the outputs in a matrix

I want to loop through different elements of 3 arrays and create a matrix as a function of their values.
My a vector ranges from 1 to 5, my b vector ranges from 1 to 5 and my x vector ranges from 2 to 10 as shown below. Then for particular values from a and b, using the equation y=a*x+b, I want the resulting y vector corresponding to the x values stored in the 1st column vector of the y matrix.
After that, changing a and b one by one, I want the results of different y to be stored in corresponding columns of the y matrix . How can I proceed to achieve that?
Here is the code I tried:
function mathstrial
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
for e1 = a
for e2 = b
for e3 = x
y = e1*x+e2;
end
end
end
disp(y)
end
I want the result to be
y =
3 4 5 6 7 ..
5 6 7 8 9 ..
7 8 9 10 11 ..
9 10 11 12 13 ..
11 12 13 14 15 ..
...
You can do this without any loops - the more "MATLAB-esque" way of doing things.
% Your a and b, to get combinations as a 5x5 grid we use meshgrid
[a,b] = meshgrid(1:5, 1:5);
% We want to make a 5x5x5 3D matrix, where the 2D layers each use a different value
% for x, and the gridded a and b we just generated. Get the layered x:
x = repmat(reshape(2:2:10, 1, 1, []), 5, 5, 1);
% Now we want the corresponding layered a and b
a = repmat(a, 1, 1, 5); b = repmat(b, 1, 1, 5);
% Now calculate the result, ensuring we use element-wise multiplication .*
y = a.*x + b;
% Reshape to be a 2D array, collapsing the 3rd dimension
y = reshape(y(:,:).', [], 5, 1);
Result as you wanted:
y =
[3, 4, 5, 6, 7
5, 6, 7, 8, 9
7, 8, 9, 10, 11
9, 10, 11, 12, 13
...
41, 42, 43, 44, 45
51, 52, 53, 54, 55]
You could easily make this more generic by using size in place of the 5s to get the appropriate sizes.
you can build up y in a single for loop
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
y = zeros(5,5,5);
for ct = 1:length(a)
y(:,:,ct) = (a(ct).*x)'+b;
end
with b over the second and a over the third dimension.
Or even in a single unreadable line
y=repmat((a'.*x),[1,1,length(b)])+repmat(permute(b,[1,3,2]),[length(x),length(a),1])
with a over the second, and b over the third dimension
a = [1:1:5];
b = [1:1:5];
x = [2:2:10];
y = zeros(5,5,5);
for i = 1:5
for j = 1:5
for k =1:5
y(i,j,k) = i*x(k)+j
end
end
end
final_y = reshape(y, [5, 25])

Transform matrix without loop

I have oldMat which is a ranking of equity tickers. The column number represents the respective rank, e.g. first column equals highest rank, second column represents second highest rank and so on. The integers within oldMatrepresent the number of the individual equity ticker. The number 3 in oldMat(3,2,1)means, that the third equity ticker is ranked second in the third period (rows represent different periods).
Now, I need to transform oldMat in the following way: The column numbers now represent the individual equity tickers. The integers now represent the rank that individual equity tickers hold at specific periods. For example, the number 2 in newMat(3,3,1) means, that the third equity ticker is ranked second in the third period.
I used a for-loop in order to solve that problem, but I am pretty sure there exists a more efficient way to achieve this result. Here's my code:
% Define oldMat
oldMat(:,:,1) = ...
[NaN, NaN, NaN, NaN, NaN, NaN; ...
1, 3, 4, 6, 2, 5; ...
6, 3, 4, 1, 2, 5; ...
2, 3, 6, 1, 4, 5; ...
5, 4, 6, 2, 3, 1; ...
5, 1, 2, 3, 6, 4; ...
4, 5, 1, 3, 6, 2; ...
4, 1, 6, 5, 2, 3];
oldMat(:,:,2) = ...
[NaN, NaN, NaN, NaN, NaN, NaN; ...
NaN, NaN, NaN, NaN, NaN, NaN; ...
1, 6, 3, 4, 2, 5; ...
6, 3, 2, 1, 4, 5; ...
2, 6, 3, 4, 1, 5; ...
5, 2, 1, 6, 3, 4; ...
5, 1, 3, 6, 2, 4; ...
4, 1, 5, 6, 3, 2];
% Pre-allocate newMat
newMat = nan(size(oldMat));
% Transform oldMat to newMat
for runNum = 1 : size(newMat,3)
for colNum = 1 : size(newMat,2)
for rowNum = 1 : size(newMat,1)
if ~isnan(oldMat(rowNum, colNum, runNum))
newMat(rowNum,oldMat(rowNum, colNum, runNum), runNum) = colNum;
end
end
end
end
Looks like a classic case of sub2ind. You want to create a set of linear indices to access the second dimension of the new matrix and set those equal to the column number. First create a grid of 3D coordinates with meshgrid, then use the oldMat matrix as an index into the second column of the output and set this equal to the column number. Make sure that you don't copy over any NaN values or sub2ind will complain. You can use isnan to help filter these values out for you:
% Initialize new matrix
newMat = nan(size(oldMat));
% Generate a grid of coordinates
[X,Y,Z] = meshgrid(1:size(newMat,2), 1:size(newMat,1), 1:size(newMat,3));
% Find elements that are NaN and remove
mask = isnan(oldMat);
X(mask) = []; Y(mask) = []; Z(mask) = [];
% Set the values now
newMat(sub2ind(size(oldMat), Y, oldMat(~isnan(oldMat)).', Z)) = X;

How to compare every elements in an array with every other element without repetition?

I want data to be processed as follows.
Eg.
say data x(i)=[1 2 3 5 2 1].
Comparisons should be elements INDEX [1 to 2, 1 to 3, 1 to 4, 1 to 5, 1 to 6, 2 to 3,2 to 4,2 to 5,2 to 6,3 to 4....]
following the above logic
hence elements values of distance = [1, 2 , 3 , 4 , 5 , 1 , 2, 3, 4, 1, 2, 3, 1, 2, 1].
hence elements values of difference = [1, 2 , 4 , 1 , 0 , 1 , 3, 0, 1, 2, 1, 2, 3, 4, 1].
I have written the following code for the same but i notice that the final matrix 'b' that i want is always changing size when it should be constant. I welcome any suggestions
clc;
close all;
clear all;
% read data set
I= imread('img2.bmp');
G=double(rgb2gray(I));
%choose 2 random numbers
n = 1;
s = [1 960];
k = round(rand(n,1)*range(s)+min(s));
for i = 1:length(k)
% choose a particular row from a matrix
row_no=k(i);
%G=R(row_no,:);
% compare every element with its neigbour to create distance and difference matrix
x1=row_no;
x2=row_no;
for y1 = 1:length(G)%size(G,2)
for y2 =1:length(G) %1:size(G,2)
distance_Mat(y1,y2) = round(sqrt((y2-y1)^2 + (x2-x1)^2));
difference_Mat(y1,y2) = 1*(G(x1,y1) - G(x2,y2))^2;
end
end
%% now remove repeating comparisons
b=horzcat(distance_Mat(:),(difference_Mat(:)));
[UniXY,Index]=unique(b,'rows');
DupIndex=setdiff(1:size(b,1),Index);
b(DupIndex,:)=[];
%calculate the cumulative sums and store it in different colums of data matrix
A1 = cumsum(b);
data(:,1)=A1;
end
If you have the stats toolbox then
distance_Mat = squareform(pdist(x'));
only does each comparison once and then mirrors the data. You can get just the lower half by
tril(distance_Mat,-1);
If you don't have the toolbox then try this:
I = tril(ones(numel(x)),-1);
[r,c] = find(I);
distance_Mat = zeros(numel(x));
distance_Mat(logical(I)) = round(sqrt((x(r)-x(c)).^2)

Copy to and delete from matrices

Not sure even if this question stands valid. But better ask.
Suppose we have two matrices in MATLAB of size (n,1) and (m,1) and we want to copy certain rows from matrix A to matrix B on a condition.
e.g. if value A(i,1) is less or equal to X
And later delete those rows from source matrix i.e. matrix A
Example:
A = [1, 2, 3, 4, 5, 6]
B = [8, 9]
copy all values which are less than or equal to 4 from A to B, and delete from A
Matrices becomes
A = [5, 6]
B = [8, 9, 1, 2, 3, 4]
You can use a logical matrix to identify the items:
mask = (A <= 4);
B = [B A(mask)];
A(mask) = [];