Create a vector that holds the index of all the columns which has non-zero values based on a condition - matlab

I have a matrix filled with zeros and ones and I need to count the number of ones in each row. Then I need to know which row's count exceeds or equal a specific limit (any number, for example 3). After that foreach row in these rows I need to create a vector that holds the index of all the columns which has non-zero values in that row and in all the rows above it and below it till it reach a row with zero count.
Example:
data contains the data below:
0 0 0 0 0 0 0
0 0 0 1 1 0 0
0 1 0 0 1 0 1
0 0 0 0 0 0 0
0 1 0 0 0 0 0
0 1 1 1 0 0 0
0 0 1 0 0 0 0
0 0 0 0 0 0 0
The output should be if the limit is 3:
Row 3: col 4 5 2 5 7
Row 6: col 2 2 3 4 3
I already read the data and I counted the ones in the code below:
load('data');
mat(isnan(mat)) = 0;
[rows,cols,vals] = find(mat~= 0);
unqRows=unique(rows);
countElinRows=histc(rows,unqRows);
Edit for clarification as requested by commentators:
If the third row of the given sample input array becomes [0 1 0 0 0 0 1], then we must only have this output -
Row 6: col 2 2 3 4 3

Assuming A as the input array, see if this works for you -
[sc1,sr1] = find(A') %//'# row and col indices for sorted rows
s_a1 = sum(A,2) %// sum input array along cols
bounds = find(s_a1==0) %// find bounds/gropus delimited by all zero rows
bounds = unique([1 ; bounds ; size(A,1)]) %// account for non all zero
%// starting and ending rows
cumsum1 = cumsum(s_a1==0) + double(sum(A(1,:))~=0) %// label groups
valid_groups = accumarray(cumsum1, s_a1, [], #max)>=3 %// valid groups
out = arrayfun(#(k1) sc1(sr1>=bounds(k1) & sr1<=bounds(k1+1)),...
1:numel(bounds)-1,'un',0) %// find all indices within each group
out = out(valid_groups) %// select only the valid groups for the final output
Visualized output with celldisp(out).

Apologies for strange code, but it's the best I could come up with
[I1,~]=find(sum(mat,2)>=3)
[I2,~]=find(sum(mat,2)==0)
[~,CM]=find(diff(mod(sum(bsxfun(#le,I1,I2.')),2))~=0)
[I,J]=arrayfun(#(t)find(mat(I2(CM(t)):I2(CM(t)+1),:)>0),1:length(CM),'UniformOutput',false)
[~,w]=cellfun(#sort,I,'UniformOutput',false);
J=arrayfun(#(t) J{t}(w{t}).',1:length(J),'UniformOutput',false)
celldisp(J)
This code does feel pretty overcomplicated.
I have tested it on a few cases and it seems to be fine, but it's hard to know for certain.

Related

Convert digit to vector octave/matlab [duplicate]

This question already has answers here:
Construct this matrix based on two vectors MATLAB
(3 answers)
Closed 8 years ago.
I have a vector y = [0; 2; 4]
I want to convert each element of it into vector, where all elements are zero but element with index equal to digit is 1.
I'd like to do it without loops.
For example [0; 2; 4] should be converted to
[1 0 0 0 0 0 0 0 0 0;
0 0 1 0 0 0 0 0 0 0;
0 0 0 0 1 0 0 0 0 0]
(in this example vector first index is 0)
The usual trick with sparse can be used to simplify the process. Let n denote the desired number of columns. Then
result = full(sparse(1:numel(y), y+1, 1, numel(y), n));
For example, y = [0;2;4] and 10 produce
result =
1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
First you need to decide how many digits you want to represent each number. In your case, you have 10 digits per number, so let's keep that in mind.
Once you do this, it's just a matter of indexing each element in your matrix. In your case, you have 10 digits per number. As such, do something like this:
y = [0; 2; 4]; %// Your digits array
out = zeros(numel(y), 10); %// 10 digits per number
ind = sub2ind(size(out), [1:numel(y)].', y+1);
out(ind) = 1;
The output should look like this:
out =
1 0 0 0 0 0 0 0 0 0
0 0 1 0 0 0 0 0 0 0
0 0 0 0 1 0 0 0 0 0
Let's go through this code slowly. y defines the digits you want per row of the output matrix. out allocates a matrix of zeroes where the number of rows is defined by how many digits you want in y. out will thus store your resulting matrix that you have shown us in your post.
The number of columns is 10, but you change this to be whatever you want. ind uses a command called sub2ind. This allows to completely vectorize the assignment of values in your out matrix and avoids a for loop. The first parameter is an array of values that defines how many rows and columns are in your matrix that you are trying to assign things to. In this case, it's just the size of out. The second and third parameters are the rows and columns you want to access in your matrix. In this case, the rows vary from 1 to as many elements as there are in y. In our case, this is 3. We want to generate one number per row, which is why it goes from 1 to 3. The columns denote where we want to set the digit to one for each row. As MATLAB indexes starting at 1, we have to make sure that we take y and add by 1. ind thus creates the column-major indices in order to access our matrix. The last statement finally accesses these locations and assigns a 1 to each location, thus producing our matrix.
Hope this helps!

Matlab permutations table

I was wondering, let's say we have a table with eg 4 columns that has all possible combinations of numbers between 0 and 2. So it would be
0 0 0 0
0 0 0 1
0 0 0 2
0 0 1 0
0 0 1 1
0 0 1 2
0 0 2 0
0 0 2 1
0 0 2 2
0 1 0 0
0 1 0 1
and so on containing 3^4 rows.
Is there a way for me to find the combination in lets say row 56 without having to construct the whole table, as it is impossible to create a table like this for bigger numbers (eg values ranging from 0 to 100 using >1000 columns).
The rightmost column of row n is simply mod(n, 3).
If you then replace n with floor(n./3) you can retrieve the next rightmost in the same way.
Rinse and repeat to construct the entire row...
Each combination is the base-3 expansion of a number, starting from 0 and ending in 3^4-1. So you can use dec2base to convert from that number to its expansion:
N = 3; %// number of digits
M = 4; %// number of columns
n = 56; %// row number: 1, 2, ..., N^M
result = dec2base(n-1,N)-'0';
This -
%%// Given data
rownum = 56; %%// Row number to be found out
arr1=[0 1 2]; %%// Numbers used for perms
Nc = 4; %%// Number of columns
N = numel(arr1);%%// Number of array elements for perms
%%// Combination needed
comb1 = arr1(fliplr(ceil(bsxfun(#mod,rownum,power(N,1:Nc))./power(N,0:Nc-1))))
Output -
comb1 =
2 0 0 1

finding the frequency of each row (3)

Per my previous question couple days ago, now, I have several mx3 matrices with rows from (0,1,num), (-1,0,num), (0,1,num), (0,-1,num), (1,1,num), (-1,1,num), (1,-1,num),(-1,-1,num), where num is an integer which can take any values between 0 to 3.
I would like to create a new matrix, with 8 rows, and 6 columns, where the the first two columns represent each of the above coordinates, and each of the remaining columns indicate the frequency
of each of the above coordinates at each num values. i.e. columns 3 of each row indicates the number of times we see the coordinate corresponding to that row with and num=0. columns 4 of each row indicates the number of times we see the coordinate corresponding to that row with and num=1.
columns 5 of each row indicates the number of times we see the coordinate corresponding to that row with and num=2, and columns 6 of each row indicates the number of times we see the coordinate corresponding to that row with and num=3.
For instance, if A=[0 1 1
1 1 1
1 1 0
1 0 0
1 1 0
1 1 0
1 1 0
1 1 0
1 1 0
1 -1 0
1 1 0
1 1 3
1 1 2
1 1 3
1 1 3]
I would like to see something like:
-1 -1 0 0 0 0
-1 0 0 0 0 0
-1 1 0 0 0 0
0 -1 0 0 0 0
0 1 0 1 0 0
1 -1 1 0 0 0
1 0 1 0 0 0
1 1 7 1 1 3
Is there a way to do it? Thanks.
Try this:
counts = zeros(9, 6); % Initialize output matrix
k = 1;
for ii = -1:1
for jj = -1:1
ijCoords = (A(:,1) == ii) & (A(:,2) == jj); % Find rows containing coordinate (ii,jj)
ijCount = histc(A(ijCoords,3), 0:3); % Count how many 0,1,2,3 in these rows
counts(k,:) = [ii, jj, ijCount(:)']; % Add the counts to the next row of the output matrix
k = k + 1;
end
end
counts(5, :) = []; % Remove coordinate (0,0) because you don't want it.

Octave/Matlab: change value at certain position in matix

I have a vector which tells me where in matrix I have to change certain bit and matrix with data. For example:
a = [2
0
4]
data = [ 1 0 1 0;
0 0 1 0
1 1 1 1]
a tells me, I have to change (flip from 1 to 0) the folowing values:
2nd column in 1st row
4rd column in 3rd row
in 2nd row there is no change !!!
the result would be
data2 = [ 1 1 1 0;
0 0 1 0
1 1 1 0]
How can I do that with only vector operations? I don't want to use for loops because they are too slow.
here's a way to do that:
data2=data;
ind=sub2ind(size(data),find(a),a(a>0));
data2(ind)=~data(ind)

Using find function on columns and rows in matlab

I am having some problems with the find function in MATLAB. I have a matrix consisting of zeros and ones (representing the geometry of a structural element), where material is present when the matrix element = 1, and where no material is present when the matrix element = 0. The matrix may have the general form shown below (it will update as the geometry is changed, but that isn't too important).
Geometry = [0 0 0 0 0 0 0 0 0 0;
0 0 1 0 1 0 1 1 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 0 0 0 0 0 0 0;
0 0 0 0 0 0 0 1 0 0;
0 0 0 0 0 0 0 0 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 1 1 1 0 1 0 0;
0 0 0 0 0 0 0 0 0 0;]
I'm trying to find the the rows and columns that are not continuously connected (i.e. where the row and columns are not all equal to 1 between the outer extents of the row or column) and then update them so they are all connected. I.e. the matrix above becomes:
Geometry = [0 0 0 0 0 0 0 0 0 0;
0 0 1 1 1 1 1 1 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 0 0 0 0 1 0 0;
0 0 1 1 1 1 1 1 0 0;
0 0 0 0 0 0 0 0 0 0;]
The problem I am having is I want to be able to find the indices of the first and last element that is equal to 1 in each row (and column), which will then be used to update the geoemtry matrix.
Ideally, I want to represent these in vectors, so going across the columns, find the row number of the first element equal to 1 and store this in a vector called rowfirst.
I.e.:
rowfirst = zeros(1,numcols)
for i = 1:numcols % Going across the columns
rowfirst(i) = find(Geometry(i,1) == 1, 1,'first')
% Store values in vector called rowfirst
end
and the repeat this for the columns and to find the last elements in each row.
For some reason, I can't get the values to store properly in the vector, does anyone have an idea of where I'm going wrong?
Thanks in advance. Please let me know if that isn't clear, as I may not have explained the problem very well.
0) bwmorph(Geometry,'close') dose it all in one line. If the holes may be bigger, try bwmorph(Geometry,'close',Inf).
Regarding your attempt:
1) It should be Geometry(i,:) instead of Geometry(i,1).
2) Your real problem here is empty matrices. Actually, what do you want rowfirst(i) to be if there are no 1s in the i'th row?
Ok, I can spot two mistakes:
You should use an array as the first argument of find. So, if you want to find the row number of the first element of each column, then you should use find(Geometry(:, i), 1, 'first').
Find returns an empty array if the column contains only zeros. You should handle this case and decide what number you want to put into rownumber (e.g. you can put -1, to indicate that the corresponding column contains no non-zero elements).
Following the above, you can try this:
for i = 1:numcols
tmp = find(Geometry(:, i), 1, 'first');
if(tmp)
rowfirst(i) = tmp;
else
rowfirst(i) = -1;
end;
end;
I'm pretty sure there's a more efficient way of doing this, but if you replace your call to find with this, it should work ok:
find(Geometry(i,:), 1,'first')
(otherwise you're just looking at the first cell of the ith row. And the == 1 is useless, since find already returns only non-zero elements, and your matrix is binary)
Use the AccumArray() function to find the min and max col (row) number.
Imagine finding the last (first) row in each column that contains a NaN.
a = [1 nan nan nan ;
2 2 3 4;
3 nan 3 3;
4 nan 4 4]
This code gets the row indices for the last NaN in each column.
[row,col] = find(isnan(a))
accumarray(col,row,[],#max)
This code gets the row indices for the first NaN in each column.
[row,col] = find(isnan(a))
accumarray(col,row,[],#min)
Swap the row and col variables to scan row-wise instead of column-wise.
This answer inspired by Finding value and index of min value in a matrix, grouped by column values