Create a new matrix from existing matrix between zeros - matlab

I have in a matrix data that contains 0 and 'proper' data. I want to crete several matrixes (new ones) to separate the data from the zeros and get rid of these zeros.
So, here is a simple example:
data = 1 3 6 4
3 6 9 5
4 5 6 2
0 0 0 0
0 0 0 0
2 4 1 8
1 4 6 5
0 0 0 0
1 7 9 1
3 4 5 8
And i want to get in this case two matrixes that would be:
A =1 3 6 4
3 6 9 5
4 5 6 2
B= 2 4 1 8
1 4 6 5
C = 1 7 9 1
3 4 5 8
Obviously my data files have thousands of datapoint and i need to automat this.
Any ideas how to do it?

Step 1: create an index of the rows containing only zeros using all:
index = all(data==0,2); #% data==0<-- logical matrix; the 2 means along dimension 2
Step 2: create vectors containing the first and last indices of each segment of desired values:
index = [1; double(index); 1]; #% convert to numeric and pad with ones
firsts = diff(index)==-1; #% 0 (real row) - 1 (spacer row) = -1
lasts = (diff(index)==1)-1; #% subtract 1 because of padding
Step 3: Create a cell array which contains sequential segments of the original matrix in each cell (using cell arrays, each cell can be a different size, or even a different type):
#% firsts and lasts should be the same length
#% iterate through lists of first/last indices
for ii=1:length(firsts)
result{ii} = data(firsts(ii):lasts(ii), :);
end
Obligatory Matlab public service announcement: i and j are popular loop index variables... you'll notice I used ii instead. Here's why.

here's an alternative way that keeps the # of columns of data in the resulted cell array:
L=bwlabel(data);
for n=1:max(L)
result{n}=reshape(data(L==n),[],size(data,2));
end
result =
[3x4 double] [2x4 double] [2x4 double]
result{1}
ans =
1 3 6 4
3 6 9 5
4 5 6 2

Related

Straighten and concatenate the individual grids from ndgrid [duplicate]

This question already has answers here:
Generate a matrix containing all combinations of elements taken from n vectors
(4 answers)
Closed 6 years ago.
I'm trying to do the following in a general way:
x = {0:1, 2:3, 4:6};
[a,b,c] = ndgrid(x{:});
Res = [a(:), b(:), c(:)]
Res =
0 2 4
1 2 4
0 3 4
1 3 4
0 2 5
1 2 5
0 3 5
1 3 5
0 2 6
1 2 6
0 3 6
1 3 6
I believe I have to start the following way, but I can't figure out how to continue:
cell_grid = cell(1,numel(x));
[cell_grid{:}] = ndgrid(x{:});
[cell_grid{:}]
ans =
ans(:,:,1) =
0 0 2 3 4 4
1 1 2 3 4 4
ans(:,:,2) =
0 0 2 3 5 5
1 1 2 3 5 5
ans(:,:,3) =
0 0 2 3 6 6
1 1 2 3 6 6
I can solve this in many ways for the case with three variables [a, b, c], both with and without loops, but I start to struggle when I get more vectors. Reshaping it directly will not give the correct result, and mixing reshape with permute becomes really hard when I have arbitrary number of dimensions.
Can you think of a clever way to do this that scales to 3-30 vectors in x?
You can use cellfun to flatten each of the cell array elements and then concatenate them along the second dimension.
tmp = cellfun(#(x)x(:), cell_grid, 'uniformoutput', false);
out = cat(2, tmp{:})
Alternately, you could avoid cellfun and concatenate them along the dimension that is one higher than your dimension of each cell_grid member (i.e. numel(x) + 1). Then reshape to flatten all dimensions but the last one you just concatenated along.
out = reshape(cat(numel(x) + 1, cell_grid{:}), [], numel(x));

How do I extract the odd and even rows of my matrix into two separate matrices in scilab?

I'm very new to scilab syntax and can't seem to find a way to extract the even and odd elements of a matrix into two separate matrix, suppose there's a matrix a:
a=[1,2,3,4,5,6,7,8,9]
How do I make two other matrix b and c which will be like
b=[2 4 6 8] and c=[1 3 5 7 9]
You can separate the matrix by calling row and column indices:
a=[1,2,3,4,5,6,7,8,9];
b=a(2:2:end);
c=a(1:2:end);
[2:2:end] means [2,4,6,...length(a)] and [1:2:end]=[1,3,5,...length(a)]. So you can use this tip for every matrix for example if you have a matrix a=[5,4,3,2,1] and you want to obtain the first three elements:
a=[5,4,3,2,1];
b=a(1:1:3)
b=
1 2 3
% OR YOU CAN USE
b=a(1:3)
If you need elements 3 to 5:
a=[5,4,3,2,1];
b=a(3:5)
b=
3 2 1
if you want to elements 5 to 1, i.e. in reverse:
a=[5,4,3,2,1];
b=a(5:-1:1);
b=
1 2 3 4 5
a=[1,2,3,4,5,6,7,8,9];
b = a(mod(a,2)==0);
c = a(mod(a,2)==1);
b =
2 4 6 8
c =
1 3 5 7 9
Use mod to check whether the number is divisible by 2 or not (i.e. is it even) and use that as a logical index into a.
The title is about selecting rows of a matrix, while the body of the question is about elements of a vector ...
With Scilab, for rows just do
a = [1,2,3 ; 4,5,6 ; 7,8,9];
odd = a(1:2:$, :);
even = a(2:2:$, :);
Example:
--> a = [
5 4 6
3 6 5
3 5 4
7 0 7
8 7 2 ];
--> a(1:2:$, :)
ans =
5 4 6
3 5 4
8 7 2
--> a(2:2:$, :)
ans =
3 6 5
7 0 7

Dividing a vector to form different matrices

I have a two long vector. Vector one contains values of 0,1,2,3,4's, 0 represent no action, 1 represent action 1 and 2 represent the second action and so on. Each action is 720 sample point which means that you could find 720 consecutive twos then 720 consecutive 4s for example. Vector two contains raw data corresponding to each action. I need to create a matrix for each action ( 1, 2, 3 and 4) which contains the corresponding data of the second vector. For example matrix 1 should has all the data (vector 2 data) which occurred at the same indices of action 1. Any Help??
Example on small amount of data:
Vector 1: 0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2
Vector 2: 6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0
Result:
Matrix 1:
5 6 4
0 5 6
Matrix 2:
9 8 7
5 8 0
Here is one approach. I used a cell array to store the output matrices, hard-coding names for such variables isn't a good plan.
V1=[0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2]
V2=[6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0]
%// Find length of sequences of 1's/2's
len=find(diff(V1(find(diff(V1)~=0,1)+1:end))~=0,1)
I=unique(V1(V1>0)); %// This just finds how many matrices to make, 1 and 2 in this case
C=bsxfun(#eq,V1,I.'); %// The i-th row of C contains 1's where there are i's in V1
%// Now pick out the elements of V2 based on C, and store them in cell arrays
Matrix=arrayfun(#(m) reshape(V2(C(m,:)),len,[]).',I,'uni',0);
%// Note, the reshape converts from a vector to a matrix
%// Display results
Matrix{1}
Matrix{2}
Since, there is a regular pattern in the lengths of groups within Vector 1, that could be exploited to vectorize many things while proposing a solution. Here's one such implementation -
%// Form new vectors out of input vectors for non-zero elements in vec1
vec1n = vec1(vec1~=0)
vec2n = vec2(vec1~=0)
%// Find positions of group shifts and length of groups
df1 = diff(vec1n)~=0
grp_change = [true df1]
grplen = find(df1,1)
%// Reshape vec2n, so that we end up with N x grplen sized array
vec2nr = reshape(vec2n,grplen,[]).' %//'
%// ID/tag each group change based on their unique vector 2 values
[R,C] = sort(vec1n(grp_change))
%// Re-arrange rows of reshaped vector2, s.t. same ID rows are grouped succesively
vec2nrs = vec2nr(C,:)
%// Find extents of each group & use those extents to have final cell array output
grp_extent = diff(find([1 diff(R) 1]))
out = mat2cell(vec2nrs,grp_extent,grplen)
Sample run for the given inputs -
>> vec1
vec1 =
0 0 1 1 1 0 0 2 2 2 ...
0 0 1 1 1 0 0 2 2 2
>> vec2
vec2 =
6 7 5 6 4 6 5 9 8 7 ...
9 7 0 5 6 4 1 5 8 0
>> celldisp(out)
out{1} =
5 6 4
0 5 6
out{2} =
9 8 7
5 8 0
Here is another solution:
v1 = [0 0 1 1 1 0 0 2 2 2 0 0 1 1 1 0 0 2 2 2];
v2 = [6 7 5 6 4 6 5 9 8 7 9 7 0 5 6 4 1 5 8 0];
m1 = reshape(v2(v1 == 1), 3, [])'
m2 = reshape(v2(v1 == 2), 3, [])'
EDIT: David's solution is more flexible and probably more efficient.

Sorting Coordinate Matrix in Matlab

In Matlab I have a big matrix containing the coordinates (x,y,z) of many points (over 200000). There is an extra column used as identification. I have written this code in order to sort all coordinate points. My final goal is to find duplicated points (rows with same x,y,z). After sorting the coordinate points I use the diff function, two consecutive rows of the matrix with the same coordinates will take value [0 0 0], and then with ismember I can find which rows of that matrix resulting from applying "diff" have the [0 0 0] row. With the indices returned from ismember I can find which points are repeated.
Back to my question...This is the code I wrote to sort properly my coordintes+id matrix. I guess It could be done better. Any suggestion?
%coordinates are always positive
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 1 2 8;
1 2 4 8];
b=a; %for checking purposes
%sorting first column
a=sortrows(a,1);
%sorting second column
for i=0:max(a(:,1));
k=find(a(:,1)==i);
if not(isempty(k))
a(k,:)=sortrows(a(k,:),2);
end
end
%Sorting third column
for i=0:max(a(:,2));
k=find(a(:,2)==i);
if not(isempty(k))
%identifying rows with same value on first column
for j=1:length(k)
[rows,~] = ismember(a(:,1:2), [ a(k(j),1),i],'rows');
a(rows,3:end)=sortrows(a(rows,3:end),1);
end
end
end
%Checking that rows remain the same
m=ismember(b,a,'rows');
if length(m)~=sum(m)
disp('Error while sorting!');
end
Why don't you just use unique?
[uniqueRows, ii, jj] = unique(a(:,1:3),'rows');
Example
a = [1 2 3 5
3 2 3 6
1 2 3 9
2 2 2 8];
gives
uniqueRows =
1 2 3
2 2 2
3 2 3
and
jj =
1
3
1
2
meaning third row equals first row.
If you need the full unique rows, including the fourth column: use ii to index a:
fullUniqueRows = a(ii,:);
which gives
fullUniqueRows =
1 2 3 9
2 2 2 8
3 2 3 6
Trying to sort a based on the fourth column? Do this -
a=[ 1 2 8 4; %sample matrix
1 0 5 6;
2 4 7 1;
3 2 1 0;
2 3 5 0;
3 2 1 8;
1 2 4 8];
[x,y] = sort(a(:,4))
sorted_a=a(y,:)
Trying to get the row indices having repeated x-y-z coordinates being represented by the first three columns? Do this -
out = sum(squeeze(all(bsxfun(#eq,a(:,1:3),permute(a(:,1:3),[3 2 1])),2)),2)>1
and use it similarly for sorted_a.

matlab adjacency list to adjacency matrix

How to convert adjacency list to adjacency matrix via matab
For example: Here is the adjacency list(undirected), the third column is the weight.
1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7
++++++++++++++++++++++
that should be converted to:
1 2 3 4 5
1 0 4 5 0
2 3 4 7 8
3 4 7 0 0
4 0 7 0 0
5 0 8 0 0
You can use sparse matrix. Let rows be the first column, cols the second, and s the weight.
A = sparse([rows; cols],[cols; rows],[s; s]);
If you want to see the matrix. use full().
UPDATE:
I made the answer a bit simpler (everything in one line, instead of adding the transposed, and included explanations, as requested:
list = [1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7];
rows = list(:,1)
cols = list(:,2)
s = list(:,3)
Now, rows, cols and s contains the needed information. Sparse matrices need three vectors. Each row of the two first vectors, rows and cols is the index of the value given in the same row of s (which is the weight).
The sparse command assigns the value s(k) to the matrix element adj_mat(rows(k),cols(k)).
Since an adjacency matrix is symmetric, A(row,col) = A(col,row). Instead of doing [rows; cols], it is possible to first create the upper triangular matrix, and then add the transposed matrix to complete the symmetric matrix.
A = sparse([rows; cols],[cols; rows],[s; s]);
full(A)
A =
0 3 4 5 0
3 0 4 7 8
4 4 0 0 0
5 7 0 0 0
0 8 0 0 0
It's really hard to tell what your'e asking. Is this right?
list = [1 2 3
1 3 4
1 4 5
2 3 4
2 5 8
2 4 7];
matrix = zeros(max(max(list(:, 1:2)))); %// Or just zeros(5) if you know you want a 5x5 result
matrix(sub2ind(size(matrix), list(:,1), list(:,2))) = list(:,3); %// Populate the upper half
matrix = matrix + matrix' %'// Find the lower half via symmetry
matrix =
0 3 4 5 0
3 0 4 7 8
4 4 0 0 0
5 7 0 0 0
0 8 0 0 0