Adding all the 1's in a row? - matlab

I have a very large matrix(around 4000000x2) , and it has 1s sprinkled throughout the matrix. What I want to do is that I just want to add up all the 1s in one row.
For example, if I have a matrix like this:
A = [0 0 4 1 0 0 1
1 0 5 0 7 0 1
5 6 0 8 1 0 6
0 9 5 1 0 0 0]
Is there a way of summing up all of the 1's a row? For example, here it would be:
sum = [2
2
1
1]
I know that if you want to add up the whole row, you can use sum(A,2). But is there a way in matlab to add up all of a specific number? I'm new to matlab and I would greatly appreciate any help, thank you!!

Generate an array that has a 1 everywhere A has a 1, and 0 everywhere else:
>> A == 1
ans =
0 0 0 1 0 0 1
1 0 0 0 0 0 1
0 0 0 0 1 0 0
0 0 0 1 0 0 0
Then you can just use sum:
sum(A == 1, 2)

Related

Create coordinate array from adjacency matrix - Matlab

I have a quick graph theory question.
I have a 13 x 13 adjacency matrix in Matlab. I've already taken just the lower diagonal (this is an undirected graph) and subtracted off the identity matrix (so there aren't edges joining a node to itself). I then added a column on the left and a row on the top with the ID numbers of the four nodes. The resulting 14 x 14 adjacency matrix looks like this:
A =
0 1 1 1 1 2 2 2 3 3 3 4 4 4
1 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
1 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
2 1 0 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0 0 0 0
2 0 0 0 0 0 0 0 0 0 0 0 0 0
3 0 0 1 0 0 0 0 0 0 0 0 0 0
3 0 0 0 0 0 0 0 0 0 0 0 0 0
3 0 1 0 0 0 0 0 0 0 0 0 0 0
4 1 0 0 0 1 0 0 0 0 0 0 0 0
4 0 0 0 1 0 0 0 0 0 0 0 0 0
4 0 0 0 0 0 0 1 0 0 0 0 0 0
How can I create the coordinate array from this? I know the result should have 7 rows (one for each unique node pair).
Please let me know if you can help. Thanks in advance!
We can use the node IDs that are provided at the first row and first column to help us create a node adjacency list. What we need to do is split up the variables so that we separate out the first row, called rowList and the first column colList. We will denote these the row and column lists respectively. We will also extract the adjacency matrix which is the rest of the matrix. The basic algorithm is the following:
Find those rows and columns that are non-zero in the adjacency matrix.
Use these rows and columns to index the corresponding rows and columns lists and spit out a co-ordinate array.
Without further ado:
rowList = A(2:end,1);
colList = A(1,2:end).';
AdjMatr = A(2:end,2:end);
[nonZeroRows, nonZeroCols] = find(AdjMatr);
nodeList = [rowList(nonZeroRows) colList(nonZeroCols)];
The output thus gives:
nodeList =
2 1
4 1
3 1
3 1
4 1
4 2
4 2
This answer does not give unique rows of course, and produces duplicates. If you wish to have unique rows, consider doing:
nodeListUnique = unique(nodeList, 'rows');
The output is:
nodeListUnique =
2 1
3 1
4 1
4 2
It appears that what you want is:
[ii, jj] = find(A(2:end,2:end)); %// row and col indices of ones in inner matrix
result = [ A(ii+1,1) A(1,jj+1).' ]; %'// node numbers corresponding to ii and jj
In your example, this gives
result =
2 1
4 1
3 1
3 1
4 1
4 2
4 2
If you need unique rows:
result = unique(result, 'rows');
which gives
result =
2 1
3 1
4 1
4 2

Matlab how to bitwise-AND of a vector and a matrix?

I want to find out the index of the matrix column in which the vector appears. My idea is to do AND of the vector over matrix and only the column that is the same will be 1 in the new vecotr. But I don't know how to do this. Below is example:
H =
0 0 0 0 1 1 1 1 1 1 1 1 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 1 0 0
1 0 1 1 0 1 1 0 0 1 1 0 0 1 0
1 1 0 1 1 0 1 0 1 0 1 0 0 0 1
S =
0 1 0 1
From that I want to get 2 as second column or even better vector
0 1 0 0 0 0 ... 0
Since there is error in second column.
How can I do this in Matlab or even better Octave?
Not really sure how you tried to approach the problem. But with repmat or bsxfun it is as simple as this:
all(bsxfun(#eq,H,S'))
How about
result = sum(H==repmat(S(:),[1 size(H,2)]))==4;
I found out the function
ismember(H', S, "rows")
works exactly as I want. Your answers are all good too, thanks.
That's pretty easy with broadcasting. The following will require Octave 3.6.0 or later but you can use bsxfun if you have a previous version:
octave-cli-3.8.1> h = logical ([
0 0 0 0 1 1 1 1 1 1 1 1 0 0 0
0 1 1 1 0 0 0 1 1 1 1 0 1 0 0
1 0 1 1 0 1 1 0 0 1 1 0 0 1 0
1 1 0 1 1 0 1 0 1 0 1 0 0 0 1]);
octave-cli-3.8.1> s = logical ([0 1 0 1]');
octave-cli-3.8.1> all (h == s)
ans =
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
From here, it's all a matter of using find to get the column numbers. It will even work if it matches more than 1 column:
octave-cli-3.8.1> find (all (h == s))
ans = 2

Calculating a partial cumulative sum for a square matrix

Let's say I have a square matrix M:
M = [0 0 0 0 0 1 9; 0 0 0 0 0 4 4; 0 0 1 1 6 1 1; 0 1 2 9 2 1 0; 2 1 8 3 2 0 0; 0 8 1 1 0 0 0; 14 2 0 1 0 0 0]
0 0 0 0 0 1 9
0 0 0 0 0 4 4
0 0 1 1 6 1 1
M = 0 1 2 9 2 1 0
2 1 8 3 2 0 0
0 8 1 1 0 0 0
14 2 0 1 0 0 0
Now I'd like to calculate two different cumulative sums: One that goes from the top of each column to the element of the column, that is a diagonal element of the matrix, and one that goes from the bottom of the column to the same diagonal element.
The resulting matrix M'should therefore be the following:
0 0 0 0 0 1 9
0 0 0 0 0 4 5
0 0 1 1 6 2 1
M' = 0 1 3 9 4 1 0
2 2 8 5 2 0 0
2 8 1 2 0 0 0
14 2 0 1 0 0 0
I hope the explanation of what I'm trying to achieve is comprehensible enough. Since my matrices are much larger than the one in this example, the calculation should be efficient as well...but so far I couldn't even figure out how to calculate it "inefficiently".
In one line using some flipping and the upper triangular function triu:
Mp = fliplr(triu(fliplr(cumsum(M)),1)) ...
+flipud(triu(cumsum(flipud(M)),1)) ...
+flipud(diag(diag(flipud(M))));
The following will do the job:
Mnew = fliplr(triu(cumsum(triu(fliplr(M)),1))) + flipud(triu(cumsum(triu(flipud(M)),1)));
Mnew = Mnew - fliplr(diag(diag(fliplr(Mnew)))) + fliplr(diag(diag(fliplr(M))));
But is it the fastest method?
I think logical indexing might get you there faster

Copying part of a matrix to another empty matrix with the same indices

I'm trying to copy part of a matrix (matrix 1) in matlab to another empty matrix of zeros (matrix 2) so that the section I copy from matrix 1 has the same indices in matrix 2, e.g.
Matrix 1 (mat1):
0 3 0 0 2 4 1 2 6
1 3 4 2 0 0 0 2 0
0 2 6 1 3 6 6 1 1
0 0 0 2 1 3 3 1 0
1 4 5 2 3 3 0 0 1
Matrix 2 (mat2) desired output:
0 0 0 0 0 0 0 0 0
0 0 4 2 0 0 0 0 0
0 0 6 1 3 6 6 0 0
0 0 0 2 1 3 3 0 0
0 0 0 0 0 0 0 0 0
I've tried something like
mat2([2:4],[3:7]) = mat1([2:4],[3:7])
but of course it doesn't work... any ideas of an efficient way to do this? I couldn't find another thread to help with this problem.
Thanks!
It does work. You just need to create mat2 first:
mat2 = zeros(size(mat1));
mat2(2:4, 3:7) = mat1(2:4, 3:7);
Note that you don't need the square brackets on those ranges.
Do this:
mat2 = zeros(size(mat1));
Before copying over.

Centroid of objects/connected components in matlab?

I am trying to find centroid of objects. I have already implemented connected components labeling and I have developed following code for centroid, it does give result but does not gives correct result:
I have following output matrix i.e matrix_img:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0
2 2 2 2 0 0 0 0 0 1 1 1 1 1 1 0
2 2 2 2 0 0 0 0 1 1 1 1 1 1 1 1
2 2 2 2 0 0 0 0 1 1 1 1 1 1 1 1
2 2 2 2 0 0 0 0 1 1 1 1 1 1 1 1
2 2 2 2 0 0 0 0 0 1 1 1 1 1 1 0
2 2 2 2 0 0 0 0 0 0 1 1 1 1 0 0
2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0
2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0
2 2 2 2 0 0 5 5 5 0 0 0 0 0 0 0
2 2 2 2 0 0 5 5 5 0 0 0 0 0 0 0
2 2 2 2 0 0 5 5 5 0 0 0 0 0 0 0
2 2 2 2 0 0 0 0 0 0 0 0 0 0 0 0
and following is the code
n= max(max(matrix_img));
for k=1:n
a(k)=length(find(matrix_img==k));
sx(k)=0;
sy(k)=0;
cx=0;
cy=0;
for i=1:1:r
for j=1:1:c
if(matrix_img(i,j)==k)
sx(k)=sx(k)+i;
sy(k)=sy(k)+j;
cx=sx(k)/a(k);
cy=sy(k)/a(k);
end
end
end
fprintf('Centroid of Object %d is %d and %d \n', k, cx, cy);
end
It gives result like :
Centroid of Object 1 is 7 and 1.250000e+001
Centroid of Object 2 is 1.050000e+001 and 2.500000e+000
Centroid of Object 3 is 0 and 0
Centroid of Object 4 is 0 and 0
Centroid of Object 5 is 14 and 8
Object 5 result is correct, object 2 is completely wrong and object 1 is partially wrong.. what shall I do?
The values you obtain are the exact centroids for those objects. So you might want to define what you'd expect to get as results.
To make this more clear, I've colored the objects in your matrix. By the symmetry on your cartesian grid, there should be an equal number of points to the left and right of your centroid and the same for above/below the centroid. I've drawn a figure with your objects colored in, together with lines to represent the horizontal and vertical center lines. Those are lines for which, we have an equal number of points to the left/right (or above/below) of them that are part of a certain object.
Their intersection is the centroid, so you can see for object 5 (blue one) that the centroid is at (8, 14). For the other two objects, these center lines do not lie on the integer grid you have: the red object (1) has its centroid at (12.5, 7) which is also the outcome of your code and the green object (2) is centered around (2.5, 10.5).
You will either have to live with inaccuracy introduced by rounding your centroids (e.g. round(cx)) or you will have to live with the non-integer coordinates of the centroids.
Next to that, I also recommend you vectorize your code as oli showed: this allows you to run your code faster and it is easier to understand when you are somewhat familiar with MATLAB than for loops.
Perhaps a little note with regard to your string representation: don't use %d for non-integers, as you see that will cause real numbers to be displayed in scientific notation. I think it's clearer if you use something like %0.2f as your format string.
When you use matlab, avoid using loops, it makes your code very slow, and it is much longer.
You can do the same thing by doing that:
[y x]=ndgrid(1:size(matrix_img,1),1:size(matrix_img,2));
n=max(matrix_img(:));
for k=1:n
cy=mean(y(matrix_img==k));
cx=mean(x(matrix_img==k));
fprintf('Centroid of Object %d is %2.2g and %2.2g \n', k, cx, cy);
end
(Maybe you want to swap x and y in that code)