Thread Subject: Count Matrix

Subject: Count Matrix

From: Erin Laraway

Date: 3 Sep, 2009 18:20:07

Message: 1 of 15

Hello,

This is my first time using MatLab. I first wrote my project in C and was converting it to MatLab, because it uses a lot of 1- and 2-D arrays and the original data is being run through another MatLab toolbox.

This is my C loop:

for(j=1;j<=tot;j++)
   B[row[j]][col[j]] += 1; //where B is a 4x4 array

So basically what I want is to enter two 1-D arrays with numbers 1 through 4 in them, into B. Based on what those numbers are it will add 1 to that spot in the matrix.

I have tried to do a for loop just like that one in MatLab:

for j=1:tot
    B(row(j),col(j)) = B(row(j),col(j)) + 1
end

but it gives a completely wrong answer (and I'm not sure of the method behind the wrongness). I have also tried several ways without a for loop (b/c that would be preferred), but have not found any that would work. Below are a couple:

B(row,col) = B(row,col) + 1 //this one just erases whatever is in B and puts the constant,1, in all spots

B([row,col]) = B([row,col]) + 1 //this one appears to add one to the first column.

I have tried numerous lines that have given me error messages and others that I don't know what they are doing.

Here is a sample problem:
row = [1 1 2 1];
col = [2 1 1 2];
B = zeros(2,2);
result should be:
B = [1 2;1 0]

Any help on this would be appreciated!

Thanks,
Erin

Subject: Count Matrix

From: arun

Date: 3 Sep, 2009 18:41:29

Message: 2 of 15

On Sep 3, 8:20 pm, "Erin Laraway" <e_lara...@hotmail.com> wrote:
> Hello,
>
> This is my first time using MatLab.  I first wrote my project in C and was converting it to MatLab, because it uses a lot of 1- and 2-D arrays and the original data is being run through another MatLab toolbox.
>
> This is my C loop:
>
> for(j=1;j<=tot;j++)
>    B[row[j]][col[j]] += 1;   //where B is a 4x4 array
>
> So basically what I want is to enter two 1-D arrays with numbers 1 through 4 in them, into B.  Based on what those numbers are it will add 1 to that spot in the matrix.
>
> I have tried to do a for loop just like that one in MatLab:
>
> for j=1:tot
>     B(row(j),col(j)) = B(row(j),col(j)) + 1
> end
>
> but it gives a completely wrong answer (and I'm not sure of the method behind the wrongness).  I have also tried several ways without a for loop (b/c that would be preferred), but have not found any that would work.  Below are a couple:
>
> B(row,col) = B(row,col) + 1  //this one just erases whatever is in B and puts the constant,1, in all spots
>
> B([row,col]) = B([row,col]) + 1  //this one appears to add one to the first column.
>
> I have tried numerous lines that have given me error messages and others that I don't know what they are doing.
>
> Here is a sample problem:
> row = [1 1 2 1];
> col = [2 1 1 2];
> B = zeros(2,2);
> result should be:
> B = [1 2;1 0]
>
> Any help on this would be appreciated!
>
> Thanks,
> Erin

May not be the best.. but you get the idea...
ix = max(row);
iy = max(col);
B = zeros(ix,iy);
for i =1:ix,
   for j=1:iy,
      B(i,j) = nnz(row==i & col ==j); % doc nnz
   end
end

best, arun.

Subject: Count Matrix

From: Erin Laraway

Date: 3 Sep, 2009 19:04:05

Message: 3 of 15

> May not be the best.. but you get the idea...
> ix = max(row);
> iy = max(col);
> B = zeros(ix,iy);
> for i =1:ix,
> for j=1:iy,
> B(i,j) = nnz(row==i & col ==j); % doc nnz
> end
> end
>
> best, arun.

Thanks! I just have one question, where is one being added? nnz tells you how many are non-zero, right? I need it to add one to B for every subscripted spot dictated by row and col.

I tried to run this loop and it said:
??? Error using ==> and
Matrix dimensions must agree.

Thanks again,
Erin

Subject: Count Matrix

From: Andy

Date: 3 Sep, 2009 19:23:03

Message: 4 of 15

"Erin Laraway" <e_laraway@hotmail.com> wrote in message <h7p3v5$1q3$1@fred.mathworks.com>...
> > May not be the best.. but you get the idea...
> > ix = max(row);
> > iy = max(col);
> > B = zeros(ix,iy);
> > for i =1:ix,
> > for j=1:iy,
> > B(i,j) = nnz(row==i & col ==j); % doc nnz
> > end
> > end
> >
> > best, arun.
>
> Thanks! I just have one question, where is one being added? nnz tells you how many are non-zero, right? I need it to add one to B for every subscripted spot dictated by row and col.
>
> I tried to run this loop and it said:
> ??? Error using ==> and
> Matrix dimensions must agree.
>
> Thanks again,
> Erin

Arun is not looping over the row/col vectors as you were. Instead, the loop runs over all elements of the array B. For each element B(i,j), the call to nnz calculates the number of times row==i and col==j, and it sets B(i,j) equal to that number. In your example, row==1 and col==2 twice in the row/col vectors, so the loop sets B(1,2)=2.

Since this loops over all of the elements of B, I would think either of the following would be faster:

Option 1:

% assuming row and col are the same length, which they should be
mr = max(row);
mc = max(col);
B = zeros(mr,mc);
for ix=1:numel(row)
  B(row(ix),col(ix))=B(row(ix),col(ix))+1;
end

% It seems you had tried this and gotten the wrong answer. I don't see anything
% wrong with this code, but I'm not at MATLAB to check it out. The only thing I
% can think of is that in your code the variable tot may have been set incorrectly,
% or you were looking at only partially computed output since you didn't end your
% line in the loop with a semicolon. (The semicolon suppresses output. Without it,
% your code would print intermediate results on every loop.)


Option 2:

doc sparse;

% You would presumably have to do some pre-processing of the variables row and
% col to make sure they are in the correct format for sparse. But I imagine this
% will be faster than creating the full matrix. Again, since I'm not at MATLAB, I
% can't check specific ways to do this. But it seems the function unique may have
% some useful options that will set up row and col in the form i,j,s for sparse.

Subject: Count Matrix

From: arun

Date: 3 Sep, 2009 19:44:14

Message: 5 of 15

On Sep 3, 9:23 pm, "Andy " <theorigam...@gmail.com> wrote:
> "Erin Laraway" <e_lara...@hotmail.com> wrote in message <h7p3v5$1q...@fred.mathworks.com>...
> > > May not be the best.. but you get the idea...
> > > ix = max(row);
> > > iy = max(col);
> > > B = zeros(ix,iy);
> > > for i =1:ix,
> > >    for j=1:iy,
> > >       B(i,j) = nnz(row==i & col ==j); % doc nnz
> > >    end
> > > end
>
> > > best, arun.
>
> > Thanks!  I just have one question, where is one being added?  nnz tells you how many are non-zero, right?  I need it to add one to B for every subscripted spot dictated by row and col.
>
> > I tried to run this loop and it said:
> > ??? Error using ==> and
> > Matrix dimensions must agree.
>
> > Thanks again,
> > Erin
>
> Arun is not looping over the row/col vectors as you were.  Instead, the loop runs over all elements of the array B.  For each element B(i,j), the call to nnz calculates the number of times row==i and col==j, and it sets B(i,j) equal to that number.  In your example, row==1 and col==2 twice in the row/col vectors, so the loop sets B(1,2)=2.  
>
> Since this loops over all of the elements of B, I would think either of the following would be faster:
>
> Option 1:
>
> % assuming row and col are the same length, which they should be
> mr = max(row);
> mc = max(col);
> B = zeros(mr,mc);
> for ix=1:numel(row)
>   B(row(ix),col(ix))=B(row(ix),col(ix))+1;
> end
>
> % It seems you had tried this and gotten the wrong answer.  I don't see anything
> % wrong with this code, but I'm not at MATLAB to check it out.  The only thing I
> % can think of is that in your code the variable tot may have been set incorrectly,
> % or you were looking at only partially computed output since you didn't end your
> % line in the loop with a semicolon.  (The semicolon suppresses output.  Without it,
> % your code would print intermediate results on every loop.)
>
> Option 2:
>
> doc sparse;
>
> % You would presumably have to do some pre-processing of the variables row and
> % col to make sure they are in the correct format for sparse.  But I imagine this
> % will be faster than creating the full matrix.  Again, since I'm not at MATLAB, I
> % can't check specific ways to do this.  But it seems the function unique may have
> % some useful options that will set up row and col in the form i,j,s for sparse.

yes, it is of course faster. I was confused regarding the same too.
That is why I resorted to the double-loop normal fashion.
However, there is app. around 0.004453 seconds difference (for larger
vectors, that is).
clear; clc;
row = ceil(5*rand(10000,1));
col = ceil(5*rand(10000,1));

ix = max(row);
iy = max(col);
B1 = zeros(ix,iy);
tic
for i =1:ix,
   for j=1:iy,
      B1(i,j) = nnz(row==i & col ==j); % doc nnz
   end
end
toc
B2 = zeros(ix,iy);
tic
for i=1:numel(row)
  B2(row(i),col(i))=B2(row(i),col(i))+1;
end
toc

isequal(B1,B2)

% Elapsed time is 0.014453 seconds.
% Elapsed time is 0.010031 seconds.

best, arun.

Subject: Count Matrix

From: arun

Date: 3 Sep, 2009 19:49:40

Message: 6 of 15

On Sep 3, 9:44 pm, arun <aragorn1...@gmail.com> wrote:
> On Sep 3, 9:23 pm, "Andy " <theorigam...@gmail.com> wrote:
>
>
>
> > "Erin Laraway" <e_lara...@hotmail.com> wrote in message <h7p3v5$1q...@fred.mathworks.com>...
> > > > May not be the best.. but you get the idea...
> > > > ix = max(row);
> > > > iy = max(col);
> > > > B = zeros(ix,iy);
> > > > for i =1:ix,
> > > >    for j=1:iy,
> > > >       B(i,j) = nnz(row==i & col ==j); % doc nnz
> > > >    end
> > > > end
>
> > > > best, arun.
>
> > > Thanks!  I just have one question, where is one being added?  nnz tells you how many are non-zero, right?  I need it to add one to B for every subscripted spot dictated by row and col.
>
> > > I tried to run this loop and it said:
> > > ??? Error using ==> and
> > > Matrix dimensions must agree.
>
> > > Thanks again,
> > > Erin
>
> > Arun is not looping over the row/col vectors as you were.  Instead, the loop runs over all elements of the array B.  For each element B(i,j), the call to nnz calculates the number of times row==i and col==j, and it sets B(i,j) equal to that number.  In your example, row==1 and col==2 twice in the row/col vectors, so the loop sets B(1,2)=2.  
>
> > Since this loops over all of the elements of B, I would think either of the following would be faster:
>
> > Option 1:
>
> > % assuming row and col are the same length, which they should be
> > mr = max(row);
> > mc = max(col);
> > B = zeros(mr,mc);
> > for ix=1:numel(row)
> >   B(row(ix),col(ix))=B(row(ix),col(ix))+1;
> > end
>
> > % It seems you had tried this and gotten the wrong answer.  I don't see anything
> > % wrong with this code, but I'm not at MATLAB to check it out.  The only thing I
> > % can think of is that in your code the variable tot may have been set incorrectly,
> > % or you were looking at only partially computed output since you didn't end your
> > % line in the loop with a semicolon.  (The semicolon suppresses output.  Without it,
> > % your code would print intermediate results on every loop.)
>
> > Option 2:
>
> > doc sparse;
>
> > % You would presumably have to do some pre-processing of the variables row and
> > % col to make sure they are in the correct format for sparse.  But I imagine this
> > % will be faster than creating the full matrix.  Again, since I'm not at MATLAB, I
> > % can't check specific ways to do this.  But it seems the function unique may have
> > % some useful options that will set up row and col in the form i,j,s for sparse.
>
> yes, it is of course faster. I was confused regarding the same too.
> That is why I resorted to the double-loop normal fashion.
> However, there is app. around 0.004453 seconds difference (for larger
> vectors, that is).
> clear; clc;
> row = ceil(5*rand(10000,1));
> col = ceil(5*rand(10000,1));
>
> ix = max(row);
> iy = max(col);
> B1 = zeros(ix,iy);
> tic
> for i =1:ix,
>    for j=1:iy,
>       B1(i,j) = nnz(row==i & col ==j); % doc nnz
>    end
> end
> toc
> B2 = zeros(ix,iy);
> tic
> for i=1:numel(row)
>   B2(row(i),col(i))=B2(row(i),col(i))+1;
> end
> toc
>
> isequal(B1,B2)
>
> % Elapsed time is 0.014453 seconds.
> % Elapsed time is 0.010031 seconds.
>
> best, arun.

I think I made a blunder in running the tests..
row and col must not be randomly generated... (usual habit...)

row = randperm(10000);
col = randperm(10000);

best, arun.

Subject: Count Matrix

From: Erin Laraway

Date: 3 Sep, 2009 19:58:01

Message: 7 of 15

arun <aragorn168b@gmail.com> wrote in message <ab41be72-129d-463c-bae2-44fcb3fe3948@s39g2000yqj.googlegroups.com>...
> On Sep 3, 9:23?pm, "Andy " <theorigam...@gmail.com> wrote:
> > "Erin Laraway" <e_lara...@hotmail.com> wrote in message <h7p3v5$1q...@fred.mathworks.com>...
> > > > May not be the best.. but you get the idea...
> > > > ix = max(row);
> > > > iy = max(col);
> > > > B = zeros(ix,iy);
> > > > for i =1:ix,
> > > > ? ?for j=1:iy,
> > > > ? ? ? B(i,j) = nnz(row==i & col ==j); % doc nnz
> > > > ? ?end
> > > > end
> >
> > > > best, arun.
> >
> > > Thanks! ?I just have one question, where is one being added? ?nnz tells you how many are non-zero, right? ?I need it to add one to B for every subscripted spot dictated by row and col.
> >
> > > I tried to run this loop and it said:
> > > ??? Error using ==> and
> > > Matrix dimensions must agree.
> >
> > > Thanks again,
> > > Erin
> >
> > Arun is not looping over the row/col vectors as you were. ?Instead, the loop runs over all elements of the array B. ?For each element B(i,j), the call to nnz calculates the number of times row==i and col==j, and it sets B(i,j) equal to that number. ?In your example, row==1 and col==2 twice in the row/col vectors, so the loop sets B(1,2)=2. ?
> >
> > Since this loops over all of the elements of B, I would think either of the following would be faster:
> >
> > Option 1:
> >
> > % assuming row and col are the same length, which they should be
> > mr = max(row);
> > mc = max(col);
> > B = zeros(mr,mc);
> > for ix=1:numel(row)
> > ? B(row(ix),col(ix))=B(row(ix),col(ix))+1;
> > end
> >
> > % It seems you had tried this and gotten the wrong answer. ?I don't see anything
> > % wrong with this code, but I'm not at MATLAB to check it out. ?The only thing I
> > % can think of is that in your code the variable tot may have been set incorrectly,
> > % or you were looking at only partially computed output since you didn't end your
> > % line in the loop with a semicolon. ?(The semicolon suppresses output. ?Without it,
> > % your code would print intermediate results on every loop.)
> >
> > Option 2:
> >
> > doc sparse;
> >
> > % You would presumably have to do some pre-processing of the variables row and
> > % col to make sure they are in the correct format for sparse. ?But I imagine this
> > % will be faster than creating the full matrix. ?Again, since I'm not at MATLAB, I
> > % can't check specific ways to do this. ?But it seems the function unique may have
> > % some useful options that will set up row and col in the form i,j,s for sparse.
>
> yes, it is of course faster. I was confused regarding the same too.
> That is why I resorted to the double-loop normal fashion.
> However, there is app. around 0.004453 seconds difference (for larger
> vectors, that is).
> clear; clc;
> row = ceil(5*rand(10000,1));
> col = ceil(5*rand(10000,1));
>
> ix = max(row);
> iy = max(col);
> B1 = zeros(ix,iy);
> tic
> for i =1:ix,
> for j=1:iy,
> B1(i,j) = nnz(row==i & col ==j); % doc nnz
> end
> end
> toc
> B2 = zeros(ix,iy);
> tic
> for i=1:numel(row)
> B2(row(i),col(i))=B2(row(i),col(i))+1;
> end
> toc
>
> isequal(B1,B2)
>
> % Elapsed time is 0.014453 seconds.
> % Elapsed time is 0.010031 seconds.
>
> best, arun.

arun, I'm still getting an error when I run yours. Are you getting the correct answer for the second loop (option 1 that Andy put up)? That is essentially my C loop. I checked my total, which I just put tot = 216; at the beginning of the program. And I added up the elements in the wrong answer that it gives me for B and they do equal 216.

Thanks,
Erin

Subject: Count Matrix

From: Bruno Luong

Date: 3 Sep, 2009 20:00:20

Message: 8 of 15

"Erin Laraway" <e_laraway@hotmail.com> wrote in message <h7p1cn$2ql$1@fred.mathworks.com>...

>
> for j=1:tot
> B(row(j),col(j)) = B(row(j),col(j)) + 1
> end
>
> but it gives a completely wrong answer (and I'm not sure of the method behind the wrongness).

It should work. Try again. This also should work:

k = sub2ind(size(B),row,col);
B(k) = B(k) + 1

Bruno

Subject: Count Matrix

From: Andy

Date: 3 Sep, 2009 20:11:20

Message: 9 of 15

% You won't get good time measurements running each code once.

% Try this instead (I'm not at MATLAB, or I would do it myself):


% Note: I changed 5 to 50 here. I would imagine the size of B and the length of
% row and col play a large role in deciding the time differences here. I would
% guess that the larger and sparser the matrix (bigger B, and smaller row and col),
% the greater is the difference in speed between the loops.
row = ceil(50*rand(10000,1));
col = ceil(50*rand(10000,1));

ix = max(row);
iy = max(col);

tic
for k=1:100
  B1 = zeros(ix,iy);
  for i =1:ix,
     for j=1:iy,
        B1(i,j) = nnz(row==i & col ==j);
     end
  end
end
toc


tic
for k=1:100
  B2 = zeros(ix,iy);
  for i=1:numel(row)
    B2(row(i),col(i))=B2(row(i),col(i))+1;
  end
end
toc

% Perhaps the OP could comment with regard to the expected length of row/col
% compared to the expected size of the values in them (which will determine the
% size of B).

Subject: Count Matrix

From: James Tursa

Date: 3 Sep, 2009 20:12:03

Message: 10 of 15

"Erin Laraway" <e_laraway@hotmail.com> wrote in message <h7p1cn$2ql$1@fred.mathworks.com>...
> Hello,
>
> This is my first time using MatLab. I first wrote my project in C and was converting it to MatLab, because it uses a lot of 1- and 2-D arrays and the original data is being run through another MatLab toolbox.
>
> This is my C loop:
>
> for(j=1;j<=tot;j++)
> B[row[j]][col[j]] += 1; //where B is a 4x4 array
>
> So basically what I want is to enter two 1-D arrays with numbers 1 through 4 in them, into B. Based on what those numbers are it will add 1 to that spot in the matrix.
>
> I have tried to do a for loop just like that one in MatLab:
>
> for j=1:tot
> B(row(j),col(j)) = B(row(j),col(j)) + 1
> end
>
> but it gives a completely wrong answer (and I'm not sure of the method behind the wrongness).

Are you comparing actual C output to the MATLAB output? C 2D array memory is row based, whereas MATLAB 2D array memory is column based. So any direct comparison would need to take this into account to be sure you were comparing apples to apples.

James Tursa

Subject: Count Matrix

From: Andy

Date: 3 Sep, 2009 20:16:07

Message: 11 of 15


> arun, I'm still getting an error when I run yours. Are you getting the correct answer for the second loop (option 1 that Andy put up)? That is essentially my C loop. I checked my total, which I just put tot = 216; at the beginning of the program. And I added up the elements in the wrong answer that it gives me for B and they do equal 216.
>
> Thanks,
> Erin

What do you mean by total? In my loop, tot should be the length of the row vector (or the length of the col vector). I don't know what you mean by "added up the elements". Example:

row = [1 1 2 1]; % tot should be 4
col = [2 1 1 2];
B = zeros(2,2);

for ix=1:numel(row) % It's better to not use tot at all. Let MATLAB figure it out
  B(row(ix),col(ix))=B(row(ix),col(ix))+1;
end

% What is your output from this?

Subject: Count Matrix

From: Erin Laraway

Date: 4 Sep, 2009 12:10:18

Message: 12 of 15

"Bruno Luong" <b.luong@fogale.findmycountry> wrote in message <h7p78k$ioh$1@fred.mathworks.com>...
> "Erin Laraway" <e_laraway@hotmail.com> wrote in message <h7p1cn$2ql$1@fred.mathworks.com>...
>
> >
> > for j=1:tot
> > B(row(j),col(j)) = B(row(j),col(j)) + 1
> > end
> >
> > but it gives a completely wrong answer (and I'm not sure of the method behind the wrongness).
>
> It should work. Try again. This also should work:
>
> k = sub2ind(size(B),row,col);
> B(k) = B(k) + 1
>
> Bruno

Thanks for all the responses! What actually happened was I thought row and col had the same length, but they didn't. So now the loops work, but I'm going to use Bruno's idea:

 k = sub2ind(size(B),row,col);
 B(k) = B(k) + 1

b/c I really wanted to have it done without a loop.

Thanks again,
Erin

Subject: Count Matrix

From: Jan Simon

Date: 4 Sep, 2009 21:24:01

Message: 13 of 15

Dear Erin, dear Bruno!

The both methods reply different results:

  row = [1,1,2,1];
  col = [2,1,1,2]

  B = zeros(2, 2);
  for j = 1:4
     B(row(j),col(j)) = B(row(j),col(j)) + 1;
  end
 
  B2 = zeros(2,2);
  k = sub2ind(size(B2),row,col);
  B2(k) = B2(k) + 1

isequal(B, B2) ==> 0

Perhaps Bruno intented to insert a loop also:
  B2 = zeros(2,2);
  k = sub2ind(size(B2),row,col);
  for i = 1:length(k)
    B2(k(i)) = B2(k(i)) + 1 ;
  end

Or do I miss something?

Kind regards, Jan

Subject: Count Matrix

From: Bruno Luong

Date: 4 Sep, 2009 21:56:02

Message: 14 of 15

Hi Jan,
I might miss read that row/col has repeated elements. If it's the case, may be this would do

B = B + accumarray([row(:) col(:)], 1, size(B))

Bruno

Subject: Count Matrix

From: Erin Laraway

Date: 8 Sep, 2009 16:24:02

Message: 15 of 15

"Bruno Luong" <b.luong@fogale.findmycountry> wrote in message <h7s2di$968$1@fred.mathworks.com>...
> Hi Jan,
> I might miss read that row/col has repeated elements. If it's the case, may be this would do
>
> B = B + accumarray([row(:) col(:)], 1, size(B))
>
> Bruno

Jan and Bruno,

Thanks, I had actually gone with the first for loop method:

for j=1:tot
     B(row(j),col(j)) = B(row(j),col(j)) + 1;
end

because I could never get the other one to work.

However, the one Bruno just put up appears to give the right answer, so I will probably use that one now.

Thanks again!
~Erin

Tags for this Thread

Everyone's Tags:

Add a New Tag:

Separated by commas
Ex.: root locus, bode

What are tags?

A tag is like a keyword or category label associated with each thread. Tags make it easier for you to find threads of interest.

Anyone can tag a thread. Tags are public and visible to everyone.

Tag Activity for This Thread
Tag Applied By Date/Time
matrix Erin Laraway 3 Sep, 2009 14:24:04
subscripts Erin Laraway 3 Sep, 2009 14:24:04
rssFeed for this Thread

Contact us at files@mathworks.com